@@ -5,6 +5,7 @@ import type {
5
5
UseMutationOptions ,
6
6
} from "react-query" ;
7
7
import { type DeleteWorkspaceOptions , API } from "api/api" ;
8
+ import { DetailedError , isApiValidationError } from "api/errors" ;
8
9
import type {
9
10
CreateWorkspaceRequest ,
10
11
ProvisionerLogLevel ,
@@ -36,14 +37,6 @@ export const workspaceByOwnerAndName = (owner: string, name: string) => {
36
37
} ;
37
38
} ;
38
39
39
- type AutoCreateWorkspaceOptions = {
40
- templateName : string ;
41
- versionId ?: string ;
42
- organizationId : string ;
43
- defaultBuildParameters ?: WorkspaceBuildParameter [ ] ;
44
- defaultName : string ;
45
- } ;
46
-
47
40
type CreateWorkspaceMutationVariables = CreateWorkspaceRequest & {
48
41
userId : string ;
49
42
organizationId : string ;
@@ -61,15 +54,41 @@ export const createWorkspace = (queryClient: QueryClient) => {
61
54
} ;
62
55
} ;
63
56
57
+ type AutoCreateWorkspaceOptions = {
58
+ organizationId : string ;
59
+ templateName : string ;
60
+ name : string ;
61
+ /**
62
+ * If provided, the auto-create workspace feature will attempt to find a
63
+ * matching workspace. If found, it will return the existing workspace instead
64
+ * of creating a new one. Its value supports [advanced filtering queries for
65
+ * workspaces](https://coder.com/docs/workspaces#workspace-filtering). If
66
+ * multiple values are returned, the first one will be returned.
67
+ */
68
+ match : string | null ;
69
+ versionId ?: string ;
70
+ buildParameters ?: WorkspaceBuildParameter [ ] ;
71
+ } ;
72
+
64
73
export const autoCreateWorkspace = ( queryClient : QueryClient ) => {
65
74
return {
66
75
mutationFn : async ( {
76
+ organizationId,
67
77
templateName,
78
+ name,
68
79
versionId,
69
- organizationId,
70
- defaultBuildParameters,
71
- defaultName,
80
+ buildParameters,
81
+ match,
72
82
} : AutoCreateWorkspaceOptions ) => {
83
+ if ( match ) {
84
+ const matchWorkspace = await findMatchWorkspace (
85
+ `owner:me template:${ templateName } ${ match } ` ,
86
+ ) ;
87
+ if ( matchWorkspace ) {
88
+ return matchWorkspace ;
89
+ }
90
+ }
91
+
73
92
let templateVersionParameters ;
74
93
75
94
if ( versionId ) {
@@ -84,8 +103,8 @@ export const autoCreateWorkspace = (queryClient: QueryClient) => {
84
103
85
104
return API . createWorkspace ( organizationId , "me" , {
86
105
...templateVersionParameters ,
87
- name : defaultName ,
88
- rich_parameter_values : defaultBuildParameters ,
106
+ name,
107
+ rich_parameter_values : buildParameters ,
89
108
} ) ;
90
109
} ,
91
110
onSuccess : async ( ) => {
@@ -94,6 +113,27 @@ export const autoCreateWorkspace = (queryClient: QueryClient) => {
94
113
} ;
95
114
} ;
96
115
116
+ async function findMatchWorkspace ( q : string ) : Promise < Workspace | undefined > {
117
+ try {
118
+ const { workspaces } = await API . getWorkspaces ( { q } ) ;
119
+ const matchWorkspace = workspaces . at ( 0 ) ;
120
+ if ( matchWorkspace ) {
121
+ return matchWorkspace ;
122
+ }
123
+ } catch ( err ) {
124
+ if ( isApiValidationError ( err ) ) {
125
+ const firstValidationErrorDetail =
126
+ err . response . data . validations ?. [ 0 ] . detail ;
127
+ throw new DetailedError (
128
+ "Invalid match value" ,
129
+ firstValidationErrorDetail ,
130
+ ) ;
131
+ }
132
+
133
+ throw err ;
134
+ }
135
+ }
136
+
97
137
export function workspacesKey ( config : WorkspacesRequest = { } ) {
98
138
const { q, limit } = config ;
99
139
return [ "workspaces" , { q, limit } ] as const ;
0 commit comments