@shipfox/client-runners 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.storybook/main.ts +1 -0
- package/.storybook/preview.css +4 -0
- package/.storybook/preview.tsx +64 -0
- package/.turbo/turbo-build.log +2 -0
- package/.turbo/turbo-type$colon$emit.log +1 -0
- package/.turbo/turbo-type.log +1 -0
- package/CHANGELOG.md +112 -0
- package/LICENSE +21 -0
- package/dist/components/create-manual-registration-token-form.d.ts +10 -0
- package/dist/components/create-manual-registration-token-form.d.ts.map +1 -0
- package/dist/components/create-manual-registration-token-form.js +206 -0
- package/dist/components/create-manual-registration-token-form.js.map +1 -0
- package/dist/components/create-provisioner-token-form.d.ts +10 -0
- package/dist/components/create-provisioner-token-form.d.ts.map +1 -0
- package/dist/components/create-provisioner-token-form.js +206 -0
- package/dist/components/create-provisioner-token-form.js.map +1 -0
- package/dist/components/form-errors.d.ts +6 -0
- package/dist/components/form-errors.d.ts.map +1 -0
- package/dist/components/form-errors.js +9 -0
- package/dist/components/form-errors.js.map +1 -0
- package/dist/components/manual-registration-token-errors.d.ts +2 -0
- package/dist/components/manual-registration-token-errors.d.ts.map +1 -0
- package/dist/components/manual-registration-token-errors.js +14 -0
- package/dist/components/manual-registration-token-errors.js.map +1 -0
- package/dist/components/manual-registration-token-format.d.ts +5 -0
- package/dist/components/manual-registration-token-format.d.ts.map +1 -0
- package/dist/components/manual-registration-token-format.js +14 -0
- package/dist/components/manual-registration-token-format.js.map +1 -0
- package/dist/components/manual-registration-token-list.d.ts +8 -0
- package/dist/components/manual-registration-token-list.d.ts.map +1 -0
- package/dist/components/manual-registration-token-list.js +293 -0
- package/dist/components/manual-registration-token-list.js.map +1 -0
- package/dist/components/manual-registration-tokens-settings-section.d.ts +4 -0
- package/dist/components/manual-registration-tokens-settings-section.d.ts.map +1 -0
- package/dist/components/manual-registration-tokens-settings-section.js +109 -0
- package/dist/components/manual-registration-tokens-settings-section.js.map +1 -0
- package/dist/components/provisioner-token-errors.d.ts +2 -0
- package/dist/components/provisioner-token-errors.d.ts.map +1 -0
- package/dist/components/provisioner-token-errors.js +13 -0
- package/dist/components/provisioner-token-errors.js.map +1 -0
- package/dist/components/provisioner-token-form-errors.d.ts +6 -0
- package/dist/components/provisioner-token-form-errors.d.ts.map +1 -0
- package/dist/components/provisioner-token-form-errors.js +9 -0
- package/dist/components/provisioner-token-form-errors.js.map +1 -0
- package/dist/components/provisioner-token-format.d.ts +21 -0
- package/dist/components/provisioner-token-format.d.ts.map +1 -0
- package/dist/components/provisioner-token-format.js +36 -0
- package/dist/components/provisioner-token-format.js.map +1 -0
- package/dist/components/provisioner-token-list.d.ts +9 -0
- package/dist/components/provisioner-token-list.d.ts.map +1 -0
- package/dist/components/provisioner-token-list.js +344 -0
- package/dist/components/provisioner-token-list.js.map +1 -0
- package/dist/components/provisioner-tokens-settings-section.d.ts +4 -0
- package/dist/components/provisioner-tokens-settings-section.d.ts.map +1 -0
- package/dist/components/provisioner-tokens-settings-section.js +117 -0
- package/dist/components/provisioner-tokens-settings-section.js.map +1 -0
- package/dist/components/token-date.d.ts +6 -0
- package/dist/components/token-date.d.ts.map +1 -0
- package/dist/components/token-date.js +27 -0
- package/dist/components/token-date.js.map +1 -0
- package/dist/components/token-expiration-select.d.ts +11 -0
- package/dist/components/token-expiration-select.d.ts.map +1 -0
- package/dist/components/token-expiration-select.js +68 -0
- package/dist/components/token-expiration-select.js.map +1 -0
- package/dist/components/token-name.d.ts +4 -0
- package/dist/components/token-name.d.ts.map +1 -0
- package/dist/components/token-name.js +24 -0
- package/dist/components/token-name.js.map +1 -0
- package/dist/components/token-settings-sections.stories.d.ts +26 -0
- package/dist/components/token-settings-sections.stories.d.ts.map +1 -0
- package/dist/components/token-settings-sections.stories.js +370 -0
- package/dist/components/token-settings-sections.stories.js.map +1 -0
- package/dist/hooks/api/manual-registration-tokens.d.ts +83 -0
- package/dist/hooks/api/manual-registration-tokens.d.ts.map +1 -0
- package/dist/hooks/api/manual-registration-tokens.js +53 -0
- package/dist/hooks/api/manual-registration-tokens.js.map +1 -0
- package/dist/hooks/api/provisioner-tokens.d.ts +125 -0
- package/dist/hooks/api/provisioner-tokens.d.ts.map +1 -0
- package/dist/hooks/api/provisioner-tokens.js +81 -0
- package/dist/hooks/api/provisioner-tokens.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/tsconfig.test.tsbuildinfo +1 -0
- package/package.json +88 -0
- package/src/components/create-manual-registration-token-form.tsx +197 -0
- package/src/components/create-provisioner-token-form.tsx +193 -0
- package/src/components/form-errors.test.ts +24 -0
- package/src/components/form-errors.ts +9 -0
- package/src/components/manual-registration-token-errors.ts +13 -0
- package/src/components/manual-registration-token-format.test.ts +48 -0
- package/src/components/manual-registration-token-format.ts +18 -0
- package/src/components/manual-registration-token-list.tsx +246 -0
- package/src/components/manual-registration-tokens-settings-section.test.tsx +251 -0
- package/src/components/manual-registration-tokens-settings-section.tsx +110 -0
- package/src/components/provisioner-token-errors.ts +12 -0
- package/src/components/provisioner-token-form-errors.test.ts +35 -0
- package/src/components/provisioner-token-form-errors.ts +9 -0
- package/src/components/provisioner-token-format.test.ts +96 -0
- package/src/components/provisioner-token-format.ts +40 -0
- package/src/components/provisioner-token-list.tsx +280 -0
- package/src/components/provisioner-tokens-settings-section.test.tsx +362 -0
- package/src/components/provisioner-tokens-settings-section.tsx +114 -0
- package/src/components/token-date.tsx +27 -0
- package/src/components/token-expiration-select.tsx +64 -0
- package/src/components/token-name.tsx +19 -0
- package/src/components/token-settings-sections.stories.tsx +360 -0
- package/src/hooks/api/manual-registration-tokens.test.ts +87 -0
- package/src/hooks/api/manual-registration-tokens.ts +71 -0
- package/src/hooks/api/provisioner-tokens.test.ts +127 -0
- package/src/hooks/api/provisioner-tokens.ts +102 -0
- package/src/index.ts +4 -0
- package/test/setup.ts +3 -0
- package/tsconfig.build.json +9 -0
- package/tsconfig.build.tsbuildinfo +1 -0
- package/tsconfig.json +3 -0
- package/tsconfig.test.json +8 -0
- package/vercel.json +8 -0
- package/vitest.config.ts +74 -0
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Button, IconButton } from '@shipfox/react-ui/button';
|
|
3
|
+
import { Callout } from '@shipfox/react-ui/callout';
|
|
4
|
+
import { Dot } from '@shipfox/react-ui/dot';
|
|
5
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@shipfox/react-ui/dropdown-menu';
|
|
6
|
+
import { EmptyState } from '@shipfox/react-ui/empty-state';
|
|
7
|
+
import { Modal, ModalBody, ModalContent, ModalFooter, ModalHeader, ModalTitle } from '@shipfox/react-ui/modal';
|
|
8
|
+
import { RelativeTime } from '@shipfox/react-ui/relative-time';
|
|
9
|
+
import { Skeleton } from '@shipfox/react-ui/skeleton';
|
|
10
|
+
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@shipfox/react-ui/table';
|
|
11
|
+
import { Code, Text } from '@shipfox/react-ui/typography';
|
|
12
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
13
|
+
import { useState } from 'react';
|
|
14
|
+
import { provisionerTokenQueryKeys, useRevokeProvisionerTokenMutation } from '#hooks/api/provisioner-tokens.js';
|
|
15
|
+
import { provisionerTokenErrorMessage } from './provisioner-token-errors.js';
|
|
16
|
+
import { formatProvisionerTokenDate, formatProvisionerTokenTimestamp, provisionerConnectionStatus, provisionerTokenDisplayName } from './provisioner-token-format.js';
|
|
17
|
+
import { TokenDate } from './token-date.js';
|
|
18
|
+
import { TokenName } from './token-name.js';
|
|
19
|
+
export function ProvisionerTokenList({ workspaceId, tokens, activeIds }) {
|
|
20
|
+
return /*#__PURE__*/ _jsxs(_Fragment, {
|
|
21
|
+
children: [
|
|
22
|
+
/*#__PURE__*/ _jsx("div", {
|
|
23
|
+
className: "max-[760px]:hidden",
|
|
24
|
+
children: /*#__PURE__*/ _jsxs(Table, {
|
|
25
|
+
className: "table-fixed",
|
|
26
|
+
children: [
|
|
27
|
+
/*#__PURE__*/ _jsx(TableHeader, {
|
|
28
|
+
children: /*#__PURE__*/ _jsxs(TableRow, {
|
|
29
|
+
children: [
|
|
30
|
+
/*#__PURE__*/ _jsx(TableHead, {
|
|
31
|
+
className: "w-[28%]",
|
|
32
|
+
children: "Name"
|
|
33
|
+
}),
|
|
34
|
+
/*#__PURE__*/ _jsx(TableHead, {
|
|
35
|
+
children: "Prefix"
|
|
36
|
+
}),
|
|
37
|
+
/*#__PURE__*/ _jsx(TableHead, {
|
|
38
|
+
className: "w-[18%]",
|
|
39
|
+
children: "Status"
|
|
40
|
+
}),
|
|
41
|
+
/*#__PURE__*/ _jsx(TableHead, {
|
|
42
|
+
className: "w-112",
|
|
43
|
+
children: "Expires"
|
|
44
|
+
}),
|
|
45
|
+
/*#__PURE__*/ _jsx(TableHead, {
|
|
46
|
+
className: "w-112",
|
|
47
|
+
children: "Created"
|
|
48
|
+
}),
|
|
49
|
+
/*#__PURE__*/ _jsx(TableHead, {
|
|
50
|
+
className: "w-80 text-right",
|
|
51
|
+
children: "Actions"
|
|
52
|
+
})
|
|
53
|
+
]
|
|
54
|
+
})
|
|
55
|
+
}),
|
|
56
|
+
/*#__PURE__*/ _jsx(TableBody, {
|
|
57
|
+
children: tokens.map((token)=>/*#__PURE__*/ _jsxs(TableRow, {
|
|
58
|
+
children: [
|
|
59
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
60
|
+
children: /*#__PURE__*/ _jsx(TokenName, {
|
|
61
|
+
name: provisionerTokenDisplayName(token)
|
|
62
|
+
})
|
|
63
|
+
}),
|
|
64
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
65
|
+
children: /*#__PURE__*/ _jsx(Code, {
|
|
66
|
+
variant: "paragraph",
|
|
67
|
+
className: "block truncate",
|
|
68
|
+
children: token.prefix
|
|
69
|
+
})
|
|
70
|
+
}),
|
|
71
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
72
|
+
children: /*#__PURE__*/ _jsx(ProvisionerStatusCell, {
|
|
73
|
+
token: token,
|
|
74
|
+
activeIds: activeIds
|
|
75
|
+
})
|
|
76
|
+
}),
|
|
77
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
78
|
+
children: /*#__PURE__*/ _jsx(ProvisionerTokenDate, {
|
|
79
|
+
value: token.expires_at
|
|
80
|
+
})
|
|
81
|
+
}),
|
|
82
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
83
|
+
children: /*#__PURE__*/ _jsx(ProvisionerTokenDate, {
|
|
84
|
+
value: token.created_at
|
|
85
|
+
})
|
|
86
|
+
}),
|
|
87
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
88
|
+
className: "text-right",
|
|
89
|
+
children: /*#__PURE__*/ _jsx(RevokeProvisionerTokenButton, {
|
|
90
|
+
workspaceId: workspaceId,
|
|
91
|
+
token: token
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
]
|
|
95
|
+
}, token.id))
|
|
96
|
+
})
|
|
97
|
+
]
|
|
98
|
+
})
|
|
99
|
+
}),
|
|
100
|
+
/*#__PURE__*/ _jsx("ul", {
|
|
101
|
+
className: "hidden flex-col gap-10 max-[760px]:flex",
|
|
102
|
+
"aria-label": "Provisioner tokens",
|
|
103
|
+
children: tokens.map((token)=>/*#__PURE__*/ _jsxs("li", {
|
|
104
|
+
className: "rounded-8 border border-border-neutral-base bg-background-neutral-base p-14",
|
|
105
|
+
children: [
|
|
106
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
107
|
+
className: "flex items-start justify-between gap-12",
|
|
108
|
+
children: [
|
|
109
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
110
|
+
className: "min-w-0 flex-1",
|
|
111
|
+
children: [
|
|
112
|
+
/*#__PURE__*/ _jsx(TokenName, {
|
|
113
|
+
name: provisionerTokenDisplayName(token)
|
|
114
|
+
}),
|
|
115
|
+
/*#__PURE__*/ _jsx(Code, {
|
|
116
|
+
variant: "paragraph",
|
|
117
|
+
className: "block truncate text-foreground-neutral-muted",
|
|
118
|
+
children: token.prefix
|
|
119
|
+
})
|
|
120
|
+
]
|
|
121
|
+
}),
|
|
122
|
+
/*#__PURE__*/ _jsx(RevokeProvisionerTokenButton, {
|
|
123
|
+
workspaceId: workspaceId,
|
|
124
|
+
token: token
|
|
125
|
+
})
|
|
126
|
+
]
|
|
127
|
+
}),
|
|
128
|
+
/*#__PURE__*/ _jsxs("dl", {
|
|
129
|
+
className: "mt-12 grid grid-cols-2 gap-10 text-sm",
|
|
130
|
+
children: [
|
|
131
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
132
|
+
children: [
|
|
133
|
+
/*#__PURE__*/ _jsx("dt", {
|
|
134
|
+
className: "text-foreground-neutral-muted",
|
|
135
|
+
children: "Status"
|
|
136
|
+
}),
|
|
137
|
+
/*#__PURE__*/ _jsx("dd", {
|
|
138
|
+
children: /*#__PURE__*/ _jsx(ProvisionerStatusCell, {
|
|
139
|
+
token: token,
|
|
140
|
+
activeIds: activeIds
|
|
141
|
+
})
|
|
142
|
+
})
|
|
143
|
+
]
|
|
144
|
+
}),
|
|
145
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
146
|
+
children: [
|
|
147
|
+
/*#__PURE__*/ _jsx("dt", {
|
|
148
|
+
className: "text-foreground-neutral-muted",
|
|
149
|
+
children: "Expires"
|
|
150
|
+
}),
|
|
151
|
+
/*#__PURE__*/ _jsx("dd", {
|
|
152
|
+
children: /*#__PURE__*/ _jsx(ProvisionerTokenDate, {
|
|
153
|
+
value: token.expires_at
|
|
154
|
+
})
|
|
155
|
+
})
|
|
156
|
+
]
|
|
157
|
+
}),
|
|
158
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
159
|
+
children: [
|
|
160
|
+
/*#__PURE__*/ _jsx("dt", {
|
|
161
|
+
className: "text-foreground-neutral-muted",
|
|
162
|
+
children: "Created"
|
|
163
|
+
}),
|
|
164
|
+
/*#__PURE__*/ _jsx("dd", {
|
|
165
|
+
children: /*#__PURE__*/ _jsx(ProvisionerTokenDate, {
|
|
166
|
+
value: token.created_at
|
|
167
|
+
})
|
|
168
|
+
})
|
|
169
|
+
]
|
|
170
|
+
})
|
|
171
|
+
]
|
|
172
|
+
})
|
|
173
|
+
]
|
|
174
|
+
}, token.id))
|
|
175
|
+
})
|
|
176
|
+
]
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
function ProvisionerTokenDate({ value }) {
|
|
180
|
+
return /*#__PURE__*/ _jsx(TokenDate, {
|
|
181
|
+
value: value,
|
|
182
|
+
date: formatProvisionerTokenDate(value),
|
|
183
|
+
timestamp: formatProvisionerTokenTimestamp(value)
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
function ProvisionerStatusCell({ token, activeIds }) {
|
|
187
|
+
const status = provisionerConnectionStatus(token, activeIds);
|
|
188
|
+
return /*#__PURE__*/ _jsxs("span", {
|
|
189
|
+
className: "inline-flex items-center gap-6",
|
|
190
|
+
children: [
|
|
191
|
+
/*#__PURE__*/ _jsx(Dot, {
|
|
192
|
+
variant: status.dotVariant
|
|
193
|
+
}),
|
|
194
|
+
status.kind === 'last-seen' ? /*#__PURE__*/ _jsxs("span", {
|
|
195
|
+
children: [
|
|
196
|
+
status.label,
|
|
197
|
+
" ",
|
|
198
|
+
/*#__PURE__*/ _jsx(RelativeTime, {
|
|
199
|
+
value: status.lastSeenAt
|
|
200
|
+
})
|
|
201
|
+
]
|
|
202
|
+
}) : /*#__PURE__*/ _jsx("span", {
|
|
203
|
+
children: status.label
|
|
204
|
+
})
|
|
205
|
+
]
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
function RevokeProvisionerTokenButton({ workspaceId, token }) {
|
|
209
|
+
const queryClient = useQueryClient();
|
|
210
|
+
const revokeToken = useRevokeProvisionerTokenMutation();
|
|
211
|
+
const [open, setOpen] = useState(false);
|
|
212
|
+
const tokenName = provisionerTokenDisplayName(token);
|
|
213
|
+
async function handleRevoke() {
|
|
214
|
+
try {
|
|
215
|
+
await revokeToken.mutateAsync({
|
|
216
|
+
workspaceId,
|
|
217
|
+
tokenId: token.id
|
|
218
|
+
});
|
|
219
|
+
await queryClient.invalidateQueries({
|
|
220
|
+
queryKey: provisionerTokenQueryKeys.list(workspaceId)
|
|
221
|
+
});
|
|
222
|
+
await queryClient.invalidateQueries({
|
|
223
|
+
queryKey: provisionerTokenQueryKeys.active(workspaceId)
|
|
224
|
+
});
|
|
225
|
+
setOpen(false);
|
|
226
|
+
} catch {
|
|
227
|
+
// React Query stores the error for the inline modal alert.
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
function handleOpenChange(nextOpen) {
|
|
231
|
+
setOpen(nextOpen);
|
|
232
|
+
if (nextOpen) {
|
|
233
|
+
revokeToken.reset();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
function openRevokeConfirmation() {
|
|
237
|
+
revokeToken.reset();
|
|
238
|
+
setOpen(true);
|
|
239
|
+
}
|
|
240
|
+
return /*#__PURE__*/ _jsxs(_Fragment, {
|
|
241
|
+
children: [
|
|
242
|
+
/*#__PURE__*/ _jsxs(DropdownMenu, {
|
|
243
|
+
children: [
|
|
244
|
+
/*#__PURE__*/ _jsx(DropdownMenuTrigger, {
|
|
245
|
+
asChild: true,
|
|
246
|
+
children: /*#__PURE__*/ _jsx(IconButton, {
|
|
247
|
+
type: "button",
|
|
248
|
+
size: "sm",
|
|
249
|
+
variant: "transparent",
|
|
250
|
+
icon: "more2Line",
|
|
251
|
+
"aria-label": `Open ${tokenName} token actions`
|
|
252
|
+
})
|
|
253
|
+
}),
|
|
254
|
+
/*#__PURE__*/ _jsx(DropdownMenuContent, {
|
|
255
|
+
align: "end",
|
|
256
|
+
size: "sm",
|
|
257
|
+
children: /*#__PURE__*/ _jsx(DropdownMenuItem, {
|
|
258
|
+
onSelect: openRevokeConfirmation,
|
|
259
|
+
children: "Revoke token"
|
|
260
|
+
})
|
|
261
|
+
})
|
|
262
|
+
]
|
|
263
|
+
}),
|
|
264
|
+
/*#__PURE__*/ _jsx(Modal, {
|
|
265
|
+
open: open,
|
|
266
|
+
onOpenChange: handleOpenChange,
|
|
267
|
+
children: /*#__PURE__*/ _jsxs(ModalContent, {
|
|
268
|
+
"aria-describedby": undefined,
|
|
269
|
+
className: "max-w-[420px]",
|
|
270
|
+
children: [
|
|
271
|
+
/*#__PURE__*/ _jsx(ModalTitle, {
|
|
272
|
+
className: "sr-only",
|
|
273
|
+
children: "Revoke token"
|
|
274
|
+
}),
|
|
275
|
+
/*#__PURE__*/ _jsx(ModalHeader, {
|
|
276
|
+
title: "Revoke token?"
|
|
277
|
+
}),
|
|
278
|
+
/*#__PURE__*/ _jsxs(ModalBody, {
|
|
279
|
+
className: "gap-16",
|
|
280
|
+
children: [
|
|
281
|
+
/*#__PURE__*/ _jsxs(Text, {
|
|
282
|
+
size: "sm",
|
|
283
|
+
className: "text-foreground-neutral-muted",
|
|
284
|
+
children: [
|
|
285
|
+
tokenName,
|
|
286
|
+
" will stop authenticating this provisioner. Runners it already provisioned keep running until their leases expire."
|
|
287
|
+
]
|
|
288
|
+
}),
|
|
289
|
+
revokeToken.isError ? /*#__PURE__*/ _jsx(Callout, {
|
|
290
|
+
role: "alert",
|
|
291
|
+
type: "error",
|
|
292
|
+
children: /*#__PURE__*/ _jsx(Text, {
|
|
293
|
+
size: "sm",
|
|
294
|
+
children: provisionerTokenErrorMessage(revokeToken.error)
|
|
295
|
+
})
|
|
296
|
+
}) : null
|
|
297
|
+
]
|
|
298
|
+
}),
|
|
299
|
+
/*#__PURE__*/ _jsxs(ModalFooter, {
|
|
300
|
+
children: [
|
|
301
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
302
|
+
size: "sm",
|
|
303
|
+
variant: "secondary",
|
|
304
|
+
onClick: ()=>setOpen(false),
|
|
305
|
+
children: "Cancel"
|
|
306
|
+
}),
|
|
307
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
308
|
+
size: "sm",
|
|
309
|
+
variant: "danger",
|
|
310
|
+
isLoading: revokeToken.isPending,
|
|
311
|
+
onClick: handleRevoke,
|
|
312
|
+
children: "Revoke"
|
|
313
|
+
})
|
|
314
|
+
]
|
|
315
|
+
})
|
|
316
|
+
]
|
|
317
|
+
})
|
|
318
|
+
})
|
|
319
|
+
]
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
export function EmptyProvisionerTokens() {
|
|
323
|
+
return /*#__PURE__*/ _jsx(EmptyState, {
|
|
324
|
+
icon: "key2Line",
|
|
325
|
+
title: "No usable provisioner registration tokens",
|
|
326
|
+
description: "Create a token to connect a provisioner that provisions runners on demand."
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
export function ProvisionerTokenTableSkeleton() {
|
|
330
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
331
|
+
role: "status",
|
|
332
|
+
"aria-label": "Loading provisioner tokens",
|
|
333
|
+
className: "flex flex-col gap-8",
|
|
334
|
+
children: [
|
|
335
|
+
0,
|
|
336
|
+
1,
|
|
337
|
+
2
|
|
338
|
+
].map((row)=>/*#__PURE__*/ _jsx(Skeleton, {
|
|
339
|
+
className: "h-44 w-full"
|
|
340
|
+
}, row))
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
//# sourceMappingURL=provisioner-token-list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/provisioner-token-list.tsx"],"sourcesContent":["import type {ProvisionerTokenDto} from '@shipfox/api-runners-dto';\nimport {Button, IconButton} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {Dot} from '@shipfox/react-ui/dot';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@shipfox/react-ui/dropdown-menu';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {\n Modal,\n ModalBody,\n ModalContent,\n ModalFooter,\n ModalHeader,\n ModalTitle,\n} from '@shipfox/react-ui/modal';\nimport {RelativeTime} from '@shipfox/react-ui/relative-time';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@shipfox/react-ui/table';\nimport {Code, Text} from '@shipfox/react-ui/typography';\nimport {useQueryClient} from '@tanstack/react-query';\nimport {useState} from 'react';\nimport {\n provisionerTokenQueryKeys,\n useRevokeProvisionerTokenMutation,\n} from '#hooks/api/provisioner-tokens.js';\nimport {provisionerTokenErrorMessage} from './provisioner-token-errors.js';\nimport {\n formatProvisionerTokenDate,\n formatProvisionerTokenTimestamp,\n provisionerConnectionStatus,\n provisionerTokenDisplayName,\n} from './provisioner-token-format.js';\nimport {TokenDate} from './token-date.js';\nimport {TokenName} from './token-name.js';\n\nexport function ProvisionerTokenList({\n workspaceId,\n tokens,\n activeIds,\n}: {\n workspaceId: string;\n tokens: ProvisionerTokenDto[];\n activeIds: ReadonlySet<string>;\n}) {\n return (\n <>\n <div className=\"max-[760px]:hidden\">\n <Table className=\"table-fixed\">\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-[28%]\">Name</TableHead>\n <TableHead>Prefix</TableHead>\n <TableHead className=\"w-[18%]\">Status</TableHead>\n <TableHead className=\"w-112\">Expires</TableHead>\n <TableHead className=\"w-112\">Created</TableHead>\n <TableHead className=\"w-80 text-right\">Actions</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {tokens.map((token) => (\n <TableRow key={token.id}>\n <TableCell>\n <TokenName name={provisionerTokenDisplayName(token)} />\n </TableCell>\n <TableCell>\n <Code variant=\"paragraph\" className=\"block truncate\">\n {token.prefix}\n </Code>\n </TableCell>\n <TableCell>\n <ProvisionerStatusCell token={token} activeIds={activeIds} />\n </TableCell>\n <TableCell>\n <ProvisionerTokenDate value={token.expires_at} />\n </TableCell>\n <TableCell>\n <ProvisionerTokenDate value={token.created_at} />\n </TableCell>\n <TableCell className=\"text-right\">\n <RevokeProvisionerTokenButton workspaceId={workspaceId} token={token} />\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n <ul className=\"hidden flex-col gap-10 max-[760px]:flex\" aria-label=\"Provisioner tokens\">\n {tokens.map((token) => (\n <li\n key={token.id}\n className=\"rounded-8 border border-border-neutral-base bg-background-neutral-base p-14\"\n >\n <div className=\"flex items-start justify-between gap-12\">\n <div className=\"min-w-0 flex-1\">\n <TokenName name={provisionerTokenDisplayName(token)} />\n <Code variant=\"paragraph\" className=\"block truncate text-foreground-neutral-muted\">\n {token.prefix}\n </Code>\n </div>\n <RevokeProvisionerTokenButton workspaceId={workspaceId} token={token} />\n </div>\n <dl className=\"mt-12 grid grid-cols-2 gap-10 text-sm\">\n <div>\n <dt className=\"text-foreground-neutral-muted\">Status</dt>\n <dd>\n <ProvisionerStatusCell token={token} activeIds={activeIds} />\n </dd>\n </div>\n <div>\n <dt className=\"text-foreground-neutral-muted\">Expires</dt>\n <dd>\n <ProvisionerTokenDate value={token.expires_at} />\n </dd>\n </div>\n <div>\n <dt className=\"text-foreground-neutral-muted\">Created</dt>\n <dd>\n <ProvisionerTokenDate value={token.created_at} />\n </dd>\n </div>\n </dl>\n </li>\n ))}\n </ul>\n </>\n );\n}\n\nfunction ProvisionerTokenDate({value}: {value: string | null}) {\n return (\n <TokenDate\n value={value}\n date={formatProvisionerTokenDate(value)}\n timestamp={formatProvisionerTokenTimestamp(value)}\n />\n );\n}\n\nfunction ProvisionerStatusCell({\n token,\n activeIds,\n}: {\n token: ProvisionerTokenDto;\n activeIds: ReadonlySet<string>;\n}) {\n const status = provisionerConnectionStatus(token, activeIds);\n\n return (\n <span className=\"inline-flex items-center gap-6\">\n <Dot variant={status.dotVariant} />\n {status.kind === 'last-seen' ? (\n <span>\n {status.label} <RelativeTime value={status.lastSeenAt} />\n </span>\n ) : (\n <span>{status.label}</span>\n )}\n </span>\n );\n}\n\nfunction RevokeProvisionerTokenButton({\n workspaceId,\n token,\n}: {\n workspaceId: string;\n token: ProvisionerTokenDto;\n}) {\n const queryClient = useQueryClient();\n const revokeToken = useRevokeProvisionerTokenMutation();\n const [open, setOpen] = useState(false);\n const tokenName = provisionerTokenDisplayName(token);\n\n async function handleRevoke() {\n try {\n await revokeToken.mutateAsync({workspaceId, tokenId: token.id});\n await queryClient.invalidateQueries({\n queryKey: provisionerTokenQueryKeys.list(workspaceId),\n });\n await queryClient.invalidateQueries({\n queryKey: provisionerTokenQueryKeys.active(workspaceId),\n });\n setOpen(false);\n } catch {\n // React Query stores the error for the inline modal alert.\n }\n }\n\n function handleOpenChange(nextOpen: boolean) {\n setOpen(nextOpen);\n if (nextOpen) {\n revokeToken.reset();\n }\n }\n\n function openRevokeConfirmation() {\n revokeToken.reset();\n setOpen(true);\n }\n\n return (\n <>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <IconButton\n type=\"button\"\n size=\"sm\"\n variant=\"transparent\"\n icon=\"more2Line\"\n aria-label={`Open ${tokenName} token actions`}\n />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" size=\"sm\">\n <DropdownMenuItem onSelect={openRevokeConfirmation}>Revoke token</DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n <Modal open={open} onOpenChange={handleOpenChange}>\n <ModalContent aria-describedby={undefined} className=\"max-w-[420px]\">\n <ModalTitle className=\"sr-only\">Revoke token</ModalTitle>\n <ModalHeader title=\"Revoke token?\" />\n <ModalBody className=\"gap-16\">\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n {tokenName} will stop authenticating this provisioner. Runners it already provisioned\n keep running until their leases expire.\n </Text>\n {revokeToken.isError ? (\n <Callout role=\"alert\" type=\"error\">\n <Text size=\"sm\">{provisionerTokenErrorMessage(revokeToken.error)}</Text>\n </Callout>\n ) : null}\n </ModalBody>\n <ModalFooter>\n <Button size=\"sm\" variant=\"secondary\" onClick={() => setOpen(false)}>\n Cancel\n </Button>\n <Button\n size=\"sm\"\n variant=\"danger\"\n isLoading={revokeToken.isPending}\n onClick={handleRevoke}\n >\n Revoke\n </Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n </>\n );\n}\n\nexport function EmptyProvisionerTokens() {\n return (\n <EmptyState\n icon=\"key2Line\"\n title=\"No usable provisioner registration tokens\"\n description=\"Create a token to connect a provisioner that provisions runners on demand.\"\n />\n );\n}\n\nexport function ProvisionerTokenTableSkeleton() {\n return (\n <div role=\"status\" aria-label=\"Loading provisioner tokens\" className=\"flex flex-col gap-8\">\n {[0, 1, 2].map((row) => (\n <Skeleton key={row} className=\"h-44 w-full\" />\n ))}\n </div>\n );\n}\n"],"names":["Button","IconButton","Callout","Dot","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuTrigger","EmptyState","Modal","ModalBody","ModalContent","ModalFooter","ModalHeader","ModalTitle","RelativeTime","Skeleton","Table","TableBody","TableCell","TableHead","TableHeader","TableRow","Code","Text","useQueryClient","useState","provisionerTokenQueryKeys","useRevokeProvisionerTokenMutation","provisionerTokenErrorMessage","formatProvisionerTokenDate","formatProvisionerTokenTimestamp","provisionerConnectionStatus","provisionerTokenDisplayName","TokenDate","TokenName","ProvisionerTokenList","workspaceId","tokens","activeIds","div","className","map","token","name","variant","prefix","ProvisionerStatusCell","ProvisionerTokenDate","value","expires_at","created_at","RevokeProvisionerTokenButton","id","ul","aria-label","li","dl","dt","dd","date","timestamp","status","span","dotVariant","kind","label","lastSeenAt","queryClient","revokeToken","open","setOpen","tokenName","handleRevoke","mutateAsync","tokenId","invalidateQueries","queryKey","list","active","handleOpenChange","nextOpen","reset","openRevokeConfirmation","asChild","type","size","icon","align","onSelect","onOpenChange","aria-describedby","undefined","title","isError","role","error","onClick","isLoading","isPending","EmptyProvisionerTokens","description","ProvisionerTokenTableSkeleton","row"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provisioner-tokens-settings-section.d.ts","sourceRoot":"","sources":["../../src/components/provisioner-tokens-settings-section.tsx"],"names":[],"mappings":"AA6BA,wBAAgB,yCAAyC,CAAC,EAAC,WAAW,EAAC,EAAE;IAAC,WAAW,EAAE,MAAM,CAAA;CAAC,+BAoF7F"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { QueryLoadError } from '@shipfox/client-ui';
|
|
3
|
+
import { Button } from '@shipfox/react-ui/button';
|
|
4
|
+
import { Icon } from '@shipfox/react-ui/icon';
|
|
5
|
+
import { Modal, ModalBody, ModalContent, ModalHeader, ModalTitle, ModalTrigger } from '@shipfox/react-ui/modal';
|
|
6
|
+
import { RelativeTimeProvider } from '@shipfox/react-ui/relative-time';
|
|
7
|
+
import { Header, Text } from '@shipfox/react-ui/typography';
|
|
8
|
+
import { useMemo, useState } from 'react';
|
|
9
|
+
import { useActiveProvisionersQuery, useProvisionerTokensQuery } from '#hooks/api/provisioner-tokens.js';
|
|
10
|
+
import { CreatedProvisionerTokenPanel, CreateProvisionerTokenForm } from './create-provisioner-token-form.js';
|
|
11
|
+
import { EmptyProvisionerTokens, ProvisionerTokenList, ProvisionerTokenTableSkeleton } from './provisioner-token-list.js';
|
|
12
|
+
export function WorkspaceProvisionerTokensSettingsSection({ workspaceId }) {
|
|
13
|
+
const tokensQuery = useProvisionerTokensQuery(workspaceId);
|
|
14
|
+
const activeProvisionersQuery = useActiveProvisionersQuery(workspaceId);
|
|
15
|
+
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
16
|
+
const [createdToken, setCreatedToken] = useState(null);
|
|
17
|
+
const tokens = tokensQuery.data?.tokens ?? [];
|
|
18
|
+
const activeIds = useMemo(()=>new Set(activeProvisionersQuery.data?.provisioners.map((provisioner)=>provisioner.id)), [
|
|
19
|
+
activeProvisionersQuery.data
|
|
20
|
+
]);
|
|
21
|
+
function handleOpenChange(nextOpen) {
|
|
22
|
+
setIsModalOpen(nextOpen);
|
|
23
|
+
if (!nextOpen) {
|
|
24
|
+
setCreatedToken(null);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
28
|
+
className: "flex min-w-0 flex-col gap-32",
|
|
29
|
+
children: /*#__PURE__*/ _jsxs("section", {
|
|
30
|
+
className: "flex flex-col gap-16",
|
|
31
|
+
children: [
|
|
32
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
33
|
+
className: "flex items-center justify-between gap-16 max-[640px]:items-start",
|
|
34
|
+
children: [
|
|
35
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
36
|
+
className: "flex flex-col gap-4",
|
|
37
|
+
children: [
|
|
38
|
+
/*#__PURE__*/ _jsx(Header, {
|
|
39
|
+
variant: "h3",
|
|
40
|
+
children: "Runner provisioner registration tokens"
|
|
41
|
+
}),
|
|
42
|
+
/*#__PURE__*/ _jsx(Text, {
|
|
43
|
+
size: "sm",
|
|
44
|
+
className: "text-foreground-neutral-muted",
|
|
45
|
+
children: "Register runner provisioners that connect to this workspace and create runners dynamically based on demand."
|
|
46
|
+
})
|
|
47
|
+
]
|
|
48
|
+
}),
|
|
49
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
50
|
+
className: "flex items-center gap-12",
|
|
51
|
+
children: [
|
|
52
|
+
tokensQuery.isFetching && !tokensQuery.isPending || activeProvisionersQuery.isFetching && !activeProvisionersQuery.isPending ? /*#__PURE__*/ _jsx(Icon, {
|
|
53
|
+
name: "loader4Line",
|
|
54
|
+
className: "mt-2 size-18 text-foreground-neutral-muted",
|
|
55
|
+
"aria-label": "Refreshing provisioner tokens"
|
|
56
|
+
}) : null,
|
|
57
|
+
/*#__PURE__*/ _jsxs(Modal, {
|
|
58
|
+
open: isModalOpen,
|
|
59
|
+
onOpenChange: handleOpenChange,
|
|
60
|
+
children: [
|
|
61
|
+
/*#__PURE__*/ _jsx(ModalTrigger, {
|
|
62
|
+
asChild: true,
|
|
63
|
+
children: /*#__PURE__*/ _jsx(Button, {
|
|
64
|
+
children: "Create token"
|
|
65
|
+
})
|
|
66
|
+
}),
|
|
67
|
+
/*#__PURE__*/ _jsxs(ModalContent, {
|
|
68
|
+
"aria-describedby": undefined,
|
|
69
|
+
children: [
|
|
70
|
+
/*#__PURE__*/ _jsx(ModalTitle, {
|
|
71
|
+
className: "sr-only",
|
|
72
|
+
children: "Create provisioner registration token"
|
|
73
|
+
}),
|
|
74
|
+
/*#__PURE__*/ _jsx(ModalHeader, {
|
|
75
|
+
children: /*#__PURE__*/ _jsx(Text, {
|
|
76
|
+
size: "lg",
|
|
77
|
+
"aria-hidden": "true",
|
|
78
|
+
className: "overflow-ellipsis overflow-hidden whitespace-nowrap",
|
|
79
|
+
children: "Create provisioner registration token"
|
|
80
|
+
})
|
|
81
|
+
}),
|
|
82
|
+
createdToken ? /*#__PURE__*/ _jsx(ModalBody, {
|
|
83
|
+
className: "gap-16",
|
|
84
|
+
children: /*#__PURE__*/ _jsx(CreatedProvisionerTokenPanel, {
|
|
85
|
+
token: createdToken
|
|
86
|
+
})
|
|
87
|
+
}) : /*#__PURE__*/ _jsx(CreateProvisionerTokenForm, {
|
|
88
|
+
workspaceId: workspaceId,
|
|
89
|
+
onCreated: setCreatedToken
|
|
90
|
+
})
|
|
91
|
+
]
|
|
92
|
+
})
|
|
93
|
+
]
|
|
94
|
+
})
|
|
95
|
+
]
|
|
96
|
+
})
|
|
97
|
+
]
|
|
98
|
+
}),
|
|
99
|
+
tokensQuery.isPending ? /*#__PURE__*/ _jsx(ProvisionerTokenTableSkeleton, {}) : null,
|
|
100
|
+
tokensQuery.isError && tokensQuery.data === undefined ? /*#__PURE__*/ _jsx(QueryLoadError, {
|
|
101
|
+
query: tokensQuery,
|
|
102
|
+
subject: "provisioner registration tokens"
|
|
103
|
+
}) : null,
|
|
104
|
+
tokensQuery.data !== undefined && tokens.length === 0 ? /*#__PURE__*/ _jsx(EmptyProvisionerTokens, {}) : null,
|
|
105
|
+
tokens.length > 0 ? /*#__PURE__*/ _jsx(RelativeTimeProvider, {
|
|
106
|
+
children: /*#__PURE__*/ _jsx(ProvisionerTokenList, {
|
|
107
|
+
workspaceId: workspaceId,
|
|
108
|
+
tokens: tokens,
|
|
109
|
+
activeIds: activeIds
|
|
110
|
+
})
|
|
111
|
+
}) : null
|
|
112
|
+
]
|
|
113
|
+
})
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
//# sourceMappingURL=provisioner-tokens-settings-section.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/provisioner-tokens-settings-section.tsx"],"sourcesContent":["import type {CreateProvisionerTokenResponseDto} from '@shipfox/api-runners-dto';\nimport {QueryLoadError} from '@shipfox/client-ui';\nimport {Button} from '@shipfox/react-ui/button';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {\n Modal,\n ModalBody,\n ModalContent,\n ModalHeader,\n ModalTitle,\n ModalTrigger,\n} from '@shipfox/react-ui/modal';\nimport {RelativeTimeProvider} from '@shipfox/react-ui/relative-time';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {useMemo, useState} from 'react';\nimport {\n useActiveProvisionersQuery,\n useProvisionerTokensQuery,\n} from '#hooks/api/provisioner-tokens.js';\nimport {\n CreatedProvisionerTokenPanel,\n CreateProvisionerTokenForm,\n} from './create-provisioner-token-form.js';\nimport {\n EmptyProvisionerTokens,\n ProvisionerTokenList,\n ProvisionerTokenTableSkeleton,\n} from './provisioner-token-list.js';\n\nexport function WorkspaceProvisionerTokensSettingsSection({workspaceId}: {workspaceId: string}) {\n const tokensQuery = useProvisionerTokensQuery(workspaceId);\n const activeProvisionersQuery = useActiveProvisionersQuery(workspaceId);\n const [isModalOpen, setIsModalOpen] = useState(false);\n const [createdToken, setCreatedToken] = useState<CreateProvisionerTokenResponseDto | null>(null);\n const tokens = tokensQuery.data?.tokens ?? [];\n const activeIds = useMemo(\n () => new Set(activeProvisionersQuery.data?.provisioners.map((provisioner) => provisioner.id)),\n [activeProvisionersQuery.data],\n );\n\n function handleOpenChange(nextOpen: boolean) {\n setIsModalOpen(nextOpen);\n if (!nextOpen) {\n setCreatedToken(null);\n }\n }\n\n return (\n <div className=\"flex min-w-0 flex-col gap-32\">\n <section className=\"flex flex-col gap-16\">\n <div className=\"flex items-center justify-between gap-16 max-[640px]:items-start\">\n <div className=\"flex flex-col gap-4\">\n <Header variant=\"h3\">Runner provisioner registration tokens</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Register runner provisioners that connect to this workspace and create runners\n dynamically based on demand.\n </Text>\n </div>\n <div className=\"flex items-center gap-12\">\n {(tokensQuery.isFetching && !tokensQuery.isPending) ||\n (activeProvisionersQuery.isFetching && !activeProvisionersQuery.isPending) ? (\n <Icon\n name=\"loader4Line\"\n className=\"mt-2 size-18 text-foreground-neutral-muted\"\n aria-label=\"Refreshing provisioner tokens\"\n />\n ) : null}\n <Modal open={isModalOpen} onOpenChange={handleOpenChange}>\n <ModalTrigger asChild>\n <Button>Create token</Button>\n </ModalTrigger>\n <ModalContent aria-describedby={undefined}>\n <ModalTitle className=\"sr-only\">Create provisioner registration token</ModalTitle>\n <ModalHeader>\n <Text\n size=\"lg\"\n aria-hidden=\"true\"\n className=\"overflow-ellipsis overflow-hidden whitespace-nowrap\"\n >\n Create provisioner registration token\n </Text>\n </ModalHeader>\n {createdToken ? (\n <ModalBody className=\"gap-16\">\n <CreatedProvisionerTokenPanel token={createdToken} />\n </ModalBody>\n ) : (\n <CreateProvisionerTokenForm\n workspaceId={workspaceId}\n onCreated={setCreatedToken}\n />\n )}\n </ModalContent>\n </Modal>\n </div>\n </div>\n\n {tokensQuery.isPending ? <ProvisionerTokenTableSkeleton /> : null}\n\n {tokensQuery.isError && tokensQuery.data === undefined ? (\n <QueryLoadError query={tokensQuery} subject=\"provisioner registration tokens\" />\n ) : null}\n\n {tokensQuery.data !== undefined && tokens.length === 0 ? <EmptyProvisionerTokens /> : null}\n\n {tokens.length > 0 ? (\n <RelativeTimeProvider>\n <ProvisionerTokenList workspaceId={workspaceId} tokens={tokens} activeIds={activeIds} />\n </RelativeTimeProvider>\n ) : null}\n </section>\n </div>\n );\n}\n"],"names":["QueryLoadError","Button","Icon","Modal","ModalBody","ModalContent","ModalHeader","ModalTitle","ModalTrigger","RelativeTimeProvider","Header","Text","useMemo","useState","useActiveProvisionersQuery","useProvisionerTokensQuery","CreatedProvisionerTokenPanel","CreateProvisionerTokenForm","EmptyProvisionerTokens","ProvisionerTokenList","ProvisionerTokenTableSkeleton","WorkspaceProvisionerTokensSettingsSection","workspaceId","tokensQuery","activeProvisionersQuery","isModalOpen","setIsModalOpen","createdToken","setCreatedToken","tokens","data","activeIds","Set","provisioners","map","provisioner","id","handleOpenChange","nextOpen","div","className","section","variant","size","isFetching","isPending","name","aria-label","open","onOpenChange","asChild","aria-describedby","undefined","aria-hidden","token","onCreated","isError","query","subject","length"],"mappings":";AACA,SAAQA,cAAc,QAAO,qBAAqB;AAClD,SAAQC,MAAM,QAAO,2BAA2B;AAChD,SAAQC,IAAI,QAAO,yBAAyB;AAC5C,SACEC,KAAK,EACLC,SAAS,EACTC,YAAY,EACZC,WAAW,EACXC,UAAU,EACVC,YAAY,QACP,0BAA0B;AACjC,SAAQC,oBAAoB,QAAO,kCAAkC;AACrE,SAAQC,MAAM,EAAEC,IAAI,QAAO,+BAA+B;AAC1D,SAAQC,OAAO,EAAEC,QAAQ,QAAO,QAAQ;AACxC,SACEC,0BAA0B,EAC1BC,yBAAyB,QACpB,mCAAmC;AAC1C,SACEC,4BAA4B,EAC5BC,0BAA0B,QACrB,qCAAqC;AAC5C,SACEC,sBAAsB,EACtBC,oBAAoB,EACpBC,6BAA6B,QACxB,8BAA8B;AAErC,OAAO,SAASC,0CAA0C,EAACC,WAAW,EAAwB;IAC5F,MAAMC,cAAcR,0BAA0BO;IAC9C,MAAME,0BAA0BV,2BAA2BQ;IAC3D,MAAM,CAACG,aAAaC,eAAe,GAAGb,SAAS;IAC/C,MAAM,CAACc,cAAcC,gBAAgB,GAAGf,SAAmD;IAC3F,MAAMgB,SAASN,YAAYO,IAAI,EAAED,UAAU,EAAE;IAC7C,MAAME,YAAYnB,QAChB,IAAM,IAAIoB,IAAIR,wBAAwBM,IAAI,EAAEG,aAAaC,IAAI,CAACC,cAAgBA,YAAYC,EAAE,IAC5F;QAACZ,wBAAwBM,IAAI;KAAC;IAGhC,SAASO,iBAAiBC,QAAiB;QACzCZ,eAAeY;QACf,IAAI,CAACA,UAAU;YACbV,gBAAgB;QAClB;IACF;IAEA,qBACE,KAACW;QAAIC,WAAU;kBACb,cAAA,MAACC;YAAQD,WAAU;;8BACjB,MAACD;oBAAIC,WAAU;;sCACb,MAACD;4BAAIC,WAAU;;8CACb,KAAC9B;oCAAOgC,SAAQ;8CAAK;;8CACrB,KAAC/B;oCAAKgC,MAAK;oCAAKH,WAAU;8CAAgC;;;;sCAK5D,MAACD;4BAAIC,WAAU;;gCACXjB,YAAYqB,UAAU,IAAI,CAACrB,YAAYsB,SAAS,IACjDrB,wBAAwBoB,UAAU,IAAI,CAACpB,wBAAwBqB,SAAS,iBACvE,KAAC3C;oCACC4C,MAAK;oCACLN,WAAU;oCACVO,cAAW;qCAEX;8CACJ,MAAC5C;oCAAM6C,MAAMvB;oCAAawB,cAAcZ;;sDACtC,KAAC7B;4CAAa0C,OAAO;sDACnB,cAAA,KAACjD;0DAAO;;;sDAEV,MAACI;4CAAa8C,oBAAkBC;;8DAC9B,KAAC7C;oDAAWiC,WAAU;8DAAU;;8DAChC,KAAClC;8DACC,cAAA,KAACK;wDACCgC,MAAK;wDACLU,eAAY;wDACZb,WAAU;kEACX;;;gDAIFb,6BACC,KAACvB;oDAAUoC,WAAU;8DACnB,cAAA,KAACxB;wDAA6BsC,OAAO3B;;mEAGvC,KAACV;oDACCK,aAAaA;oDACbiC,WAAW3B;;;;;;;;;;gBAQtBL,YAAYsB,SAAS,iBAAG,KAACzB,qCAAmC;gBAE5DG,YAAYiC,OAAO,IAAIjC,YAAYO,IAAI,KAAKsB,0BAC3C,KAACpD;oBAAeyD,OAAOlC;oBAAamC,SAAQ;qBAC1C;gBAEHnC,YAAYO,IAAI,KAAKsB,aAAavB,OAAO8B,MAAM,KAAK,kBAAI,KAACzC,8BAA4B;gBAErFW,OAAO8B,MAAM,GAAG,kBACf,KAAClD;8BACC,cAAA,KAACU;wBAAqBG,aAAaA;wBAAaO,QAAQA;wBAAQE,WAAWA;;qBAE3E;;;;AAIZ"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-date.d.ts","sourceRoot":"","sources":["../../src/components/token-date.tsx"],"names":[],"mappings":"AAEA,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,IAAI,EACJ,SAAS,GACV,EAAE;IACD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B,+BAgBA"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from '@shipfox/react-ui/tooltip';
|
|
3
|
+
export function TokenDate({ value, date, timestamp }) {
|
|
4
|
+
if (!value || !timestamp) return /*#__PURE__*/ _jsx(_Fragment, {
|
|
5
|
+
children: date
|
|
6
|
+
});
|
|
7
|
+
return /*#__PURE__*/ _jsxs(Tooltip, {
|
|
8
|
+
children: [
|
|
9
|
+
/*#__PURE__*/ _jsx(TooltipTrigger, {
|
|
10
|
+
asChild: true,
|
|
11
|
+
children: /*#__PURE__*/ _jsx("button", {
|
|
12
|
+
type: "button",
|
|
13
|
+
className: "cursor-help rounded-4 outline-none focus-visible:shadow-button-neutral-focus",
|
|
14
|
+
children: /*#__PURE__*/ _jsx("time", {
|
|
15
|
+
dateTime: value,
|
|
16
|
+
children: date
|
|
17
|
+
})
|
|
18
|
+
})
|
|
19
|
+
}),
|
|
20
|
+
/*#__PURE__*/ _jsx(TooltipContent, {
|
|
21
|
+
children: timestamp
|
|
22
|
+
})
|
|
23
|
+
]
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=token-date.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/token-date.tsx"],"sourcesContent":["import {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\n\nexport function TokenDate({\n value,\n date,\n timestamp,\n}: {\n value: string | null;\n date: string;\n timestamp: string | undefined;\n}) {\n if (!value || !timestamp) return <>{date}</>;\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n className=\"cursor-help rounded-4 outline-none focus-visible:shadow-button-neutral-focus\"\n >\n <time dateTime={value}>{date}</time>\n </button>\n </TooltipTrigger>\n <TooltipContent>{timestamp}</TooltipContent>\n </Tooltip>\n );\n}\n"],"names":["Tooltip","TooltipContent","TooltipTrigger","TokenDate","value","date","timestamp","asChild","button","type","className","time","dateTime"],"mappings":";AAAA,SAAQA,OAAO,EAAEC,cAAc,EAAEC,cAAc,QAAO,4BAA4B;AAElF,OAAO,SAASC,UAAU,EACxBC,KAAK,EACLC,IAAI,EACJC,SAAS,EAKV;IACC,IAAI,CAACF,SAAS,CAACE,WAAW,qBAAO;kBAAGD;;IAEpC,qBACE,MAACL;;0BACC,KAACE;gBAAeK,OAAO;0BACrB,cAAA,KAACC;oBACCC,MAAK;oBACLC,WAAU;8BAEV,cAAA,KAACC;wBAAKC,UAAUR;kCAAQC;;;;0BAG5B,KAACJ;0BAAgBK;;;;AAGvB"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type TokenExpirationOption = '86400' | '604800' | '2592000' | '7776000' | '15552000' | '31536000' | 'never';
|
|
2
|
+
export declare const expirationOptions: Array<{
|
|
3
|
+
value: TokenExpirationOption;
|
|
4
|
+
label: string;
|
|
5
|
+
}>;
|
|
6
|
+
export declare function expirationHint(expiration: TokenExpirationOption): string;
|
|
7
|
+
export declare function ExpirationSelect({ value, onValueChange, }: {
|
|
8
|
+
value: TokenExpirationOption;
|
|
9
|
+
onValueChange: (next: TokenExpirationOption) => void;
|
|
10
|
+
}): import("react").JSX.Element;
|
|
11
|
+
//# sourceMappingURL=token-expiration-select.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-expiration-select.d.ts","sourceRoot":"","sources":["../../src/components/token-expiration-select.tsx"],"names":[],"mappings":"AASA,MAAM,MAAM,qBAAqB,GAC7B,OAAO,GACP,QAAQ,GACR,SAAS,GACT,SAAS,GACT,UAAU,GACV,UAAU,GACV,OAAO,CAAC;AAEZ,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,qBAAqB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,CAQlF,CAAC;AAEF,wBAAgB,cAAc,CAAC,UAAU,EAAE,qBAAqB,GAAG,MAAM,CAKxE;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,aAAa,GACd,EAAE;IACD,KAAK,EAAE,qBAAqB,CAAC;IAC7B,aAAa,EAAE,CAAC,IAAI,EAAE,qBAAqB,KAAK,IAAI,CAAC;CACtD,+BAsBA"}
|