@shipfox/client-secrets 13.0.0 → 14.0.1
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +27 -0
- package/dist/components/delete-entry-dialog.js +1 -1
- package/dist/components/delete-entry-dialog.js.map +1 -1
- package/dist/components/form-shell.js +2 -2
- package/dist/components/form-shell.js.map +1 -1
- package/dist/components/secret-form.d.ts.map +1 -1
- package/dist/components/secret-form.js +2 -2
- package/dist/components/secret-form.js.map +1 -1
- package/dist/components/store-section-shell.js +1 -1
- package/dist/components/store-section-shell.js.map +1 -1
- package/dist/components/variable-form.js +1 -1
- package/dist/components/variable-form.js.map +1 -1
- package/dist/components/workspace-secrets-section.js +5 -5
- package/dist/components/workspace-secrets-section.js.map +1 -1
- package/dist/components/workspace-variables-section.js +5 -5
- package/dist/components/workspace-variables-section.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/src/components/delete-entry-dialog.tsx +1 -1
- package/src/components/form-shell.tsx +2 -2
- package/src/components/secret-form.tsx +4 -2
- package/src/components/store-section-shell.tsx +1 -1
- package/src/components/variable-form.tsx +1 -1
- package/src/components/workspace-secrets-section.tsx +5 -5
- package/src/components/workspace-variables-section.tsx +5 -5
- package/tsconfig.build.tsbuildinfo +1 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
$ shipfox-swc
|
|
2
|
-
Successfully compiled: 22 files with swc (
|
|
2
|
+
Successfully compiled: 22 files with swc (465.91ms)
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# @shipfox/client-secrets
|
|
2
2
|
|
|
3
|
+
## 14.0.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 88bf8e8: Migrates the shell, auth, secrets, logs, workspace-settings, config, and invitations
|
|
8
|
+
surfaces to semantic spacing roles and brings them under the `no-raw-spacing` Biome
|
|
9
|
+
plugin. Adds shared menu-surface and edge-specific panel roles for existing spacing
|
|
10
|
+
contracts.
|
|
11
|
+
- Updated dependencies [88bf8e8]
|
|
12
|
+
- Updated dependencies [6aa6c7a]
|
|
13
|
+
- Updated dependencies [5c56ba6]
|
|
14
|
+
- @shipfox/react-ui@1.0.0
|
|
15
|
+
- @shipfox/client-shell@14.0.1
|
|
16
|
+
- @shipfox/client-ui@14.0.1
|
|
17
|
+
|
|
18
|
+
## 14.0.0
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- Updated dependencies [baa7594]
|
|
23
|
+
- Updated dependencies [f8a98cb]
|
|
24
|
+
- Updated dependencies [1267eb3]
|
|
25
|
+
- Updated dependencies [b2d4550]
|
|
26
|
+
- @shipfox/react-ui@0.5.0
|
|
27
|
+
- @shipfox/client-ui@14.0.0
|
|
28
|
+
- @shipfox/client-shell@14.0.0
|
|
29
|
+
|
|
3
30
|
## 13.0.0
|
|
4
31
|
|
|
5
32
|
### Major Changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/delete-entry-dialog.tsx"],"sourcesContent":["import {Button} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {\n Modal,\n ModalBody,\n ModalContent,\n ModalFooter,\n ModalHeader,\n ModalTitle,\n} from '@shipfox/react-ui/modal';\nimport {Text} from '@shipfox/react-ui/typography';\n\nexport function DeleteEntryDialog({\n open,\n onOpenChange,\n entryKey,\n isLoading,\n errorMessage,\n onConfirm,\n}: {\n open: boolean;\n onOpenChange: (next: boolean) => void;\n entryKey: string;\n isLoading: boolean;\n errorMessage?: string | undefined;\n onConfirm: () => void;\n}) {\n return (\n <Modal open={open} onOpenChange={onOpenChange}>\n <ModalContent>\n <ModalHeader>\n <ModalTitle>\n Delete <strong>{entryKey}</strong>?\n </ModalTitle>\n </ModalHeader>\n <ModalBody className=\"gap-
|
|
1
|
+
{"version":3,"sources":["../../src/components/delete-entry-dialog.tsx"],"sourcesContent":["import {Button} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {\n Modal,\n ModalBody,\n ModalContent,\n ModalFooter,\n ModalHeader,\n ModalTitle,\n} from '@shipfox/react-ui/modal';\nimport {Text} from '@shipfox/react-ui/typography';\n\nexport function DeleteEntryDialog({\n open,\n onOpenChange,\n entryKey,\n isLoading,\n errorMessage,\n onConfirm,\n}: {\n open: boolean;\n onOpenChange: (next: boolean) => void;\n entryKey: string;\n isLoading: boolean;\n errorMessage?: string | undefined;\n onConfirm: () => void;\n}) {\n return (\n <Modal open={open} onOpenChange={onOpenChange}>\n <ModalContent>\n <ModalHeader>\n <ModalTitle>\n Delete <strong>{entryKey}</strong>?\n </ModalTitle>\n </ModalHeader>\n <ModalBody className=\"gap-group\">\n <Text size=\"sm\">\n Workflows that reference <strong>{entryKey}</strong> will fail at their next run.\n </Text>\n {errorMessage ? (\n <Callout role=\"alert\" type=\"error\">\n <Text size=\"sm\">{errorMessage}</Text>\n </Callout>\n ) : null}\n </ModalBody>\n <ModalFooter>\n <Button variant=\"secondary\" onClick={() => onOpenChange(false)}>\n Cancel\n </Button>\n <Button variant=\"danger\" isLoading={isLoading} onClick={onConfirm}>\n Delete\n </Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n );\n}\n"],"names":["Button","Callout","Modal","ModalBody","ModalContent","ModalFooter","ModalHeader","ModalTitle","Text","DeleteEntryDialog","open","onOpenChange","entryKey","isLoading","errorMessage","onConfirm","strong","className","size","role","type","variant","onClick"],"mappings":";AAAA,SAAQA,MAAM,QAAO,2BAA2B;AAChD,SAAQC,OAAO,QAAO,4BAA4B;AAClD,SACEC,KAAK,EACLC,SAAS,EACTC,YAAY,EACZC,WAAW,EACXC,WAAW,EACXC,UAAU,QACL,0BAA0B;AACjC,SAAQC,IAAI,QAAO,+BAA+B;AAElD,OAAO,SAASC,kBAAkB,EAChCC,IAAI,EACJC,YAAY,EACZC,QAAQ,EACRC,SAAS,EACTC,YAAY,EACZC,SAAS,EAQV;IACC,qBACE,KAACb;QAAMQ,MAAMA;QAAMC,cAAcA;kBAC/B,cAAA,MAACP;;8BACC,KAACE;8BACC,cAAA,MAACC;;4BAAW;0CACH,KAACS;0CAAQJ;;4BAAkB;;;;8BAGtC,MAACT;oBAAUc,WAAU;;sCACnB,MAACT;4BAAKU,MAAK;;gCAAK;8CACW,KAACF;8CAAQJ;;gCAAkB;;;wBAErDE,6BACC,KAACb;4BAAQkB,MAAK;4BAAQC,MAAK;sCACzB,cAAA,KAACZ;gCAAKU,MAAK;0CAAMJ;;6BAEjB;;;8BAEN,MAACT;;sCACC,KAACL;4BAAOqB,SAAQ;4BAAYC,SAAS,IAAMX,aAAa;sCAAQ;;sCAGhE,KAACX;4BAAOqB,SAAQ;4BAASR,WAAWA;4BAAWS,SAASP;sCAAW;;;;;;;AAO7E"}
|
|
@@ -6,7 +6,7 @@ import { cn } from '@shipfox/react-ui/utils';
|
|
|
6
6
|
* tests) without a Modal context.
|
|
7
7
|
*/ export function FormBody({ children, className }) {
|
|
8
8
|
return /*#__PURE__*/ _jsx("div", {
|
|
9
|
-
className: cn('flex w-full flex-col items-start gap-
|
|
9
|
+
className: cn('flex w-full flex-col items-start gap-group bg-background-neutral-base px-frame pt-[16px] pb-panel', className),
|
|
10
10
|
children: children
|
|
11
11
|
});
|
|
12
12
|
}
|
|
@@ -18,7 +18,7 @@ export function FormFooter({ children }) {
|
|
|
18
18
|
className: "h-[1px] w-full bg-border-neutral-strong"
|
|
19
19
|
}),
|
|
20
20
|
/*#__PURE__*/ _jsx("div", {
|
|
21
|
-
className: "flex w-full items-center justify-end gap-
|
|
21
|
+
className: "flex w-full items-center justify-end gap-group bg-background-neutral-base px-frame py-[16px]",
|
|
22
22
|
children: children
|
|
23
23
|
})
|
|
24
24
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/form-shell.tsx"],"sourcesContent":["import {cn} from '@shipfox/react-ui/utils';\nimport type {ReactNode} from 'react';\n\n/**\n * Modal-agnostic body/footer layout matching `ModalBody`/`ModalFooter` so the\n * forms render the same inside a `ModalContent` and standalone (stories, RTL\n * tests) without a Modal context.\n */\nexport function FormBody({children, className}: {children: ReactNode; className?: string}) {\n return (\n <div\n className={cn(\n 'flex w-full flex-col items-start gap-
|
|
1
|
+
{"version":3,"sources":["../../src/components/form-shell.tsx"],"sourcesContent":["import {cn} from '@shipfox/react-ui/utils';\nimport type {ReactNode} from 'react';\n\n/**\n * Modal-agnostic body/footer layout matching `ModalBody`/`ModalFooter` so the\n * forms render the same inside a `ModalContent` and standalone (stories, RTL\n * tests) without a Modal context.\n */\nexport function FormBody({children, className}: {children: ReactNode; className?: string}) {\n return (\n <div\n className={cn(\n 'flex w-full flex-col items-start gap-group bg-background-neutral-base px-frame pt-[16px] pb-panel',\n className,\n )}\n >\n {children}\n </div>\n );\n}\n\nexport function FormFooter({children}: {children: ReactNode}) {\n return (\n <div className=\"flex w-full shrink-0 flex-col\">\n <div className=\"h-[1px] w-full bg-border-neutral-strong\" />\n <div className=\"flex w-full items-center justify-end gap-group bg-background-neutral-base px-frame py-[16px]\">\n {children}\n </div>\n </div>\n );\n}\n"],"names":["cn","FormBody","children","className","div","FormFooter"],"mappings":";AAAA,SAAQA,EAAE,QAAO,0BAA0B;AAG3C;;;;CAIC,GACD,OAAO,SAASC,SAAS,EAACC,QAAQ,EAAEC,SAAS,EAA4C;IACvF,qBACE,KAACC;QACCD,WAAWH,GACT,qGACAG;kBAGDD;;AAGP;AAEA,OAAO,SAASG,WAAW,EAACH,QAAQ,EAAwB;IAC1D,qBACE,MAACE;QAAID,WAAU;;0BACb,KAACC;gBAAID,WAAU;;0BACf,KAACC;gBAAID,WAAU;0BACZD;;;;AAIT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"secret-form.d.ts","sourceRoot":"","sources":["../../src/components/secret-form.tsx"],"names":[],"mappings":"AAsBA,eAAO,MAAM,cAAc,gBAAgB,CAAC;AAM5C,wBAAgB,UAAU,CAAC,EACzB,WAAW,EACX,IAAI,EACJ,WAAW,EACX,YAAiB,EACjB,OAAO,EACP,QAAQ,GACT,EAAE;IACD,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAC7C,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB,+
|
|
1
|
+
{"version":3,"file":"secret-form.d.ts","sourceRoot":"","sources":["../../src/components/secret-form.tsx"],"names":[],"mappings":"AAsBA,eAAO,MAAM,cAAc,gBAAgB,CAAC;AAM5C,wBAAgB,UAAU,CAAC,EACzB,WAAW,EACX,IAAI,EACJ,WAAW,EACX,YAAiB,EACjB,OAAO,EACP,QAAQ,GACT,EAAE;IACD,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAC7C,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB,+BA2IA"}
|
|
@@ -54,7 +54,7 @@ export function SecretForm({ workspaceId, mode, existingKey, reservedKeys = [],
|
|
|
54
54
|
children: [
|
|
55
55
|
/*#__PURE__*/ _jsxs("form", {
|
|
56
56
|
id: SECRET_FORM_ID,
|
|
57
|
-
className: "flex w-full flex-col gap-
|
|
57
|
+
className: "flex w-full flex-col gap-group",
|
|
58
58
|
noValidate: true,
|
|
59
59
|
onSubmit: (event)=>{
|
|
60
60
|
event.preventDefault();
|
|
@@ -108,7 +108,7 @@ export function SecretForm({ workspaceId, mode, existingKey, reservedKeys = [],
|
|
|
108
108
|
className: "relative",
|
|
109
109
|
children: [
|
|
110
110
|
/*#__PURE__*/ _jsx(FormFieldTextarea, {
|
|
111
|
-
className: showValue ? 'pr-
|
|
111
|
+
className: showValue ? 'pr-[32px] font-code' : 'pr-[32px] font-code [-webkit-text-security:disc]',
|
|
112
112
|
autoComplete: "off",
|
|
113
113
|
spellCheck: false,
|
|
114
114
|
rows: 3,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/secret-form.tsx"],"sourcesContent":["import {Button, IconButton} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {\n FormField,\n FormFieldInput,\n FormFieldTextarea,\n fieldError,\n} from '@shipfox/react-ui/form-field';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {useForm} from '@tanstack/react-form';\nimport {useState} from 'react';\nimport {\n normalizeStoreKey,\n STORE_KEY_HELP,\n shouldWarnShortSecretValue,\n validateNewStoreKey,\n workspaceStoreScope,\n} from '#core/store.js';\nimport {usePutSecretMutation} from '#hooks/api/secrets.js';\nimport {secretsErrorToFormError} from './form-errors.js';\nimport {FormBody, FormFooter} from './form-shell.js';\n\nexport const SECRET_FORM_ID = 'secret-form';\n\n// Client-side mirror of the server default SECRETS_SHORT_VALUE_WARN_LENGTH. The\n// advisory is best-effort UX, so drift from a self-hosted override is cosmetic.\nconst SHORT_VALUE_THRESHOLD = 12;\n\nexport function SecretForm({\n workspaceId,\n mode,\n existingKey,\n reservedKeys = [],\n onSaved,\n onCancel,\n}: {\n workspaceId: string;\n mode: 'create' | 'edit';\n existingKey?: string | undefined;\n reservedKeys?: readonly string[] | undefined;\n onSaved: () => void;\n onCancel: () => void;\n}) {\n const putSecret = usePutSecretMutation();\n const [formError, setFormError] = useState<string | undefined>();\n const [showValue, setShowValue] = useState(false);\n\n const form = useForm({\n defaultValues: {key: existingKey ?? '', value: ''},\n onSubmit: async ({value}) => {\n setFormError(undefined);\n try {\n await putSecret.mutateAsync({\n workspaceId,\n key: normalizeStoreKey(value.key),\n value: value.value,\n scope: workspaceStoreScope,\n });\n onSaved();\n } catch (error) {\n const mapped = secretsErrorToFormError(error);\n if (mapped.kind === 'field') {\n form.setFieldMeta(mapped.field, (prev) => ({\n ...prev,\n errorMap: {...prev.errorMap, onServer: mapped.message},\n }));\n } else {\n setFormError(mapped.message);\n }\n }\n },\n });\n\n return (\n <>\n <FormBody>\n <form\n id={SECRET_FORM_ID}\n className=\"flex w-full flex-col gap-16\"\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n event.stopPropagation();\n void form.handleSubmit();\n }}\n >\n <form.Field\n name=\"key\"\n validators={{\n onBlur: ({value}) => validateNewStoreKey(value, {mode, reservedKeys, kind: 'secret'}),\n onSubmit: ({value}) =>\n validateNewStoreKey(value, {mode, reservedKeys, kind: 'secret'}),\n }}\n >\n {(field) => (\n <FormField\n label=\"Name\"\n id=\"secret-key\"\n description={STORE_KEY_HELP}\n error={fieldError(field)}\n >\n <FormFieldInput\n className=\"font-code\"\n autoComplete=\"off\"\n spellCheck={false}\n disabled={mode === 'edit'}\n placeholder=\"MY_TOKEN\"\n value={field.state.value}\n onChange={(event) => field.handleChange(normalizeStoreKey(event.target.value))}\n onBlur={field.handleBlur}\n />\n </FormField>\n )}\n </form.Field>\n\n <form.Field\n name=\"value\"\n validators={{\n onBlur: ({value}) => (value.length > 0 ? undefined : 'A value is required.'),\n onSubmit: ({value}) => (value.length > 0 ? undefined : 'A value is required.'),\n }}\n >\n {(field) => (\n <FormField label=\"Value\" id=\"secret-value\" error={fieldError(field)}>\n <div className=\"relative\">\n <FormFieldTextarea\n className={\n showValue ? 'pr-32 font-code' : 'pr-32 font-code [-webkit-text-security:disc]'\n }\n autoComplete=\"off\"\n spellCheck={false}\n rows={3}\n placeholder={\n mode === 'edit'\n ? 'Enter a new value to replace the current one'\n : 'Paste the secret value'\n }\n value={field.state.value}\n onChange={(event) => field.handleChange(event.target.value)}\n onBlur={field.handleBlur}\n />\n <IconButton\n type=\"button\"\n variant=\"transparent\"\n size=\"xs\"\n className=\"absolute top-6 right-6\"\n icon={showValue ? 'eyeOffLine' : 'eyeLine'}\n aria-label={showValue ? 'Hide value' : 'Show value'}\n onClick={() => setShowValue((prev) => !prev)}\n />\n </div>\n {shouldWarnShortSecretValue(field.state.value, SHORT_VALUE_THRESHOLD) ? (\n <Callout role=\"alert\" type=\"warning\">\n <Text size=\"sm\">\n Very short secrets can match ordinary log text and redact unrelated output. If\n this value is not sensitive, store it as a Variable instead.\n </Text>\n </Callout>\n ) : null}\n </FormField>\n )}\n </form.Field>\n </form>\n {formError ? (\n <Callout role=\"alert\" type=\"error\">\n <Text size=\"sm\">{formError}</Text>\n </Callout>\n ) : null}\n </FormBody>\n <FormFooter>\n <Button variant=\"secondary\" type=\"button\" onClick={onCancel}>\n Cancel\n </Button>\n <Button type=\"submit\" form={SECRET_FORM_ID} isLoading={putSecret.isPending}>\n {mode === 'edit' ? 'Update secret' : 'Create secret'}\n </Button>\n </FormFooter>\n </>\n );\n}\n"],"names":["Button","IconButton","Callout","FormField","FormFieldInput","FormFieldTextarea","fieldError","Text","useForm","useState","normalizeStoreKey","STORE_KEY_HELP","shouldWarnShortSecretValue","validateNewStoreKey","workspaceStoreScope","usePutSecretMutation","secretsErrorToFormError","FormBody","FormFooter","SECRET_FORM_ID","SHORT_VALUE_THRESHOLD","SecretForm","workspaceId","mode","existingKey","reservedKeys","onSaved","onCancel","putSecret","formError","setFormError","showValue","setShowValue","form","defaultValues","key","value","onSubmit","undefined","mutateAsync","scope","error","mapped","kind","setFieldMeta","field","prev","errorMap","onServer","message","id","className","noValidate","event","preventDefault","stopPropagation","handleSubmit","Field","name","validators","onBlur","label","description","autoComplete","spellCheck","disabled","placeholder","state","onChange","handleChange","target","handleBlur","length","div","rows","type","variant","size","icon","aria-label","onClick","role","isLoading","isPending"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/components/secret-form.tsx"],"sourcesContent":["import {Button, IconButton} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {\n FormField,\n FormFieldInput,\n FormFieldTextarea,\n fieldError,\n} from '@shipfox/react-ui/form-field';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {useForm} from '@tanstack/react-form';\nimport {useState} from 'react';\nimport {\n normalizeStoreKey,\n STORE_KEY_HELP,\n shouldWarnShortSecretValue,\n validateNewStoreKey,\n workspaceStoreScope,\n} from '#core/store.js';\nimport {usePutSecretMutation} from '#hooks/api/secrets.js';\nimport {secretsErrorToFormError} from './form-errors.js';\nimport {FormBody, FormFooter} from './form-shell.js';\n\nexport const SECRET_FORM_ID = 'secret-form';\n\n// Client-side mirror of the server default SECRETS_SHORT_VALUE_WARN_LENGTH. The\n// advisory is best-effort UX, so drift from a self-hosted override is cosmetic.\nconst SHORT_VALUE_THRESHOLD = 12;\n\nexport function SecretForm({\n workspaceId,\n mode,\n existingKey,\n reservedKeys = [],\n onSaved,\n onCancel,\n}: {\n workspaceId: string;\n mode: 'create' | 'edit';\n existingKey?: string | undefined;\n reservedKeys?: readonly string[] | undefined;\n onSaved: () => void;\n onCancel: () => void;\n}) {\n const putSecret = usePutSecretMutation();\n const [formError, setFormError] = useState<string | undefined>();\n const [showValue, setShowValue] = useState(false);\n\n const form = useForm({\n defaultValues: {key: existingKey ?? '', value: ''},\n onSubmit: async ({value}) => {\n setFormError(undefined);\n try {\n await putSecret.mutateAsync({\n workspaceId,\n key: normalizeStoreKey(value.key),\n value: value.value,\n scope: workspaceStoreScope,\n });\n onSaved();\n } catch (error) {\n const mapped = secretsErrorToFormError(error);\n if (mapped.kind === 'field') {\n form.setFieldMeta(mapped.field, (prev) => ({\n ...prev,\n errorMap: {...prev.errorMap, onServer: mapped.message},\n }));\n } else {\n setFormError(mapped.message);\n }\n }\n },\n });\n\n return (\n <>\n <FormBody>\n <form\n id={SECRET_FORM_ID}\n className=\"flex w-full flex-col gap-group\"\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n event.stopPropagation();\n void form.handleSubmit();\n }}\n >\n <form.Field\n name=\"key\"\n validators={{\n onBlur: ({value}) => validateNewStoreKey(value, {mode, reservedKeys, kind: 'secret'}),\n onSubmit: ({value}) =>\n validateNewStoreKey(value, {mode, reservedKeys, kind: 'secret'}),\n }}\n >\n {(field) => (\n <FormField\n label=\"Name\"\n id=\"secret-key\"\n description={STORE_KEY_HELP}\n error={fieldError(field)}\n >\n <FormFieldInput\n className=\"font-code\"\n autoComplete=\"off\"\n spellCheck={false}\n disabled={mode === 'edit'}\n placeholder=\"MY_TOKEN\"\n value={field.state.value}\n onChange={(event) => field.handleChange(normalizeStoreKey(event.target.value))}\n onBlur={field.handleBlur}\n />\n </FormField>\n )}\n </form.Field>\n\n <form.Field\n name=\"value\"\n validators={{\n onBlur: ({value}) => (value.length > 0 ? undefined : 'A value is required.'),\n onSubmit: ({value}) => (value.length > 0 ? undefined : 'A value is required.'),\n }}\n >\n {(field) => (\n <FormField label=\"Value\" id=\"secret-value\" error={fieldError(field)}>\n <div className=\"relative\">\n <FormFieldTextarea\n className={\n showValue\n ? 'pr-[32px] font-code'\n : 'pr-[32px] font-code [-webkit-text-security:disc]'\n }\n autoComplete=\"off\"\n spellCheck={false}\n rows={3}\n placeholder={\n mode === 'edit'\n ? 'Enter a new value to replace the current one'\n : 'Paste the secret value'\n }\n value={field.state.value}\n onChange={(event) => field.handleChange(event.target.value)}\n onBlur={field.handleBlur}\n />\n <IconButton\n type=\"button\"\n variant=\"transparent\"\n size=\"xs\"\n className=\"absolute top-6 right-6\"\n icon={showValue ? 'eyeOffLine' : 'eyeLine'}\n aria-label={showValue ? 'Hide value' : 'Show value'}\n onClick={() => setShowValue((prev) => !prev)}\n />\n </div>\n {shouldWarnShortSecretValue(field.state.value, SHORT_VALUE_THRESHOLD) ? (\n <Callout role=\"alert\" type=\"warning\">\n <Text size=\"sm\">\n Very short secrets can match ordinary log text and redact unrelated output. If\n this value is not sensitive, store it as a Variable instead.\n </Text>\n </Callout>\n ) : null}\n </FormField>\n )}\n </form.Field>\n </form>\n {formError ? (\n <Callout role=\"alert\" type=\"error\">\n <Text size=\"sm\">{formError}</Text>\n </Callout>\n ) : null}\n </FormBody>\n <FormFooter>\n <Button variant=\"secondary\" type=\"button\" onClick={onCancel}>\n Cancel\n </Button>\n <Button type=\"submit\" form={SECRET_FORM_ID} isLoading={putSecret.isPending}>\n {mode === 'edit' ? 'Update secret' : 'Create secret'}\n </Button>\n </FormFooter>\n </>\n );\n}\n"],"names":["Button","IconButton","Callout","FormField","FormFieldInput","FormFieldTextarea","fieldError","Text","useForm","useState","normalizeStoreKey","STORE_KEY_HELP","shouldWarnShortSecretValue","validateNewStoreKey","workspaceStoreScope","usePutSecretMutation","secretsErrorToFormError","FormBody","FormFooter","SECRET_FORM_ID","SHORT_VALUE_THRESHOLD","SecretForm","workspaceId","mode","existingKey","reservedKeys","onSaved","onCancel","putSecret","formError","setFormError","showValue","setShowValue","form","defaultValues","key","value","onSubmit","undefined","mutateAsync","scope","error","mapped","kind","setFieldMeta","field","prev","errorMap","onServer","message","id","className","noValidate","event","preventDefault","stopPropagation","handleSubmit","Field","name","validators","onBlur","label","description","autoComplete","spellCheck","disabled","placeholder","state","onChange","handleChange","target","handleBlur","length","div","rows","type","variant","size","icon","aria-label","onClick","role","isLoading","isPending"],"mappings":"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"}
|
|
@@ -14,7 +14,7 @@ export const STORE_SURFACE_CLASS = 'overflow-hidden rounded-8 border border-bord
|
|
|
14
14
|
1,
|
|
15
15
|
2
|
|
16
16
|
].map((row)=>/*#__PURE__*/ _jsxs("li", {
|
|
17
|
-
className: "flex items-center gap-
|
|
17
|
+
className: "flex items-center gap-cluster px-row py-row",
|
|
18
18
|
children: [
|
|
19
19
|
/*#__PURE__*/ _jsx(Skeleton, {
|
|
20
20
|
className: "h-16 w-140"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/store-section-shell.tsx"],"sourcesContent":["import {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {cn} from '@shipfox/react-ui/utils';\n\nexport const STORE_SURFACE_CLASS =\n 'overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base';\n\n/** Placeholder rows shown while the store list loads. */\nexport function StoreRowsSkeleton({label}: {label: string}) {\n return (\n <div role=\"status\" aria-label={label} className={STORE_SURFACE_CLASS}>\n <ul className=\"divide-y divide-border-neutral-base\">\n {[0, 1, 2].map((row) => (\n <li key={row} className=\"flex items-center gap-
|
|
1
|
+
{"version":3,"sources":["../../src/components/store-section-shell.tsx"],"sourcesContent":["import {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {cn} from '@shipfox/react-ui/utils';\n\nexport const STORE_SURFACE_CLASS =\n 'overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base';\n\n/** Placeholder rows shown while the store list loads. */\nexport function StoreRowsSkeleton({label}: {label: string}) {\n return (\n <div role=\"status\" aria-label={label} className={STORE_SURFACE_CLASS}>\n <ul className=\"divide-y divide-border-neutral-base\">\n {[0, 1, 2].map((row) => (\n <li key={row} className=\"flex items-center gap-cluster px-row py-row\">\n <Skeleton className=\"h-16 w-140\" />\n <Skeleton className=\"h-16 w-96\" />\n <Skeleton className=\"ml-auto h-14 w-80 shrink-0\" />\n </li>\n ))}\n </ul>\n </div>\n );\n}\n\nexport function StoreSurface({\n className,\n children,\n}: {\n className?: string;\n children: React.ReactNode;\n}) {\n return <div className={cn(STORE_SURFACE_CLASS, className)}>{children}</div>;\n}\n"],"names":["Skeleton","cn","STORE_SURFACE_CLASS","StoreRowsSkeleton","label","div","role","aria-label","className","ul","map","row","li","StoreSurface","children"],"mappings":";AAAA,SAAQA,QAAQ,QAAO,6BAA6B;AACpD,SAAQC,EAAE,QAAO,0BAA0B;AAE3C,OAAO,MAAMC,sBACX,yFAAyF;AAE3F,uDAAuD,GACvD,OAAO,SAASC,kBAAkB,EAACC,KAAK,EAAkB;IACxD,qBACE,KAACC;QAAIC,MAAK;QAASC,cAAYH;QAAOI,WAAWN;kBAC/C,cAAA,KAACO;YAAGD,WAAU;sBACX;gBAAC;gBAAG;gBAAG;aAAE,CAACE,GAAG,CAAC,CAACC,oBACd,MAACC;oBAAaJ,WAAU;;sCACtB,KAACR;4BAASQ,WAAU;;sCACpB,KAACR;4BAASQ,WAAU;;sCACpB,KAACR;4BAASQ,WAAU;;;mBAHbG;;;AASnB;AAEA,OAAO,SAASE,aAAa,EAC3BL,SAAS,EACTM,QAAQ,EAIT;IACC,qBAAO,KAACT;QAAIG,WAAWP,GAAGC,qBAAqBM;kBAAaM;;AAC9D"}
|
|
@@ -70,7 +70,7 @@ export function VariableForm({ workspaceId, mode, existingKey, existingValue, ex
|
|
|
70
70
|
children: [
|
|
71
71
|
/*#__PURE__*/ _jsxs("form", {
|
|
72
72
|
id: VARIABLE_FORM_ID,
|
|
73
|
-
className: "flex w-full flex-col gap-
|
|
73
|
+
className: "flex w-full flex-col gap-group",
|
|
74
74
|
noValidate: true,
|
|
75
75
|
onSubmit: (event)=>{
|
|
76
76
|
event.preventDefault();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/variable-form.tsx"],"sourcesContent":["import {Button} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {\n FormField,\n FormFieldInput,\n FormFieldTextarea,\n fieldError,\n} from '@shipfox/react-ui/form-field';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {useForm} from '@tanstack/react-form';\nimport {useEffect, useRef, useState} from 'react';\nimport {\n normalizeStoreKey,\n STORE_KEY_HELP,\n shouldWarnSensitiveVariableName,\n validateNewStoreKey,\n workspaceStoreScope,\n} from '#core/store.js';\nimport {usePutVariableMutation, useVariableQuery} from '#hooks/api/variables.js';\nimport {secretsErrorToFormError} from './form-errors.js';\nimport {FormBody, FormFooter} from './form-shell.js';\n\nexport const VARIABLE_FORM_ID = 'variable-form';\n\nexport function VariableForm({\n workspaceId,\n mode,\n existingKey,\n existingValue,\n existingValueTruncated = false,\n reservedKeys = [],\n onSaved,\n onCancel,\n}: {\n workspaceId: string;\n mode: 'create' | 'edit';\n existingKey?: string | undefined;\n existingValue?: string | undefined;\n existingValueTruncated?: boolean | undefined;\n reservedKeys?: readonly string[] | undefined;\n onSaved: () => void;\n onCancel: () => void;\n}) {\n const putVariable = usePutVariableMutation();\n const [formError, setFormError] = useState<string | undefined>();\n\n // The list value is only a preview, so a truncated variable must load its full\n // value before editing to avoid saving the truncated preview back.\n const needsFullValue = mode === 'edit' && existingValueTruncated;\n const fullValueQuery = useVariableQuery(workspaceId, needsFullValue ? existingKey : undefined);\n\n const form = useForm({\n defaultValues: {key: existingKey ?? '', value: existingValue ?? ''},\n onSubmit: async ({value}) => {\n setFormError(undefined);\n try {\n await putVariable.mutateAsync({\n workspaceId,\n key: normalizeStoreKey(value.key),\n value: value.value,\n scope: workspaceStoreScope,\n });\n onSaved();\n } catch (error) {\n const mapped = secretsErrorToFormError(error);\n if (mapped.kind === 'field') {\n form.setFieldMeta(mapped.field, (prev) => ({\n ...prev,\n errorMap: {...prev.errorMap, onServer: mapped.message},\n }));\n } else {\n setFormError(mapped.message);\n }\n }\n },\n });\n\n const populatedRef = useRef(false);\n useEffect(() => {\n if (needsFullValue && fullValueQuery.data && !populatedRef.current) {\n populatedRef.current = true;\n form.setFieldValue('value', fullValueQuery.data.value);\n }\n }, [needsFullValue, fullValueQuery.data, form]);\n\n // The full value must be loaded before a save is allowed, otherwise submitting would\n // overwrite the stored value with the truncated preview. Block until it arrives.\n // whether the fetch is still pending or has failed.\n const awaitingFullValue = needsFullValue && fullValueQuery.data === undefined;\n const loadingFullValue = needsFullValue && fullValueQuery.isPending;\n\n return (\n <>\n <FormBody>\n <form\n id={VARIABLE_FORM_ID}\n className=\"flex w-full flex-col gap-16\"\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n event.stopPropagation();\n void form.handleSubmit();\n }}\n >\n <form.Field\n name=\"key\"\n validators={{\n onBlur: ({value}) =>\n validateNewStoreKey(value, {mode, reservedKeys, kind: 'variable'}),\n onSubmit: ({value}) =>\n validateNewStoreKey(value, {mode, reservedKeys, kind: 'variable'}),\n }}\n >\n {(field) => (\n <FormField\n label=\"Name\"\n id=\"variable-key\"\n description={STORE_KEY_HELP}\n error={fieldError(field)}\n >\n <FormFieldInput\n className=\"font-code\"\n autoComplete=\"off\"\n spellCheck={false}\n disabled={mode === 'edit'}\n placeholder=\"LOG_LEVEL\"\n value={field.state.value}\n onChange={(event) => field.handleChange(normalizeStoreKey(event.target.value))}\n onBlur={field.handleBlur}\n />\n {shouldWarnSensitiveVariableName(field.state.value) ? (\n <Callout role=\"alert\" type=\"warning\">\n <Text size=\"sm\" aria-live=\"polite\">\n This looks like it may be sensitive. Variables are stored in plaintext and are\n not redacted from logs. Use a Secret if this value contains private data.\n </Text>\n </Callout>\n ) : null}\n </FormField>\n )}\n </form.Field>\n\n <form.Field name=\"value\">\n {(field) => (\n <FormField\n label=\"Value\"\n id=\"variable-value\"\n error={fieldError(field)}\n description={loadingFullValue ? 'Loading the current value…' : undefined}\n >\n <FormFieldTextarea\n className=\"font-code\"\n autoComplete=\"off\"\n spellCheck={false}\n rows={3}\n disabled={awaitingFullValue}\n placeholder=\"debug\"\n value={field.state.value}\n onChange={(event) => field.handleChange(event.target.value)}\n onBlur={field.handleBlur}\n />\n </FormField>\n )}\n </form.Field>\n </form>\n {awaitingFullValue && fullValueQuery.isError ? (\n <Callout role=\"alert\" type=\"error\">\n <Text size=\"sm\">Could not load the current value. Close and try again.</Text>\n </Callout>\n ) : null}\n {formError ? (\n <Callout role=\"alert\" type=\"error\">\n <Text size=\"sm\">{formError}</Text>\n </Callout>\n ) : null}\n </FormBody>\n <FormFooter>\n <Button variant=\"secondary\" type=\"button\" onClick={onCancel}>\n Cancel\n </Button>\n <Button\n type=\"submit\"\n form={VARIABLE_FORM_ID}\n isLoading={putVariable.isPending}\n disabled={awaitingFullValue}\n >\n {mode === 'edit' ? 'Update variable' : 'Create variable'}\n </Button>\n </FormFooter>\n </>\n );\n}\n"],"names":["Button","Callout","FormField","FormFieldInput","FormFieldTextarea","fieldError","Text","useForm","useEffect","useRef","useState","normalizeStoreKey","STORE_KEY_HELP","shouldWarnSensitiveVariableName","validateNewStoreKey","workspaceStoreScope","usePutVariableMutation","useVariableQuery","secretsErrorToFormError","FormBody","FormFooter","VARIABLE_FORM_ID","VariableForm","workspaceId","mode","existingKey","existingValue","existingValueTruncated","reservedKeys","onSaved","onCancel","putVariable","formError","setFormError","needsFullValue","fullValueQuery","undefined","form","defaultValues","key","value","onSubmit","mutateAsync","scope","error","mapped","kind","setFieldMeta","field","prev","errorMap","onServer","message","populatedRef","data","current","setFieldValue","awaitingFullValue","loadingFullValue","isPending","id","className","noValidate","event","preventDefault","stopPropagation","handleSubmit","Field","name","validators","onBlur","label","description","autoComplete","spellCheck","disabled","placeholder","state","onChange","handleChange","target","handleBlur","role","type","size","aria-live","rows","isError","variant","onClick","isLoading"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/components/variable-form.tsx"],"sourcesContent":["import {Button} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {\n FormField,\n FormFieldInput,\n FormFieldTextarea,\n fieldError,\n} from '@shipfox/react-ui/form-field';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {useForm} from '@tanstack/react-form';\nimport {useEffect, useRef, useState} from 'react';\nimport {\n normalizeStoreKey,\n STORE_KEY_HELP,\n shouldWarnSensitiveVariableName,\n validateNewStoreKey,\n workspaceStoreScope,\n} from '#core/store.js';\nimport {usePutVariableMutation, useVariableQuery} from '#hooks/api/variables.js';\nimport {secretsErrorToFormError} from './form-errors.js';\nimport {FormBody, FormFooter} from './form-shell.js';\n\nexport const VARIABLE_FORM_ID = 'variable-form';\n\nexport function VariableForm({\n workspaceId,\n mode,\n existingKey,\n existingValue,\n existingValueTruncated = false,\n reservedKeys = [],\n onSaved,\n onCancel,\n}: {\n workspaceId: string;\n mode: 'create' | 'edit';\n existingKey?: string | undefined;\n existingValue?: string | undefined;\n existingValueTruncated?: boolean | undefined;\n reservedKeys?: readonly string[] | undefined;\n onSaved: () => void;\n onCancel: () => void;\n}) {\n const putVariable = usePutVariableMutation();\n const [formError, setFormError] = useState<string | undefined>();\n\n // The list value is only a preview, so a truncated variable must load its full\n // value before editing to avoid saving the truncated preview back.\n const needsFullValue = mode === 'edit' && existingValueTruncated;\n const fullValueQuery = useVariableQuery(workspaceId, needsFullValue ? existingKey : undefined);\n\n const form = useForm({\n defaultValues: {key: existingKey ?? '', value: existingValue ?? ''},\n onSubmit: async ({value}) => {\n setFormError(undefined);\n try {\n await putVariable.mutateAsync({\n workspaceId,\n key: normalizeStoreKey(value.key),\n value: value.value,\n scope: workspaceStoreScope,\n });\n onSaved();\n } catch (error) {\n const mapped = secretsErrorToFormError(error);\n if (mapped.kind === 'field') {\n form.setFieldMeta(mapped.field, (prev) => ({\n ...prev,\n errorMap: {...prev.errorMap, onServer: mapped.message},\n }));\n } else {\n setFormError(mapped.message);\n }\n }\n },\n });\n\n const populatedRef = useRef(false);\n useEffect(() => {\n if (needsFullValue && fullValueQuery.data && !populatedRef.current) {\n populatedRef.current = true;\n form.setFieldValue('value', fullValueQuery.data.value);\n }\n }, [needsFullValue, fullValueQuery.data, form]);\n\n // The full value must be loaded before a save is allowed, otherwise submitting would\n // overwrite the stored value with the truncated preview. Block until it arrives.\n // whether the fetch is still pending or has failed.\n const awaitingFullValue = needsFullValue && fullValueQuery.data === undefined;\n const loadingFullValue = needsFullValue && fullValueQuery.isPending;\n\n return (\n <>\n <FormBody>\n <form\n id={VARIABLE_FORM_ID}\n className=\"flex w-full flex-col gap-group\"\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n event.stopPropagation();\n void form.handleSubmit();\n }}\n >\n <form.Field\n name=\"key\"\n validators={{\n onBlur: ({value}) =>\n validateNewStoreKey(value, {mode, reservedKeys, kind: 'variable'}),\n onSubmit: ({value}) =>\n validateNewStoreKey(value, {mode, reservedKeys, kind: 'variable'}),\n }}\n >\n {(field) => (\n <FormField\n label=\"Name\"\n id=\"variable-key\"\n description={STORE_KEY_HELP}\n error={fieldError(field)}\n >\n <FormFieldInput\n className=\"font-code\"\n autoComplete=\"off\"\n spellCheck={false}\n disabled={mode === 'edit'}\n placeholder=\"LOG_LEVEL\"\n value={field.state.value}\n onChange={(event) => field.handleChange(normalizeStoreKey(event.target.value))}\n onBlur={field.handleBlur}\n />\n {shouldWarnSensitiveVariableName(field.state.value) ? (\n <Callout role=\"alert\" type=\"warning\">\n <Text size=\"sm\" aria-live=\"polite\">\n This looks like it may be sensitive. Variables are stored in plaintext and are\n not redacted from logs. Use a Secret if this value contains private data.\n </Text>\n </Callout>\n ) : null}\n </FormField>\n )}\n </form.Field>\n\n <form.Field name=\"value\">\n {(field) => (\n <FormField\n label=\"Value\"\n id=\"variable-value\"\n error={fieldError(field)}\n description={loadingFullValue ? 'Loading the current value…' : undefined}\n >\n <FormFieldTextarea\n className=\"font-code\"\n autoComplete=\"off\"\n spellCheck={false}\n rows={3}\n disabled={awaitingFullValue}\n placeholder=\"debug\"\n value={field.state.value}\n onChange={(event) => field.handleChange(event.target.value)}\n onBlur={field.handleBlur}\n />\n </FormField>\n )}\n </form.Field>\n </form>\n {awaitingFullValue && fullValueQuery.isError ? (\n <Callout role=\"alert\" type=\"error\">\n <Text size=\"sm\">Could not load the current value. Close and try again.</Text>\n </Callout>\n ) : null}\n {formError ? (\n <Callout role=\"alert\" type=\"error\">\n <Text size=\"sm\">{formError}</Text>\n </Callout>\n ) : null}\n </FormBody>\n <FormFooter>\n <Button variant=\"secondary\" type=\"button\" onClick={onCancel}>\n Cancel\n </Button>\n <Button\n type=\"submit\"\n form={VARIABLE_FORM_ID}\n isLoading={putVariable.isPending}\n disabled={awaitingFullValue}\n >\n {mode === 'edit' ? 'Update variable' : 'Create variable'}\n </Button>\n </FormFooter>\n </>\n );\n}\n"],"names":["Button","Callout","FormField","FormFieldInput","FormFieldTextarea","fieldError","Text","useForm","useEffect","useRef","useState","normalizeStoreKey","STORE_KEY_HELP","shouldWarnSensitiveVariableName","validateNewStoreKey","workspaceStoreScope","usePutVariableMutation","useVariableQuery","secretsErrorToFormError","FormBody","FormFooter","VARIABLE_FORM_ID","VariableForm","workspaceId","mode","existingKey","existingValue","existingValueTruncated","reservedKeys","onSaved","onCancel","putVariable","formError","setFormError","needsFullValue","fullValueQuery","undefined","form","defaultValues","key","value","onSubmit","mutateAsync","scope","error","mapped","kind","setFieldMeta","field","prev","errorMap","onServer","message","populatedRef","data","current","setFieldValue","awaitingFullValue","loadingFullValue","isPending","id","className","noValidate","event","preventDefault","stopPropagation","handleSubmit","Field","name","validators","onBlur","label","description","autoComplete","spellCheck","disabled","placeholder","state","onChange","handleChange","target","handleBlur","role","type","size","aria-live","rows","isError","variant","onClick","isLoading"],"mappings":"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"}
|
|
@@ -36,14 +36,14 @@ export function WorkspaceSecretsSection({ workspaceId }) {
|
|
|
36
36
|
return /*#__PURE__*/ _jsxs(RelativeTimeProvider, {
|
|
37
37
|
children: [
|
|
38
38
|
/*#__PURE__*/ _jsxs("section", {
|
|
39
|
-
className: "flex flex-col gap-
|
|
39
|
+
className: "flex flex-col gap-group",
|
|
40
40
|
"aria-label": "Secrets",
|
|
41
41
|
children: [
|
|
42
42
|
/*#__PURE__*/ _jsxs("div", {
|
|
43
|
-
className: "flex items-start justify-between gap-
|
|
43
|
+
className: "flex items-start justify-between gap-group",
|
|
44
44
|
children: [
|
|
45
45
|
/*#__PURE__*/ _jsxs("div", {
|
|
46
|
-
className: "flex flex-col gap-
|
|
46
|
+
className: "flex flex-col gap-tight",
|
|
47
47
|
children: [
|
|
48
48
|
/*#__PURE__*/ _jsx(Header, {
|
|
49
49
|
variant: "h3",
|
|
@@ -69,14 +69,14 @@ export function WorkspaceSecretsSection({ workspaceId }) {
|
|
|
69
69
|
label: "Loading secrets"
|
|
70
70
|
}) : null,
|
|
71
71
|
secretsQuery.isError && secretsQuery.data === undefined ? /*#__PURE__*/ _jsx(StoreSurface, {
|
|
72
|
-
className: "px-
|
|
72
|
+
className: "px-row",
|
|
73
73
|
children: /*#__PURE__*/ _jsx(QueryLoadError, {
|
|
74
74
|
query: secretsQuery,
|
|
75
75
|
subject: "secrets"
|
|
76
76
|
})
|
|
77
77
|
}) : null,
|
|
78
78
|
secretsQuery.data !== undefined && secrets.length === 0 ? /*#__PURE__*/ _jsx(StoreSurface, {
|
|
79
|
-
className: "px-
|
|
79
|
+
className: "px-row",
|
|
80
80
|
children: /*#__PURE__*/ _jsx(EmptyState, {
|
|
81
81
|
icon: "keyLine",
|
|
82
82
|
title: "No secrets yet",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/workspace-secrets-section.tsx"],"sourcesContent":["import {QueryLoadError} from '@shipfox/client-ui';\nimport {Button, IconButton} from '@shipfox/react-ui/button';\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 {Modal, ModalContent, ModalHeader, ModalTitle} from '@shipfox/react-ui/modal';\nimport {RelativeTime, RelativeTimeProvider} from '@shipfox/react-ui/relative-time';\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@shipfox/react-ui/table';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Code, Header, Text} from '@shipfox/react-ui/typography';\nimport {useMemo, useState} from 'react';\nimport {type SecretMetadata, workspaceStoreScope} from '#core/store.js';\nimport {useDeleteSecretMutation, useSecretsQuery} from '#hooks/api/secrets.js';\nimport {copyKeyName} from './copy-key.js';\nimport {DeleteEntryDialog} from './delete-entry-dialog.js';\nimport {secretsErrorToFormError} from './form-errors.js';\nimport {SecretForm} from './secret-form.js';\nimport {StoreRowsSkeleton, StoreSurface} from './store-section-shell.js';\n\nconst SECRETS_DESCRIPTION =\n 'Encrypted, write-only values for sensitive data like API keys, tokens, and passwords.';\nconst EMPTY_SECRETS_DESCRIPTION =\n 'Create a secret to store sensitive values like API keys, tokens, and passwords.';\n\ntype FormState = {mode: 'create'} | {mode: 'edit'; key: string} | null;\n\nexport function WorkspaceSecretsSection({workspaceId}: {workspaceId: string}) {\n const secretsQuery = useSecretsQuery(workspaceId);\n const deleteSecret = useDeleteSecretMutation();\n const [formState, setFormState] = useState<FormState>(null);\n const [deleteKey, setDeleteKey] = useState<string | null>(null);\n const [deleteError, setDeleteError] = useState<string | undefined>();\n\n const secrets = useMemo(\n () => [...(secretsQuery.data ?? [])].sort((a, b) => a.key.localeCompare(b.key)),\n [secretsQuery.data],\n );\n\n function closeDelete() {\n setDeleteKey(null);\n setDeleteError(undefined);\n }\n\n return (\n <RelativeTimeProvider>\n <section className=\"flex flex-col gap-16\" aria-label=\"Secrets\">\n <div className=\"flex items-start justify-between gap-16\">\n <div className=\"flex flex-col gap-4\">\n <Header variant=\"h3\">Secrets</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n {SECRETS_DESCRIPTION}\n </Text>\n </div>\n <Button size=\"sm\" onClick={() => setFormState({mode: 'create'})}>\n Create secret\n </Button>\n </div>\n\n {secretsQuery.isPending ? <StoreRowsSkeleton label=\"Loading secrets\" /> : null}\n\n {secretsQuery.isError && secretsQuery.data === undefined ? (\n <StoreSurface className=\"px-16\">\n <QueryLoadError query={secretsQuery} subject=\"secrets\" />\n </StoreSurface>\n ) : null}\n\n {secretsQuery.data !== undefined && secrets.length === 0 ? (\n <StoreSurface className=\"px-16\">\n <EmptyState\n icon=\"keyLine\"\n title=\"No secrets yet\"\n description={EMPTY_SECRETS_DESCRIPTION}\n action={\n <Button size=\"sm\" onClick={() => setFormState({mode: 'create'})}>\n Create secret\n </Button>\n }\n />\n </StoreSurface>\n ) : null}\n\n {secrets.length > 0 ? (\n <StoreSurface>\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>Name</TableHead>\n <TableHead>Value</TableHead>\n <TableHead>Last edited</TableHead>\n <TableHead className=\"w-40 text-right\">\n <span className=\"sr-only\">Actions</span>\n </TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {secrets.map((secret) => (\n <SecretRow\n key={secret.key}\n secret={secret}\n onEdit={() => setFormState({mode: 'edit', key: secret.key})}\n onDelete={() => setDeleteKey(secret.key)}\n />\n ))}\n </TableBody>\n </Table>\n </StoreSurface>\n ) : null}\n </section>\n\n <Modal\n open={formState !== null}\n onOpenChange={(open) => {\n if (!open) setFormState(null);\n }}\n >\n <ModalContent>\n <ModalHeader>\n <ModalTitle>\n {formState?.mode === 'edit' ? 'Update secret' : 'Create secret'}\n </ModalTitle>\n </ModalHeader>\n {formState ? (\n <SecretForm\n workspaceId={workspaceId}\n mode={formState.mode}\n existingKey={formState.mode === 'edit' ? formState.key : undefined}\n reservedKeys={secrets.map((secret) => secret.key)}\n onSaved={() => {\n const wasEdit = formState.mode === 'edit';\n setFormState(null);\n toast.success(wasEdit ? 'Secret updated' : 'Secret created');\n }}\n onCancel={() => setFormState(null)}\n />\n ) : null}\n </ModalContent>\n </Modal>\n\n <DeleteEntryDialog\n open={deleteKey !== null}\n onOpenChange={(open) => {\n if (!open) closeDelete();\n }}\n entryKey={deleteKey ?? ''}\n isLoading={deleteSecret.isPending}\n errorMessage={deleteError}\n onConfirm={async () => {\n if (deleteKey === null) return;\n setDeleteError(undefined);\n try {\n await deleteSecret.mutateAsync({\n workspaceId,\n key: deleteKey,\n scope: workspaceStoreScope,\n });\n toast.success('Secret deleted');\n closeDelete();\n } catch (error) {\n setDeleteError(secretsErrorToFormError(error).message);\n }\n }}\n />\n </RelativeTimeProvider>\n );\n}\n\nfunction SecretRow({\n secret,\n onEdit,\n onDelete,\n}: {\n secret: SecretMetadata;\n onEdit: () => void;\n onDelete: () => void;\n}) {\n return (\n <TableRow>\n <TableCell>\n <button\n type=\"button\"\n className=\"inline-flex min-w-0 cursor-pointer rounded-4 border-none bg-transparent p-0 text-left text-foreground-neutral-base outline-none transition-colors hover:text-foreground-highlight-interactive focus-visible:shadow-border-interactive-with-active\"\n aria-label={`Copy secret name ${secret.key}`}\n onClick={() => void copyKeyName(secret.key)}\n >\n <Code as=\"span\" variant=\"paragraph\" className=\"truncate\">\n {secret.key}\n </Code>\n </button>\n </TableCell>\n <TableCell>\n <span\n role=\"img\"\n aria-label=\"Value hidden\"\n className=\"font-code text-foreground-neutral-muted\"\n >\n ••••••••\n </span>\n </TableCell>\n <TableCell className=\"text-foreground-neutral-muted\">\n <RelativeTime value={secret.updatedAt} />\n </TableCell>\n <TableCell className=\"text-right\">\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <IconButton\n size=\"sm\"\n variant=\"transparent\"\n icon=\"more2Line\"\n aria-label={`Actions for ${secret.key}`}\n />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem icon=\"editLine\" onSelect={onEdit}>\n Edit value\n </DropdownMenuItem>\n <DropdownMenuItem icon=\"deleteBinLine\" onSelect={onDelete}>\n Delete\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </TableCell>\n </TableRow>\n );\n}\n"],"names":["QueryLoadError","Button","IconButton","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuTrigger","EmptyState","Modal","ModalContent","ModalHeader","ModalTitle","RelativeTime","RelativeTimeProvider","Table","TableBody","TableCell","TableHead","TableHeader","TableRow","toast","Code","Header","Text","useMemo","useState","workspaceStoreScope","useDeleteSecretMutation","useSecretsQuery","copyKeyName","DeleteEntryDialog","secretsErrorToFormError","SecretForm","StoreRowsSkeleton","StoreSurface","SECRETS_DESCRIPTION","EMPTY_SECRETS_DESCRIPTION","WorkspaceSecretsSection","workspaceId","secretsQuery","deleteSecret","formState","setFormState","deleteKey","setDeleteKey","deleteError","setDeleteError","secrets","data","sort","a","b","key","localeCompare","closeDelete","undefined","section","className","aria-label","div","variant","size","onClick","mode","isPending","label","isError","query","subject","length","icon","title","description","action","span","map","secret","SecretRow","onEdit","onDelete","open","onOpenChange","existingKey","reservedKeys","onSaved","wasEdit","success","onCancel","entryKey","isLoading","errorMessage","onConfirm","mutateAsync","scope","error","message","button","type","as","role","value","updatedAt","asChild","align","onSelect"],"mappings":";AAAA,SAAQA,cAAc,QAAO,qBAAqB;AAClD,SAAQC,MAAM,EAAEC,UAAU,QAAO,2BAA2B;AAC5D,SACEC,YAAY,EACZC,mBAAmB,EACnBC,gBAAgB,EAChBC,mBAAmB,QACd,kCAAkC;AACzC,SAAQC,UAAU,QAAO,gCAAgC;AACzD,SAAQC,KAAK,EAAEC,YAAY,EAAEC,WAAW,EAAEC,UAAU,QAAO,0BAA0B;AACrF,SAAQC,YAAY,EAAEC,oBAAoB,QAAO,kCAAkC;AACnF,SACEC,KAAK,EACLC,SAAS,EACTC,SAAS,EACTC,SAAS,EACTC,WAAW,EACXC,QAAQ,QACH,0BAA0B;AACjC,SAAQC,KAAK,QAAO,0BAA0B;AAC9C,SAAQC,IAAI,EAAEC,MAAM,EAAEC,IAAI,QAAO,+BAA+B;AAChE,SAAQC,OAAO,EAAEC,QAAQ,QAAO,QAAQ;AACxC,SAA6BC,mBAAmB,QAAO,iBAAiB;AACxE,SAAQC,uBAAuB,EAAEC,eAAe,QAAO,wBAAwB;AAC/E,SAAQC,WAAW,QAAO,gBAAgB;AAC1C,SAAQC,iBAAiB,QAAO,2BAA2B;AAC3D,SAAQC,uBAAuB,QAAO,mBAAmB;AACzD,SAAQC,UAAU,QAAO,mBAAmB;AAC5C,SAAQC,iBAAiB,EAAEC,YAAY,QAAO,2BAA2B;AAEzE,MAAMC,sBACJ;AACF,MAAMC,4BACJ;AAIF,OAAO,SAASC,wBAAwB,EAACC,WAAW,EAAwB;IAC1E,MAAMC,eAAeX,gBAAgBU;IACrC,MAAME,eAAeb;IACrB,MAAM,CAACc,WAAWC,aAAa,GAAGjB,SAAoB;IACtD,MAAM,CAACkB,WAAWC,aAAa,GAAGnB,SAAwB;IAC1D,MAAM,CAACoB,aAAaC,eAAe,GAAGrB;IAEtC,MAAMsB,UAAUvB,QACd,IAAM;eAAKe,aAAaS,IAAI,IAAI,EAAE;SAAE,CAACC,IAAI,CAAC,CAACC,GAAGC,IAAMD,EAAEE,GAAG,CAACC,aAAa,CAACF,EAAEC,GAAG,IAC7E;QAACb,aAAaS,IAAI;KAAC;IAGrB,SAASM;QACPV,aAAa;QACbE,eAAeS;IACjB;IAEA,qBACE,MAAC1C;;0BACC,MAAC2C;gBAAQC,WAAU;gBAAuBC,cAAW;;kCACnD,MAACC;wBAAIF,WAAU;;0CACb,MAACE;gCAAIF,WAAU;;kDACb,KAACnC;wCAAOsC,SAAQ;kDAAK;;kDACrB,KAACrC;wCAAKsC,MAAK;wCAAKJ,WAAU;kDACvBtB;;;;0CAGL,KAAClC;gCAAO4D,MAAK;gCAAKC,SAAS,IAAMpB,aAAa;wCAACqB,MAAM;oCAAQ;0CAAI;;;;oBAKlExB,aAAayB,SAAS,iBAAG,KAAC/B;wBAAkBgC,OAAM;yBAAuB;oBAEzE1B,aAAa2B,OAAO,IAAI3B,aAAaS,IAAI,KAAKO,0BAC7C,KAACrB;wBAAauB,WAAU;kCACtB,cAAA,KAACzD;4BAAemE,OAAO5B;4BAAc6B,SAAQ;;yBAE7C;oBAEH7B,aAAaS,IAAI,KAAKO,aAAaR,QAAQsB,MAAM,KAAK,kBACrD,KAACnC;wBAAauB,WAAU;kCACtB,cAAA,KAAClD;4BACC+D,MAAK;4BACLC,OAAM;4BACNC,aAAapC;4BACbqC,sBACE,KAACxE;gCAAO4D,MAAK;gCAAKC,SAAS,IAAMpB,aAAa;wCAACqB,MAAM;oCAAQ;0CAAI;;;yBAMrE;oBAEHhB,QAAQsB,MAAM,GAAG,kBAChB,KAACnC;kCACC,cAAA,MAACpB;;8CACC,KAACI;8CACC,cAAA,MAACC;;0DACC,KAACF;0DAAU;;0DACX,KAACA;0DAAU;;0DACX,KAACA;0DAAU;;0DACX,KAACA;gDAAUwC,WAAU;0DACnB,cAAA,KAACiB;oDAAKjB,WAAU;8DAAU;;;;;;8CAIhC,KAAC1C;8CACEgC,QAAQ4B,GAAG,CAAC,CAACC,uBACZ,KAACC;4CAECD,QAAQA;4CACRE,QAAQ,IAAMpC,aAAa;oDAACqB,MAAM;oDAAQX,KAAKwB,OAAOxB,GAAG;gDAAA;4CACzD2B,UAAU,IAAMnC,aAAagC,OAAOxB,GAAG;2CAHlCwB,OAAOxB,GAAG;;;;yBASvB;;;0BAGN,KAAC5C;gBACCwE,MAAMvC,cAAc;gBACpBwC,cAAc,CAACD;oBACb,IAAI,CAACA,MAAMtC,aAAa;gBAC1B;0BAEA,cAAA,MAACjC;;sCACC,KAACC;sCACC,cAAA,KAACC;0CACE8B,WAAWsB,SAAS,SAAS,kBAAkB;;;wBAGnDtB,0BACC,KAACT;4BACCM,aAAaA;4BACbyB,MAAMtB,UAAUsB,IAAI;4BACpBmB,aAAazC,UAAUsB,IAAI,KAAK,SAAStB,UAAUW,GAAG,GAAGG;4BACzD4B,cAAcpC,QAAQ4B,GAAG,CAAC,CAACC,SAAWA,OAAOxB,GAAG;4BAChDgC,SAAS;gCACP,MAAMC,UAAU5C,UAAUsB,IAAI,KAAK;gCACnCrB,aAAa;gCACbtB,MAAMkE,OAAO,CAACD,UAAU,mBAAmB;4BAC7C;4BACAE,UAAU,IAAM7C,aAAa;6BAE7B;;;;0BAIR,KAACZ;gBACCkD,MAAMrC,cAAc;gBACpBsC,cAAc,CAACD;oBACb,IAAI,CAACA,MAAM1B;gBACb;gBACAkC,UAAU7C,aAAa;gBACvB8C,WAAWjD,aAAawB,SAAS;gBACjC0B,cAAc7C;gBACd8C,WAAW;oBACT,IAAIhD,cAAc,MAAM;oBACxBG,eAAeS;oBACf,IAAI;wBACF,MAAMf,aAAaoD,WAAW,CAAC;4BAC7BtD;4BACAc,KAAKT;4BACLkD,OAAOnE;wBACT;wBACAN,MAAMkE,OAAO,CAAC;wBACdhC;oBACF,EAAE,OAAOwC,OAAO;wBACdhD,eAAef,wBAAwB+D,OAAOC,OAAO;oBACvD;gBACF;;;;AAIR;AAEA,SAASlB,UAAU,EACjBD,MAAM,EACNE,MAAM,EACNC,QAAQ,EAKT;IACC,qBACE,MAAC5D;;0BACC,KAACH;0BACC,cAAA,KAACgF;oBACCC,MAAK;oBACLxC,WAAU;oBACVC,cAAY,CAAC,iBAAiB,EAAEkB,OAAOxB,GAAG,EAAE;oBAC5CU,SAAS,IAAM,KAAKjC,YAAY+C,OAAOxB,GAAG;8BAE1C,cAAA,KAAC/B;wBAAK6E,IAAG;wBAAOtC,SAAQ;wBAAYH,WAAU;kCAC3CmB,OAAOxB,GAAG;;;;0BAIjB,KAACpC;0BACC,cAAA,KAAC0D;oBACCyB,MAAK;oBACLzC,cAAW;oBACXD,WAAU;8BACX;;;0BAIH,KAACzC;gBAAUyC,WAAU;0BACnB,cAAA,KAAC7C;oBAAawF,OAAOxB,OAAOyB,SAAS;;;0BAEvC,KAACrF;gBAAUyC,WAAU;0BACnB,cAAA,MAACtD;;sCACC,KAACG;4BAAoBgG,OAAO;sCAC1B,cAAA,KAACpG;gCACC2D,MAAK;gCACLD,SAAQ;gCACRU,MAAK;gCACLZ,cAAY,CAAC,YAAY,EAAEkB,OAAOxB,GAAG,EAAE;;;sCAG3C,MAAChD;4BAAoBmG,OAAM;;8CACzB,KAAClG;oCAAiBiE,MAAK;oCAAWkC,UAAU1B;8CAAQ;;8CAGpD,KAACzE;oCAAiBiE,MAAK;oCAAgBkC,UAAUzB;8CAAU;;;;;;;;;AAQvE"}
|
|
1
|
+
{"version":3,"sources":["../../src/components/workspace-secrets-section.tsx"],"sourcesContent":["import {QueryLoadError} from '@shipfox/client-ui';\nimport {Button, IconButton} from '@shipfox/react-ui/button';\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 {Modal, ModalContent, ModalHeader, ModalTitle} from '@shipfox/react-ui/modal';\nimport {RelativeTime, RelativeTimeProvider} from '@shipfox/react-ui/relative-time';\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@shipfox/react-ui/table';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Code, Header, Text} from '@shipfox/react-ui/typography';\nimport {useMemo, useState} from 'react';\nimport {type SecretMetadata, workspaceStoreScope} from '#core/store.js';\nimport {useDeleteSecretMutation, useSecretsQuery} from '#hooks/api/secrets.js';\nimport {copyKeyName} from './copy-key.js';\nimport {DeleteEntryDialog} from './delete-entry-dialog.js';\nimport {secretsErrorToFormError} from './form-errors.js';\nimport {SecretForm} from './secret-form.js';\nimport {StoreRowsSkeleton, StoreSurface} from './store-section-shell.js';\n\nconst SECRETS_DESCRIPTION =\n 'Encrypted, write-only values for sensitive data like API keys, tokens, and passwords.';\nconst EMPTY_SECRETS_DESCRIPTION =\n 'Create a secret to store sensitive values like API keys, tokens, and passwords.';\n\ntype FormState = {mode: 'create'} | {mode: 'edit'; key: string} | null;\n\nexport function WorkspaceSecretsSection({workspaceId}: {workspaceId: string}) {\n const secretsQuery = useSecretsQuery(workspaceId);\n const deleteSecret = useDeleteSecretMutation();\n const [formState, setFormState] = useState<FormState>(null);\n const [deleteKey, setDeleteKey] = useState<string | null>(null);\n const [deleteError, setDeleteError] = useState<string | undefined>();\n\n const secrets = useMemo(\n () => [...(secretsQuery.data ?? [])].sort((a, b) => a.key.localeCompare(b.key)),\n [secretsQuery.data],\n );\n\n function closeDelete() {\n setDeleteKey(null);\n setDeleteError(undefined);\n }\n\n return (\n <RelativeTimeProvider>\n <section className=\"flex flex-col gap-group\" aria-label=\"Secrets\">\n <div className=\"flex items-start justify-between gap-group\">\n <div className=\"flex flex-col gap-tight\">\n <Header variant=\"h3\">Secrets</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n {SECRETS_DESCRIPTION}\n </Text>\n </div>\n <Button size=\"sm\" onClick={() => setFormState({mode: 'create'})}>\n Create secret\n </Button>\n </div>\n\n {secretsQuery.isPending ? <StoreRowsSkeleton label=\"Loading secrets\" /> : null}\n\n {secretsQuery.isError && secretsQuery.data === undefined ? (\n <StoreSurface className=\"px-row\">\n <QueryLoadError query={secretsQuery} subject=\"secrets\" />\n </StoreSurface>\n ) : null}\n\n {secretsQuery.data !== undefined && secrets.length === 0 ? (\n <StoreSurface className=\"px-row\">\n <EmptyState\n icon=\"keyLine\"\n title=\"No secrets yet\"\n description={EMPTY_SECRETS_DESCRIPTION}\n action={\n <Button size=\"sm\" onClick={() => setFormState({mode: 'create'})}>\n Create secret\n </Button>\n }\n />\n </StoreSurface>\n ) : null}\n\n {secrets.length > 0 ? (\n <StoreSurface>\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>Name</TableHead>\n <TableHead>Value</TableHead>\n <TableHead>Last edited</TableHead>\n <TableHead className=\"w-40 text-right\">\n <span className=\"sr-only\">Actions</span>\n </TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {secrets.map((secret) => (\n <SecretRow\n key={secret.key}\n secret={secret}\n onEdit={() => setFormState({mode: 'edit', key: secret.key})}\n onDelete={() => setDeleteKey(secret.key)}\n />\n ))}\n </TableBody>\n </Table>\n </StoreSurface>\n ) : null}\n </section>\n\n <Modal\n open={formState !== null}\n onOpenChange={(open) => {\n if (!open) setFormState(null);\n }}\n >\n <ModalContent>\n <ModalHeader>\n <ModalTitle>\n {formState?.mode === 'edit' ? 'Update secret' : 'Create secret'}\n </ModalTitle>\n </ModalHeader>\n {formState ? (\n <SecretForm\n workspaceId={workspaceId}\n mode={formState.mode}\n existingKey={formState.mode === 'edit' ? formState.key : undefined}\n reservedKeys={secrets.map((secret) => secret.key)}\n onSaved={() => {\n const wasEdit = formState.mode === 'edit';\n setFormState(null);\n toast.success(wasEdit ? 'Secret updated' : 'Secret created');\n }}\n onCancel={() => setFormState(null)}\n />\n ) : null}\n </ModalContent>\n </Modal>\n\n <DeleteEntryDialog\n open={deleteKey !== null}\n onOpenChange={(open) => {\n if (!open) closeDelete();\n }}\n entryKey={deleteKey ?? ''}\n isLoading={deleteSecret.isPending}\n errorMessage={deleteError}\n onConfirm={async () => {\n if (deleteKey === null) return;\n setDeleteError(undefined);\n try {\n await deleteSecret.mutateAsync({\n workspaceId,\n key: deleteKey,\n scope: workspaceStoreScope,\n });\n toast.success('Secret deleted');\n closeDelete();\n } catch (error) {\n setDeleteError(secretsErrorToFormError(error).message);\n }\n }}\n />\n </RelativeTimeProvider>\n );\n}\n\nfunction SecretRow({\n secret,\n onEdit,\n onDelete,\n}: {\n secret: SecretMetadata;\n onEdit: () => void;\n onDelete: () => void;\n}) {\n return (\n <TableRow>\n <TableCell>\n <button\n type=\"button\"\n className=\"inline-flex min-w-0 cursor-pointer rounded-4 border-none bg-transparent p-0 text-left text-foreground-neutral-base outline-none transition-colors hover:text-foreground-highlight-interactive focus-visible:shadow-border-interactive-with-active\"\n aria-label={`Copy secret name ${secret.key}`}\n onClick={() => void copyKeyName(secret.key)}\n >\n <Code as=\"span\" variant=\"paragraph\" className=\"truncate\">\n {secret.key}\n </Code>\n </button>\n </TableCell>\n <TableCell>\n <span\n role=\"img\"\n aria-label=\"Value hidden\"\n className=\"font-code text-foreground-neutral-muted\"\n >\n ••••••••\n </span>\n </TableCell>\n <TableCell className=\"text-foreground-neutral-muted\">\n <RelativeTime value={secret.updatedAt} />\n </TableCell>\n <TableCell className=\"text-right\">\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <IconButton\n size=\"sm\"\n variant=\"transparent\"\n icon=\"more2Line\"\n aria-label={`Actions for ${secret.key}`}\n />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem icon=\"editLine\" onSelect={onEdit}>\n Edit value\n </DropdownMenuItem>\n <DropdownMenuItem icon=\"deleteBinLine\" onSelect={onDelete}>\n Delete\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </TableCell>\n </TableRow>\n );\n}\n"],"names":["QueryLoadError","Button","IconButton","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuTrigger","EmptyState","Modal","ModalContent","ModalHeader","ModalTitle","RelativeTime","RelativeTimeProvider","Table","TableBody","TableCell","TableHead","TableHeader","TableRow","toast","Code","Header","Text","useMemo","useState","workspaceStoreScope","useDeleteSecretMutation","useSecretsQuery","copyKeyName","DeleteEntryDialog","secretsErrorToFormError","SecretForm","StoreRowsSkeleton","StoreSurface","SECRETS_DESCRIPTION","EMPTY_SECRETS_DESCRIPTION","WorkspaceSecretsSection","workspaceId","secretsQuery","deleteSecret","formState","setFormState","deleteKey","setDeleteKey","deleteError","setDeleteError","secrets","data","sort","a","b","key","localeCompare","closeDelete","undefined","section","className","aria-label","div","variant","size","onClick","mode","isPending","label","isError","query","subject","length","icon","title","description","action","span","map","secret","SecretRow","onEdit","onDelete","open","onOpenChange","existingKey","reservedKeys","onSaved","wasEdit","success","onCancel","entryKey","isLoading","errorMessage","onConfirm","mutateAsync","scope","error","message","button","type","as","role","value","updatedAt","asChild","align","onSelect"],"mappings":"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"}
|
|
@@ -36,14 +36,14 @@ export function WorkspaceVariablesSection({ workspaceId }) {
|
|
|
36
36
|
return /*#__PURE__*/ _jsxs(RelativeTimeProvider, {
|
|
37
37
|
children: [
|
|
38
38
|
/*#__PURE__*/ _jsxs("section", {
|
|
39
|
-
className: "flex flex-col gap-
|
|
39
|
+
className: "flex flex-col gap-group",
|
|
40
40
|
"aria-label": "Variables",
|
|
41
41
|
children: [
|
|
42
42
|
/*#__PURE__*/ _jsxs("div", {
|
|
43
|
-
className: "flex items-start justify-between gap-
|
|
43
|
+
className: "flex items-start justify-between gap-group",
|
|
44
44
|
children: [
|
|
45
45
|
/*#__PURE__*/ _jsxs("div", {
|
|
46
|
-
className: "flex flex-col gap-
|
|
46
|
+
className: "flex flex-col gap-tight",
|
|
47
47
|
children: [
|
|
48
48
|
/*#__PURE__*/ _jsx(Header, {
|
|
49
49
|
variant: "h3",
|
|
@@ -69,14 +69,14 @@ export function WorkspaceVariablesSection({ workspaceId }) {
|
|
|
69
69
|
label: "Loading variables"
|
|
70
70
|
}) : null,
|
|
71
71
|
variablesQuery.isError && variablesQuery.data === undefined ? /*#__PURE__*/ _jsx(StoreSurface, {
|
|
72
|
-
className: "px-
|
|
72
|
+
className: "px-row",
|
|
73
73
|
children: /*#__PURE__*/ _jsx(QueryLoadError, {
|
|
74
74
|
query: variablesQuery,
|
|
75
75
|
subject: "variables"
|
|
76
76
|
})
|
|
77
77
|
}) : null,
|
|
78
78
|
variablesQuery.data !== undefined && variables.length === 0 ? /*#__PURE__*/ _jsx(StoreSurface, {
|
|
79
|
-
className: "px-
|
|
79
|
+
className: "px-row",
|
|
80
80
|
children: /*#__PURE__*/ _jsx(EmptyState, {
|
|
81
81
|
icon: "bracesLine",
|
|
82
82
|
title: "No variables yet",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/workspace-variables-section.tsx"],"sourcesContent":["import {QueryLoadError} from '@shipfox/client-ui';\nimport {Button, IconButton} from '@shipfox/react-ui/button';\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 {Modal, ModalContent, ModalHeader, ModalTitle} from '@shipfox/react-ui/modal';\nimport {RelativeTime, RelativeTimeProvider} from '@shipfox/react-ui/relative-time';\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@shipfox/react-ui/table';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Code, Header, Text} from '@shipfox/react-ui/typography';\nimport {useMemo, useState} from 'react';\nimport {type VariablePreview, workspaceStoreScope} from '#core/store.js';\nimport {useDeleteVariableMutation, useVariablesQuery} from '#hooks/api/variables.js';\nimport {copyKeyName} from './copy-key.js';\nimport {DeleteEntryDialog} from './delete-entry-dialog.js';\nimport {secretsErrorToFormError} from './form-errors.js';\nimport {StoreRowsSkeleton, StoreSurface} from './store-section-shell.js';\nimport {VariableForm} from './variable-form.js';\n\nconst VARIABLES_DESCRIPTION =\n 'Plaintext configuration values for non-sensitive data like regions, flags, and log levels.';\nconst EMPTY_VARIABLES_DESCRIPTION =\n 'Create a variable to store non-sensitive configuration like regions, flags, and log levels.';\n\ntype FormState = {mode: 'create'} | {mode: 'edit'; variable: VariablePreview} | null;\n\nexport function WorkspaceVariablesSection({workspaceId}: {workspaceId: string}) {\n const variablesQuery = useVariablesQuery(workspaceId);\n const deleteVariable = useDeleteVariableMutation();\n const [formState, setFormState] = useState<FormState>(null);\n const [deleteKey, setDeleteKey] = useState<string | null>(null);\n const [deleteError, setDeleteError] = useState<string | undefined>();\n\n const variables = useMemo(\n () => [...(variablesQuery.data ?? [])].sort((a, b) => a.key.localeCompare(b.key)),\n [variablesQuery.data],\n );\n\n function closeDelete() {\n setDeleteKey(null);\n setDeleteError(undefined);\n }\n\n return (\n <RelativeTimeProvider>\n <section className=\"flex flex-col gap-16\" aria-label=\"Variables\">\n <div className=\"flex items-start justify-between gap-16\">\n <div className=\"flex flex-col gap-4\">\n <Header variant=\"h3\">Variables</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n {VARIABLES_DESCRIPTION}\n </Text>\n </div>\n <Button size=\"sm\" onClick={() => setFormState({mode: 'create'})}>\n Create variable\n </Button>\n </div>\n\n {variablesQuery.isPending ? <StoreRowsSkeleton label=\"Loading variables\" /> : null}\n\n {variablesQuery.isError && variablesQuery.data === undefined ? (\n <StoreSurface className=\"px-16\">\n <QueryLoadError query={variablesQuery} subject=\"variables\" />\n </StoreSurface>\n ) : null}\n\n {variablesQuery.data !== undefined && variables.length === 0 ? (\n <StoreSurface className=\"px-16\">\n <EmptyState\n icon=\"bracesLine\"\n title=\"No variables yet\"\n description={EMPTY_VARIABLES_DESCRIPTION}\n action={\n <Button size=\"sm\" onClick={() => setFormState({mode: 'create'})}>\n Create variable\n </Button>\n }\n />\n </StoreSurface>\n ) : null}\n\n {variables.length > 0 ? (\n <StoreSurface>\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>Name</TableHead>\n <TableHead>Value</TableHead>\n <TableHead>Last edited</TableHead>\n <TableHead className=\"w-40 text-right\">\n <span className=\"sr-only\">Actions</span>\n </TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {variables.map((variable) => (\n <VariableRow\n key={variable.key}\n variable={variable}\n onEdit={() => setFormState({mode: 'edit', variable})}\n onDelete={() => setDeleteKey(variable.key)}\n />\n ))}\n </TableBody>\n </Table>\n </StoreSurface>\n ) : null}\n </section>\n\n <Modal\n open={formState !== null}\n onOpenChange={(open) => {\n if (!open) setFormState(null);\n }}\n >\n <ModalContent>\n <ModalHeader>\n <ModalTitle>\n {formState?.mode === 'edit' ? 'Update variable' : 'Create variable'}\n </ModalTitle>\n </ModalHeader>\n {formState ? (\n <VariableForm\n workspaceId={workspaceId}\n mode={formState.mode}\n existingKey={formState.mode === 'edit' ? formState.variable.key : undefined}\n existingValue={formState.mode === 'edit' ? formState.variable.value : undefined}\n existingValueTruncated={\n formState.mode === 'edit' ? formState.variable.valueTruncated : undefined\n }\n reservedKeys={variables.map((variable) => variable.key)}\n onSaved={() => {\n const wasEdit = formState.mode === 'edit';\n setFormState(null);\n toast.success(wasEdit ? 'Variable updated' : 'Variable created');\n }}\n onCancel={() => setFormState(null)}\n />\n ) : null}\n </ModalContent>\n </Modal>\n\n <DeleteEntryDialog\n open={deleteKey !== null}\n onOpenChange={(open) => {\n if (!open) closeDelete();\n }}\n entryKey={deleteKey ?? ''}\n isLoading={deleteVariable.isPending}\n errorMessage={deleteError}\n onConfirm={async () => {\n if (deleteKey === null) return;\n setDeleteError(undefined);\n try {\n await deleteVariable.mutateAsync({\n workspaceId,\n key: deleteKey,\n scope: workspaceStoreScope,\n });\n toast.success('Variable deleted');\n closeDelete();\n } catch (error) {\n setDeleteError(secretsErrorToFormError(error).message);\n }\n }}\n />\n </RelativeTimeProvider>\n );\n}\n\nfunction VariableRow({\n variable,\n onEdit,\n onDelete,\n}: {\n variable: VariablePreview;\n onEdit: () => void;\n onDelete: () => void;\n}) {\n return (\n <TableRow>\n <TableCell>\n <button\n type=\"button\"\n className=\"inline-flex min-w-0 cursor-pointer rounded-4 border-none bg-transparent p-0 text-left text-foreground-neutral-base outline-none transition-colors hover:text-foreground-highlight-interactive focus-visible:shadow-border-interactive-with-active\"\n aria-label={`Copy variable name ${variable.key}`}\n onClick={() => void copyKeyName(variable.key)}\n >\n <Code as=\"span\" variant=\"paragraph\" className=\"truncate\">\n {variable.key}\n </Code>\n </button>\n </TableCell>\n <TableCell>\n <span\n title={variable.value}\n className=\"block max-w-[280px] truncate font-code text-foreground-neutral-base\"\n >\n {variable.value === '' ? (\n <span className=\"text-foreground-neutral-muted\">(empty)</span>\n ) : (\n variable.value\n )}\n </span>\n </TableCell>\n <TableCell className=\"text-foreground-neutral-muted\">\n <RelativeTime value={variable.updatedAt} />\n </TableCell>\n <TableCell className=\"text-right\">\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <IconButton\n size=\"sm\"\n variant=\"transparent\"\n icon=\"more2Line\"\n aria-label={`Actions for ${variable.key}`}\n />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem icon=\"editLine\" onSelect={onEdit}>\n Edit value\n </DropdownMenuItem>\n <DropdownMenuItem icon=\"deleteBinLine\" onSelect={onDelete}>\n Delete\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </TableCell>\n </TableRow>\n );\n}\n"],"names":["QueryLoadError","Button","IconButton","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuTrigger","EmptyState","Modal","ModalContent","ModalHeader","ModalTitle","RelativeTime","RelativeTimeProvider","Table","TableBody","TableCell","TableHead","TableHeader","TableRow","toast","Code","Header","Text","useMemo","useState","workspaceStoreScope","useDeleteVariableMutation","useVariablesQuery","copyKeyName","DeleteEntryDialog","secretsErrorToFormError","StoreRowsSkeleton","StoreSurface","VariableForm","VARIABLES_DESCRIPTION","EMPTY_VARIABLES_DESCRIPTION","WorkspaceVariablesSection","workspaceId","variablesQuery","deleteVariable","formState","setFormState","deleteKey","setDeleteKey","deleteError","setDeleteError","variables","data","sort","a","b","key","localeCompare","closeDelete","undefined","section","className","aria-label","div","variant","size","onClick","mode","isPending","label","isError","query","subject","length","icon","title","description","action","span","map","variable","VariableRow","onEdit","onDelete","open","onOpenChange","existingKey","existingValue","value","existingValueTruncated","valueTruncated","reservedKeys","onSaved","wasEdit","success","onCancel","entryKey","isLoading","errorMessage","onConfirm","mutateAsync","scope","error","message","button","type","as","updatedAt","asChild","align","onSelect"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/components/workspace-variables-section.tsx"],"sourcesContent":["import {QueryLoadError} from '@shipfox/client-ui';\nimport {Button, IconButton} from '@shipfox/react-ui/button';\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 {Modal, ModalContent, ModalHeader, ModalTitle} from '@shipfox/react-ui/modal';\nimport {RelativeTime, RelativeTimeProvider} from '@shipfox/react-ui/relative-time';\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@shipfox/react-ui/table';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Code, Header, Text} from '@shipfox/react-ui/typography';\nimport {useMemo, useState} from 'react';\nimport {type VariablePreview, workspaceStoreScope} from '#core/store.js';\nimport {useDeleteVariableMutation, useVariablesQuery} from '#hooks/api/variables.js';\nimport {copyKeyName} from './copy-key.js';\nimport {DeleteEntryDialog} from './delete-entry-dialog.js';\nimport {secretsErrorToFormError} from './form-errors.js';\nimport {StoreRowsSkeleton, StoreSurface} from './store-section-shell.js';\nimport {VariableForm} from './variable-form.js';\n\nconst VARIABLES_DESCRIPTION =\n 'Plaintext configuration values for non-sensitive data like regions, flags, and log levels.';\nconst EMPTY_VARIABLES_DESCRIPTION =\n 'Create a variable to store non-sensitive configuration like regions, flags, and log levels.';\n\ntype FormState = {mode: 'create'} | {mode: 'edit'; variable: VariablePreview} | null;\n\nexport function WorkspaceVariablesSection({workspaceId}: {workspaceId: string}) {\n const variablesQuery = useVariablesQuery(workspaceId);\n const deleteVariable = useDeleteVariableMutation();\n const [formState, setFormState] = useState<FormState>(null);\n const [deleteKey, setDeleteKey] = useState<string | null>(null);\n const [deleteError, setDeleteError] = useState<string | undefined>();\n\n const variables = useMemo(\n () => [...(variablesQuery.data ?? [])].sort((a, b) => a.key.localeCompare(b.key)),\n [variablesQuery.data],\n );\n\n function closeDelete() {\n setDeleteKey(null);\n setDeleteError(undefined);\n }\n\n return (\n <RelativeTimeProvider>\n <section className=\"flex flex-col gap-group\" aria-label=\"Variables\">\n <div className=\"flex items-start justify-between gap-group\">\n <div className=\"flex flex-col gap-tight\">\n <Header variant=\"h3\">Variables</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n {VARIABLES_DESCRIPTION}\n </Text>\n </div>\n <Button size=\"sm\" onClick={() => setFormState({mode: 'create'})}>\n Create variable\n </Button>\n </div>\n\n {variablesQuery.isPending ? <StoreRowsSkeleton label=\"Loading variables\" /> : null}\n\n {variablesQuery.isError && variablesQuery.data === undefined ? (\n <StoreSurface className=\"px-row\">\n <QueryLoadError query={variablesQuery} subject=\"variables\" />\n </StoreSurface>\n ) : null}\n\n {variablesQuery.data !== undefined && variables.length === 0 ? (\n <StoreSurface className=\"px-row\">\n <EmptyState\n icon=\"bracesLine\"\n title=\"No variables yet\"\n description={EMPTY_VARIABLES_DESCRIPTION}\n action={\n <Button size=\"sm\" onClick={() => setFormState({mode: 'create'})}>\n Create variable\n </Button>\n }\n />\n </StoreSurface>\n ) : null}\n\n {variables.length > 0 ? (\n <StoreSurface>\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>Name</TableHead>\n <TableHead>Value</TableHead>\n <TableHead>Last edited</TableHead>\n <TableHead className=\"w-40 text-right\">\n <span className=\"sr-only\">Actions</span>\n </TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {variables.map((variable) => (\n <VariableRow\n key={variable.key}\n variable={variable}\n onEdit={() => setFormState({mode: 'edit', variable})}\n onDelete={() => setDeleteKey(variable.key)}\n />\n ))}\n </TableBody>\n </Table>\n </StoreSurface>\n ) : null}\n </section>\n\n <Modal\n open={formState !== null}\n onOpenChange={(open) => {\n if (!open) setFormState(null);\n }}\n >\n <ModalContent>\n <ModalHeader>\n <ModalTitle>\n {formState?.mode === 'edit' ? 'Update variable' : 'Create variable'}\n </ModalTitle>\n </ModalHeader>\n {formState ? (\n <VariableForm\n workspaceId={workspaceId}\n mode={formState.mode}\n existingKey={formState.mode === 'edit' ? formState.variable.key : undefined}\n existingValue={formState.mode === 'edit' ? formState.variable.value : undefined}\n existingValueTruncated={\n formState.mode === 'edit' ? formState.variable.valueTruncated : undefined\n }\n reservedKeys={variables.map((variable) => variable.key)}\n onSaved={() => {\n const wasEdit = formState.mode === 'edit';\n setFormState(null);\n toast.success(wasEdit ? 'Variable updated' : 'Variable created');\n }}\n onCancel={() => setFormState(null)}\n />\n ) : null}\n </ModalContent>\n </Modal>\n\n <DeleteEntryDialog\n open={deleteKey !== null}\n onOpenChange={(open) => {\n if (!open) closeDelete();\n }}\n entryKey={deleteKey ?? ''}\n isLoading={deleteVariable.isPending}\n errorMessage={deleteError}\n onConfirm={async () => {\n if (deleteKey === null) return;\n setDeleteError(undefined);\n try {\n await deleteVariable.mutateAsync({\n workspaceId,\n key: deleteKey,\n scope: workspaceStoreScope,\n });\n toast.success('Variable deleted');\n closeDelete();\n } catch (error) {\n setDeleteError(secretsErrorToFormError(error).message);\n }\n }}\n />\n </RelativeTimeProvider>\n );\n}\n\nfunction VariableRow({\n variable,\n onEdit,\n onDelete,\n}: {\n variable: VariablePreview;\n onEdit: () => void;\n onDelete: () => void;\n}) {\n return (\n <TableRow>\n <TableCell>\n <button\n type=\"button\"\n className=\"inline-flex min-w-0 cursor-pointer rounded-4 border-none bg-transparent p-0 text-left text-foreground-neutral-base outline-none transition-colors hover:text-foreground-highlight-interactive focus-visible:shadow-border-interactive-with-active\"\n aria-label={`Copy variable name ${variable.key}`}\n onClick={() => void copyKeyName(variable.key)}\n >\n <Code as=\"span\" variant=\"paragraph\" className=\"truncate\">\n {variable.key}\n </Code>\n </button>\n </TableCell>\n <TableCell>\n <span\n title={variable.value}\n className=\"block max-w-[280px] truncate font-code text-foreground-neutral-base\"\n >\n {variable.value === '' ? (\n <span className=\"text-foreground-neutral-muted\">(empty)</span>\n ) : (\n variable.value\n )}\n </span>\n </TableCell>\n <TableCell className=\"text-foreground-neutral-muted\">\n <RelativeTime value={variable.updatedAt} />\n </TableCell>\n <TableCell className=\"text-right\">\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <IconButton\n size=\"sm\"\n variant=\"transparent\"\n icon=\"more2Line\"\n aria-label={`Actions for ${variable.key}`}\n />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem icon=\"editLine\" onSelect={onEdit}>\n Edit value\n </DropdownMenuItem>\n <DropdownMenuItem icon=\"deleteBinLine\" onSelect={onDelete}>\n Delete\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </TableCell>\n </TableRow>\n );\n}\n"],"names":["QueryLoadError","Button","IconButton","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuTrigger","EmptyState","Modal","ModalContent","ModalHeader","ModalTitle","RelativeTime","RelativeTimeProvider","Table","TableBody","TableCell","TableHead","TableHeader","TableRow","toast","Code","Header","Text","useMemo","useState","workspaceStoreScope","useDeleteVariableMutation","useVariablesQuery","copyKeyName","DeleteEntryDialog","secretsErrorToFormError","StoreRowsSkeleton","StoreSurface","VariableForm","VARIABLES_DESCRIPTION","EMPTY_VARIABLES_DESCRIPTION","WorkspaceVariablesSection","workspaceId","variablesQuery","deleteVariable","formState","setFormState","deleteKey","setDeleteKey","deleteError","setDeleteError","variables","data","sort","a","b","key","localeCompare","closeDelete","undefined","section","className","aria-label","div","variant","size","onClick","mode","isPending","label","isError","query","subject","length","icon","title","description","action","span","map","variable","VariableRow","onEdit","onDelete","open","onOpenChange","existingKey","existingValue","value","existingValueTruncated","valueTruncated","reservedKeys","onSaved","wasEdit","success","onCancel","entryKey","isLoading","errorMessage","onConfirm","mutateAsync","scope","error","message","button","type","as","updatedAt","asChild","align","onSelect"],"mappings":"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"}
|