@stackframe/stack 2.8.2 → 2.8.3
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/CHANGELOG.md +10 -0
- package/dist/components/api-key-dialogs.js +184 -0
- package/dist/components/api-key-dialogs.js.map +1 -0
- package/dist/components/api-key-table.js +149 -0
- package/dist/components/api-key-table.js.map +1 -0
- package/dist/components-page/account-settings.js +134 -15
- package/dist/components-page/account-settings.js.map +1 -1
- package/dist/esm/components/api-key-dialogs.js +157 -0
- package/dist/esm/components/api-key-dialogs.js.map +1 -0
- package/dist/esm/components/api-key-table.js +125 -0
- package/dist/esm/components/api-key-table.js.map +1 -0
- package/dist/esm/components-page/account-settings.js +132 -15
- package/dist/esm/components-page/account-settings.js.map +1 -1
- package/dist/esm/lib/stack-app/api-keys/index.js +14 -6
- package/dist/esm/lib/stack-app/api-keys/index.js.map +1 -1
- package/dist/esm/lib/stack-app/apps/implementations/admin-app-impl.js +26 -23
- package/dist/esm/lib/stack-app/apps/implementations/admin-app-impl.js.map +1 -1
- package/dist/esm/lib/stack-app/apps/implementations/client-app-impl.js +90 -0
- package/dist/esm/lib/stack-app/apps/implementations/client-app-impl.js.map +1 -1
- package/dist/esm/lib/stack-app/apps/implementations/common.js +1 -1
- package/dist/esm/lib/stack-app/apps/implementations/common.js.map +1 -1
- package/dist/esm/lib/stack-app/apps/implementations/server-app-impl.js +148 -8
- package/dist/esm/lib/stack-app/apps/implementations/server-app-impl.js.map +1 -1
- package/dist/esm/lib/stack-app/apps/interfaces/admin-app.js.map +1 -1
- package/dist/esm/lib/stack-app/apps/interfaces/server-app.js.map +1 -1
- package/dist/esm/lib/stack-app/index.js.map +1 -1
- package/dist/esm/lib/stack-app/internal-api-keys/index.js +14 -0
- package/dist/esm/lib/stack-app/internal-api-keys/index.js.map +1 -0
- package/dist/esm/lib/stack-app/projects/index.js +3 -1
- package/dist/esm/lib/stack-app/projects/index.js.map +1 -1
- package/dist/esm/lib/stack-app/teams/index.js.map +1 -1
- package/dist/esm/lib/stack-app/users/index.js.map +1 -1
- package/dist/index.d.mts +99 -35
- package/dist/index.d.ts +99 -35
- package/dist/lib/stack-app/api-keys/index.js +16 -7
- package/dist/lib/stack-app/api-keys/index.js.map +1 -1
- package/dist/lib/stack-app/apps/implementations/admin-app-impl.js +25 -22
- package/dist/lib/stack-app/apps/implementations/admin-app-impl.js.map +1 -1
- package/dist/lib/stack-app/apps/implementations/client-app-impl.js +90 -0
- package/dist/lib/stack-app/apps/implementations/client-app-impl.js.map +1 -1
- package/dist/lib/stack-app/apps/implementations/common.js +1 -1
- package/dist/lib/stack-app/apps/implementations/common.js.map +1 -1
- package/dist/lib/stack-app/apps/implementations/server-app-impl.js +148 -8
- package/dist/lib/stack-app/apps/implementations/server-app-impl.js.map +1 -1
- package/dist/lib/stack-app/apps/interfaces/admin-app.js.map +1 -1
- package/dist/lib/stack-app/apps/interfaces/server-app.js.map +1 -1
- package/dist/lib/stack-app/index.js.map +1 -1
- package/dist/lib/stack-app/internal-api-keys/index.js +39 -0
- package/dist/lib/stack-app/internal-api-keys/index.js.map +1 -0
- package/dist/lib/stack-app/project-configs/index.js.map +1 -1
- package/dist/lib/stack-app/projects/index.js +3 -1
- package/dist/lib/stack-app/projects/index.js.map +1 -1
- package/dist/lib/stack-app/teams/index.js.map +1 -1
- package/dist/lib/stack-app/users/index.js.map +1 -1
- package/package.json +5 -4
package/CHANGELOG.md
CHANGED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
"use client";
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
21
|
+
|
|
22
|
+
// src/components/api-key-dialogs.tsx
|
|
23
|
+
var api_key_dialogs_exports = {};
|
|
24
|
+
__export(api_key_dialogs_exports, {
|
|
25
|
+
CreateApiKeyDialog: () => CreateApiKeyDialog,
|
|
26
|
+
ShowApiKeyDialog: () => ShowApiKeyDialog,
|
|
27
|
+
expiresInOptions: () => expiresInOptions,
|
|
28
|
+
neverInMs: () => neverInMs
|
|
29
|
+
});
|
|
30
|
+
module.exports = __toCommonJS(api_key_dialogs_exports);
|
|
31
|
+
var import_yup = require("@hookform/resolvers/yup");
|
|
32
|
+
var import_schema_fields = require("@stackframe/stack-shared/dist/schema-fields");
|
|
33
|
+
var import_errors = require("@stackframe/stack-shared/dist/utils/errors");
|
|
34
|
+
var import_promises = require("@stackframe/stack-shared/dist/utils/promises");
|
|
35
|
+
var import_stack_ui = require("@stackframe/stack-ui");
|
|
36
|
+
var import_react = require("react");
|
|
37
|
+
var import_react_hook_form = require("react-hook-form");
|
|
38
|
+
var import__ = require("..");
|
|
39
|
+
var import_form_warning = require("../components/elements/form-warning");
|
|
40
|
+
var import_translations = require("../lib/translations");
|
|
41
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
42
|
+
var neverInMs = 1e3 * 60 * 60 * 24 * 365 * 200;
|
|
43
|
+
var expiresInOptions = {
|
|
44
|
+
[1e3 * 60 * 60 * 24 * 1]: "1 day",
|
|
45
|
+
[1e3 * 60 * 60 * 24 * 7]: "7 days",
|
|
46
|
+
[1e3 * 60 * 60 * 24 * 30]: "30 days",
|
|
47
|
+
[1e3 * 60 * 60 * 24 * 90]: "90 days",
|
|
48
|
+
[1e3 * 60 * 60 * 24 * 365]: "1 year",
|
|
49
|
+
[neverInMs]: "Never"
|
|
50
|
+
};
|
|
51
|
+
function CreateApiKeyDialog(props) {
|
|
52
|
+
const { t } = (0, import_translations.useTranslation)();
|
|
53
|
+
const user = (0, import__.useUser)({ or: "redirect" });
|
|
54
|
+
const [loading, setLoading] = (0, import_react.useState)(false);
|
|
55
|
+
const apiKeySchema = (0, import_schema_fields.yupObject)({
|
|
56
|
+
description: (0, import_schema_fields.yupString)().defined().nonEmpty(t("Description is required")),
|
|
57
|
+
expiresIn: (0, import_schema_fields.yupString)().defined()
|
|
58
|
+
});
|
|
59
|
+
const { register, handleSubmit, formState: { errors }, reset } = (0, import_react_hook_form.useForm)({
|
|
60
|
+
resolver: (0, import_yup.yupResolver)(apiKeySchema),
|
|
61
|
+
defaultValues: {
|
|
62
|
+
description: "",
|
|
63
|
+
expiresIn: Object.keys(expiresInOptions)[2]
|
|
64
|
+
// Default to 30 days
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
const onSubmit = async (data) => {
|
|
68
|
+
setLoading(true);
|
|
69
|
+
try {
|
|
70
|
+
const expiresAt = new Date(Date.now() + parseInt(data.expiresIn));
|
|
71
|
+
const apiKey = await props.createApiKey({
|
|
72
|
+
description: data.description,
|
|
73
|
+
expiresAt
|
|
74
|
+
});
|
|
75
|
+
if (props.onKeyCreated) {
|
|
76
|
+
props.onKeyCreated(apiKey);
|
|
77
|
+
}
|
|
78
|
+
reset();
|
|
79
|
+
props.onOpenChange(false);
|
|
80
|
+
} catch (error) {
|
|
81
|
+
(0, import_errors.captureError)("Failed to create API key", { error });
|
|
82
|
+
} finally {
|
|
83
|
+
setLoading(false);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
87
|
+
import_stack_ui.ActionDialog,
|
|
88
|
+
{
|
|
89
|
+
open: props.open,
|
|
90
|
+
onOpenChange: props.onOpenChange,
|
|
91
|
+
title: t("Create API Key"),
|
|
92
|
+
description: t("API keys grant programmatic access to your account."),
|
|
93
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
94
|
+
"form",
|
|
95
|
+
{
|
|
96
|
+
onSubmit: (e) => {
|
|
97
|
+
e.preventDefault();
|
|
98
|
+
(0, import_promises.runAsynchronously)(handleSubmit(onSubmit));
|
|
99
|
+
},
|
|
100
|
+
className: "space-y-4",
|
|
101
|
+
children: [
|
|
102
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-2", children: [
|
|
103
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { htmlFor: "description", children: t("Description") }),
|
|
104
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
105
|
+
import_stack_ui.Input,
|
|
106
|
+
{
|
|
107
|
+
id: "description",
|
|
108
|
+
placeholder: t("e.g. Development, Production, CI/CD"),
|
|
109
|
+
...register("description")
|
|
110
|
+
}
|
|
111
|
+
),
|
|
112
|
+
errors.description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_form_warning.FormWarningText, { text: errors.description.message })
|
|
113
|
+
] }),
|
|
114
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-2", children: [
|
|
115
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { htmlFor: "expiresIn", children: t("Expires In") }),
|
|
116
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
117
|
+
"select",
|
|
118
|
+
{
|
|
119
|
+
id: "expiresIn",
|
|
120
|
+
className: "w-full p-2 border border-input rounded-md bg-background",
|
|
121
|
+
...register("expiresIn"),
|
|
122
|
+
children: Object.entries(expiresInOptions).map(([value, label]) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value, children: t(label) }, value))
|
|
123
|
+
}
|
|
124
|
+
),
|
|
125
|
+
errors.expiresIn && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_form_warning.FormWarningText, { text: errors.expiresIn.message })
|
|
126
|
+
] }),
|
|
127
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex justify-end gap-2 pt-4", children: [
|
|
128
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
129
|
+
import_stack_ui.Button,
|
|
130
|
+
{
|
|
131
|
+
type: "button",
|
|
132
|
+
variant: "secondary",
|
|
133
|
+
onClick: () => {
|
|
134
|
+
reset();
|
|
135
|
+
props.onOpenChange(false);
|
|
136
|
+
},
|
|
137
|
+
children: t("Cancel")
|
|
138
|
+
}
|
|
139
|
+
),
|
|
140
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { type: "submit", loading, children: t("Create") })
|
|
141
|
+
] })
|
|
142
|
+
]
|
|
143
|
+
}
|
|
144
|
+
)
|
|
145
|
+
}
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
function ShowApiKeyDialog(props) {
|
|
149
|
+
const { t } = (0, import_translations.useTranslation)();
|
|
150
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
151
|
+
import_stack_ui.ActionDialog,
|
|
152
|
+
{
|
|
153
|
+
open: !!props.apiKey,
|
|
154
|
+
title: t("API Key"),
|
|
155
|
+
okButton: { label: t("Close") },
|
|
156
|
+
onClose: props.onClose,
|
|
157
|
+
preventClose: true,
|
|
158
|
+
confirmText: t("I understand that I will not be able to view this key again."),
|
|
159
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-4", children: [
|
|
160
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.Typography, { children: [
|
|
161
|
+
t("Here is your API key."),
|
|
162
|
+
" ",
|
|
163
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-bold", children: t("Copy it to a safe place. You will not be able to view it again.") })
|
|
164
|
+
] }),
|
|
165
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
166
|
+
import_stack_ui.CopyField,
|
|
167
|
+
{
|
|
168
|
+
monospace: true,
|
|
169
|
+
value: props.apiKey?.value ?? "",
|
|
170
|
+
label: t("Secret API Key")
|
|
171
|
+
}
|
|
172
|
+
)
|
|
173
|
+
] })
|
|
174
|
+
}
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
178
|
+
0 && (module.exports = {
|
|
179
|
+
CreateApiKeyDialog,
|
|
180
|
+
ShowApiKeyDialog,
|
|
181
|
+
expiresInOptions,
|
|
182
|
+
neverInMs
|
|
183
|
+
});
|
|
184
|
+
//# sourceMappingURL=api-key-dialogs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/api-key-dialogs.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\n\nimport { yupResolver } from \"@hookform/resolvers/yup\";\nimport { yupObject, yupString } from '@stackframe/stack-shared/dist/schema-fields';\nimport { captureError } from '@stackframe/stack-shared/dist/utils/errors';\nimport { runAsynchronously } from '@stackframe/stack-shared/dist/utils/promises';\nimport { ActionDialog, Button, CopyField, Input, Label, Typography } from '@stackframe/stack-ui';\nimport { useState } from \"react\";\nimport { useForm } from 'react-hook-form';\nimport * as yup from \"yup\";\nimport { useUser } from '..';\nimport { FormWarningText } from '../components/elements/form-warning';\nimport { ApiKey, ApiKeyCreationOptions, ApiKeyType } from \"../lib/stack-app/api-keys\";\nimport { useTranslation } from \"../lib/translations\";\n\n// Constants for expiration options\nexport const neverInMs = 1000 * 60 * 60 * 24 * 365 * 200;\nexport const expiresInOptions = {\n [1000 * 60 * 60 * 24 * 1]: \"1 day\",\n [1000 * 60 * 60 * 24 * 7]: \"7 days\",\n [1000 * 60 * 60 * 24 * 30]: \"30 days\",\n [1000 * 60 * 60 * 24 * 90]: \"90 days\",\n [1000 * 60 * 60 * 24 * 365]: \"1 year\",\n [neverInMs]: \"Never\",\n} as const;\n\n/**\n * Dialog for creating a new API key\n */\nexport function CreateApiKeyDialog<Type extends ApiKeyType = ApiKeyType>(props: {\n open: boolean,\n onOpenChange: (open: boolean) => void,\n onKeyCreated?: (key: ApiKey<Type, true>) => void,\n createApiKey: (data: ApiKeyCreationOptions<Type>) => Promise<ApiKey<Type, true>>,\n}) {\n const { t } = useTranslation();\n const user = useUser({ or: 'redirect' });\n const [loading, setLoading] = useState(false);\n\n const apiKeySchema = yupObject({\n description: yupString().defined().nonEmpty(t('Description is required')),\n expiresIn: yupString().defined(),\n });\n\n const { register, handleSubmit, formState: { errors }, reset } = useForm({\n resolver: yupResolver(apiKeySchema),\n defaultValues: {\n description: '',\n expiresIn: Object.keys(expiresInOptions)[2], // Default to 30 days\n }\n });\n\n const onSubmit = async (data: yup.InferType<typeof apiKeySchema>) => {\n setLoading(true);\n try {\n const expiresAt = new Date(Date.now() + parseInt(data.expiresIn));\n const apiKey = await props.createApiKey({\n description: data.description,\n expiresAt,\n });\n\n if (props.onKeyCreated) {\n props.onKeyCreated(apiKey);\n }\n\n reset();\n props.onOpenChange(false);\n } catch (error) {\n captureError(\"Failed to create API key\", { error });\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <ActionDialog\n open={props.open}\n onOpenChange={props.onOpenChange}\n title={t('Create API Key')}\n description={t('API keys grant programmatic access to your account.')}\n >\n <form\n onSubmit={(e) => {\n e.preventDefault();\n runAsynchronously(handleSubmit(onSubmit));\n }}\n className=\"space-y-4\"\n >\n <div className=\"space-y-2\">\n <Label htmlFor=\"description\">{t('Description')}</Label>\n <Input\n id=\"description\"\n placeholder={t('e.g. Development, Production, CI/CD')}\n {...register('description')}\n />\n {errors.description && <FormWarningText text={errors.description.message} />}\n </div>\n\n <div className=\"space-y-2\">\n <Label htmlFor=\"expiresIn\">{t('Expires In')}</Label>\n <select\n id=\"expiresIn\"\n className=\"w-full p-2 border border-input rounded-md bg-background\"\n {...register('expiresIn')}\n >\n {Object.entries(expiresInOptions).map(([value, label]) => (\n <option key={value} value={value}>{t(label)}</option>\n ))}\n </select>\n {errors.expiresIn && <FormWarningText text={errors.expiresIn.message} />}\n </div>\n\n <div className=\"flex justify-end gap-2 pt-4\">\n <Button\n type=\"button\"\n variant=\"secondary\"\n onClick={() => {\n reset();\n props.onOpenChange(false);\n }}\n >\n {t('Cancel')}\n </Button>\n <Button type=\"submit\" loading={loading}>\n {t('Create')}\n </Button>\n </div>\n </form>\n </ActionDialog>\n );\n}\n\n/**\n * Dialog for showing the newly created API key\n */\nexport function ShowApiKeyDialog<Type extends ApiKeyType = ApiKeyType>(props: {\n apiKey: ApiKey<Type, true> | null,\n onClose?: () => void,\n}) {\n const { t } = useTranslation();\n\n return (\n <ActionDialog\n open={!!props.apiKey}\n title={t(\"API Key\")}\n okButton={{ label: t(\"Close\") }}\n onClose={props.onClose}\n preventClose\n confirmText={t(\"I understand that I will not be able to view this key again.\")}\n >\n <div className=\"flex flex-col gap-4\">\n <Typography>\n {t(\"Here is your API key.\")}{\" \"}\n <span className=\"font-bold\">\n {t(\"Copy it to a safe place. You will not be able to view it again.\")}\n </span>\n </Typography>\n <CopyField\n monospace\n value={props.apiKey?.value ?? ''}\n label={t(\"Secret API Key\")}\n />\n </div>\n </ActionDialog>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
"use client";
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
21
|
+
|
|
22
|
+
// src/components/api-key-table.tsx
|
|
23
|
+
var api_key_table_exports = {};
|
|
24
|
+
__export(api_key_table_exports, {
|
|
25
|
+
ApiKeyTable: () => ApiKeyTable
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(api_key_table_exports);
|
|
28
|
+
var import_stack_ui = require("@stackframe/stack-ui");
|
|
29
|
+
var import_react = require("react");
|
|
30
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
31
|
+
function toolbarRender(table) {
|
|
32
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
33
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.SearchToolbarItem, { table, placeholder: "Search table" }),
|
|
34
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
35
|
+
import_stack_ui.DataTableFacetedFilter,
|
|
36
|
+
{
|
|
37
|
+
column: table.getColumn("status"),
|
|
38
|
+
title: "Status",
|
|
39
|
+
options: ["valid", "expired", "revoked"].map((provider) => ({
|
|
40
|
+
value: provider,
|
|
41
|
+
label: provider
|
|
42
|
+
}))
|
|
43
|
+
}
|
|
44
|
+
)
|
|
45
|
+
] });
|
|
46
|
+
}
|
|
47
|
+
function RevokeDialog(props) {
|
|
48
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
49
|
+
import_stack_ui.ActionDialog,
|
|
50
|
+
{
|
|
51
|
+
open: props.open,
|
|
52
|
+
onOpenChange: props.onOpenChange,
|
|
53
|
+
title: "Revoke API Key",
|
|
54
|
+
danger: true,
|
|
55
|
+
cancelButton: true,
|
|
56
|
+
okButton: { label: "Revoke Key", onClick: async () => {
|
|
57
|
+
await props.apiKey.revoke();
|
|
58
|
+
} },
|
|
59
|
+
confirmText: "I understand this will unlink all the apps using this API key",
|
|
60
|
+
children: `Are you sure you want to revoke API key *****${props.apiKey.value.lastFour}?`
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
function Actions({ row }) {
|
|
65
|
+
const [isRevokeModalOpen, setIsRevokeModalOpen] = (0, import_react.useState)(false);
|
|
66
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
67
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(RevokeDialog, { apiKey: row.original, open: isRevokeModalOpen, onOpenChange: setIsRevokeModalOpen }),
|
|
68
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
69
|
+
import_stack_ui.ActionCell,
|
|
70
|
+
{
|
|
71
|
+
invisible: row.original.status !== "valid",
|
|
72
|
+
items: [{
|
|
73
|
+
item: "Revoke",
|
|
74
|
+
danger: true,
|
|
75
|
+
onClick: () => setIsRevokeModalOpen(true)
|
|
76
|
+
}]
|
|
77
|
+
}
|
|
78
|
+
)
|
|
79
|
+
] });
|
|
80
|
+
}
|
|
81
|
+
var columns = [
|
|
82
|
+
{
|
|
83
|
+
accessorKey: "description",
|
|
84
|
+
header: ({ column }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.DataTableColumnHeader, { column, columnTitle: "Description" }),
|
|
85
|
+
cell: ({ row }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TextCell, { size: 100, children: row.original.description })
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
accessorKey: "status",
|
|
89
|
+
header: ({ column }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.DataTableColumnHeader, { column, columnTitle: "Status" }),
|
|
90
|
+
cell: ({ row }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.BadgeCell, { badges: [row.original.status] }),
|
|
91
|
+
filterFn: import_stack_ui.standardFilterFn
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
id: "value",
|
|
95
|
+
accessorFn: (row) => row.value.lastFour,
|
|
96
|
+
header: ({ column }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.DataTableColumnHeader, { column, columnTitle: "Client Key" }),
|
|
97
|
+
cell: ({ row }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.TextCell, { children: [
|
|
98
|
+
"*******",
|
|
99
|
+
row.original.value.lastFour
|
|
100
|
+
] }),
|
|
101
|
+
enableSorting: false
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
accessorKey: "expiresAt",
|
|
105
|
+
header: ({ column }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.DataTableColumnHeader, { column, columnTitle: "Expires At" }),
|
|
106
|
+
cell: ({ row }) => {
|
|
107
|
+
if (row.original.status === "revoked") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TextCell, { children: "-" });
|
|
108
|
+
return row.original.expiresAt ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.DateCell, { date: row.original.expiresAt, ignoreAfterYears: 50 }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TextCell, { children: "Never" });
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
accessorKey: "createdAt",
|
|
113
|
+
header: ({ column }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.DataTableColumnHeader, { column, columnTitle: "Created At" }),
|
|
114
|
+
cell: ({ row }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.DateCell, { date: row.original.createdAt, ignoreAfterYears: 50 })
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
id: "actions",
|
|
118
|
+
cell: ({ row }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Actions, { row })
|
|
119
|
+
}
|
|
120
|
+
];
|
|
121
|
+
function ApiKeyTable(props) {
|
|
122
|
+
const extendedApiKeys = (0, import_react.useMemo)(() => {
|
|
123
|
+
const keys = props.apiKeys.map((apiKey) => ({
|
|
124
|
+
...apiKey,
|
|
125
|
+
status: { "valid": "valid", "manually-revoked": "revoked", "expired": "expired" }[apiKey.whyInvalid() || "valid"]
|
|
126
|
+
}));
|
|
127
|
+
return keys.sort((a, b) => {
|
|
128
|
+
if (a.status === b.status) {
|
|
129
|
+
return a.createdAt < b.createdAt ? 1 : -1;
|
|
130
|
+
}
|
|
131
|
+
return a.status === "valid" ? -1 : 1;
|
|
132
|
+
});
|
|
133
|
+
}, [props.apiKeys]);
|
|
134
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
135
|
+
import_stack_ui.DataTable,
|
|
136
|
+
{
|
|
137
|
+
data: extendedApiKeys,
|
|
138
|
+
columns,
|
|
139
|
+
toolbarRender,
|
|
140
|
+
defaultColumnFilters: [],
|
|
141
|
+
defaultSorting: []
|
|
142
|
+
}
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
146
|
+
0 && (module.exports = {
|
|
147
|
+
ApiKeyTable
|
|
148
|
+
});
|
|
149
|
+
//# sourceMappingURL=api-key-table.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/api-key-table.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\nimport { ActionCell, ActionDialog, BadgeCell, DataTable, DataTableColumnHeader, DataTableFacetedFilter, DateCell, SearchToolbarItem, TextCell, standardFilterFn } from \"@stackframe/stack-ui\";\nimport { ColumnDef, Row, Table } from \"@tanstack/react-table\";\nimport { useMemo, useState } from \"react\";\nimport { ApiKey } from \"../lib/stack-app/api-keys\";\n\ntype ExtendedApiKey = ApiKey & {\n status: 'valid' | 'expired' | 'revoked',\n};\n\nfunction toolbarRender<TData>(table: Table<TData>) {\n return (\n <>\n <SearchToolbarItem table={table} placeholder=\"Search table\" />\n <DataTableFacetedFilter\n column={table.getColumn(\"status\")}\n title=\"Status\"\n options={['valid', 'expired', 'revoked'].map((provider) => ({\n value: provider,\n label: provider,\n }))}\n />\n </>\n );\n}\n\nfunction RevokeDialog(props: {\n apiKey: ExtendedApiKey,\n open: boolean,\n onOpenChange: (open: boolean) => void,\n}) {\n return <ActionDialog\n open={props.open}\n onOpenChange={props.onOpenChange}\n title=\"Revoke API Key\"\n danger\n cancelButton\n okButton={{ label: \"Revoke Key\", onClick: async () => { await props.apiKey.revoke(); } }}\n confirmText=\"I understand this will unlink all the apps using this API key\"\n >\n {`Are you sure you want to revoke API key *****${props.apiKey.value.lastFour}?`}\n </ActionDialog>;\n}\n\nfunction Actions({ row }: { row: Row<ExtendedApiKey> }) {\n const [isRevokeModalOpen, setIsRevokeModalOpen] = useState(false);\n return (\n <>\n <RevokeDialog apiKey={row.original} open={isRevokeModalOpen} onOpenChange={setIsRevokeModalOpen} />\n <ActionCell\n invisible={row.original.status !== 'valid'}\n items={[{\n item: \"Revoke\",\n danger: true,\n onClick: () => setIsRevokeModalOpen(true),\n }]}\n />\n </>\n );\n}\n\nconst columns: ColumnDef<ExtendedApiKey>[] = [\n {\n accessorKey: \"description\",\n header: ({ column }) => <DataTableColumnHeader column={column} columnTitle=\"Description\" />,\n cell: ({ row }) => <TextCell size={100}>{row.original.description}</TextCell>,\n },\n {\n accessorKey: \"status\",\n header: ({ column }) => <DataTableColumnHeader column={column} columnTitle=\"Status\" />,\n cell: ({ row }) => <BadgeCell badges={[row.original.status]} />,\n filterFn: standardFilterFn,\n },\n {\n id: \"value\",\n accessorFn: (row) => row.value.lastFour,\n header: ({ column }) => <DataTableColumnHeader column={column} columnTitle=\"Client Key\" />,\n cell: ({ row }) => <TextCell>*******{row.original.value.lastFour}</TextCell>,\n enableSorting: false,\n },\n {\n accessorKey: \"expiresAt\",\n header: ({ column }) => <DataTableColumnHeader column={column} columnTitle=\"Expires At\" />,\n cell: ({ row }) => {\n if (row.original.status === 'revoked') return <TextCell>-</TextCell>;\n return row.original.expiresAt ? <DateCell date={row.original.expiresAt} ignoreAfterYears={50} /> : <TextCell>Never</TextCell>;\n },\n },\n {\n accessorKey: \"createdAt\",\n header: ({ column }) => <DataTableColumnHeader column={column} columnTitle=\"Created At\" />,\n cell: ({ row }) => <DateCell date={row.original.createdAt} ignoreAfterYears={50} />\n },\n {\n id: \"actions\",\n cell: ({ row }) => <Actions row={row} />,\n },\n];\n\nexport function ApiKeyTable(props: { apiKeys: ApiKey[] }) {\n const extendedApiKeys = useMemo(() => {\n const keys = props.apiKeys.map((apiKey) => ({\n ...apiKey,\n status: ({ 'valid': 'valid', 'manually-revoked': 'revoked', 'expired': 'expired' } as const)[apiKey.whyInvalid() || 'valid'],\n } satisfies ExtendedApiKey));\n // first sort based on status, then by createdAt\n return keys.sort((a, b) => {\n if (a.status === b.status) {\n return a.createdAt < b.createdAt ? 1 : -1;\n }\n return a.status === 'valid' ? -1 : 1;\n });\n }, [props.apiKeys]);\n\n return <DataTable\n data={extendedApiKeys}\n columns={columns}\n toolbarRender={toolbarRender}\n defaultColumnFilters={[]}\n defaultSorting={[]}\n />;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -33,7 +33,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
33
33
|
var account_settings_exports = {};
|
|
34
34
|
__export(account_settings_exports, {
|
|
35
35
|
AccountSettings: () => AccountSettings,
|
|
36
|
-
|
|
36
|
+
ApiKeysPage: () => ApiKeysPage,
|
|
37
|
+
EditableText: () => EditableText,
|
|
38
|
+
TeamApiKeysSection: () => TeamApiKeysSection
|
|
37
39
|
});
|
|
38
40
|
module.exports = __toCommonJS(account_settings_exports);
|
|
39
41
|
var import_yup = require("@hookform/resolvers/yup");
|
|
@@ -53,6 +55,8 @@ var import_react = require("react");
|
|
|
53
55
|
var import_react_hook_form = require("react-hook-form");
|
|
54
56
|
var yup = __toESM(require("yup"));
|
|
55
57
|
var import__ = require("..");
|
|
58
|
+
var import_api_key_dialogs = require("../components/api-key-dialogs");
|
|
59
|
+
var import_api_key_table = require("../components/api-key-table");
|
|
56
60
|
var import_form_warning = require("../components/elements/form-warning");
|
|
57
61
|
var import_maybe_full_page = require("../components/elements/maybe-full-page");
|
|
58
62
|
var import_sidebar_layout = require("../components/elements/sidebar-layout");
|
|
@@ -96,6 +100,13 @@ function AccountSettings(props) {
|
|
|
96
100
|
icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { name: "Monitor" }),
|
|
97
101
|
content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.Suspense, { fallback: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ActiveSessionsPageSkeleton, {}), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ActiveSessionsPage, {}) })
|
|
98
102
|
},
|
|
103
|
+
...project.config.allowUserApiKeys ? [{
|
|
104
|
+
title: t("API Keys"),
|
|
105
|
+
type: "item",
|
|
106
|
+
id: "api-keys",
|
|
107
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { name: "Key" }),
|
|
108
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.Suspense, { fallback: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ApiKeysPageSkeleton, {}), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ApiKeysPage, {}) })
|
|
109
|
+
}] : [],
|
|
99
110
|
{
|
|
100
111
|
title: t("Settings"),
|
|
101
112
|
type: "item",
|
|
@@ -129,14 +140,14 @@ function AccountSettings(props) {
|
|
|
129
140
|
] }),
|
|
130
141
|
type: "item",
|
|
131
142
|
id: `team-${team.id}`,
|
|
132
|
-
content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamPage, { team })
|
|
143
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.Suspense, { fallback: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamPageSkeleton, {}), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamPage, { team }) })
|
|
133
144
|
})),
|
|
134
145
|
...project.config.clientTeamCreationEnabled ? [{
|
|
135
146
|
title: t("Create a team"),
|
|
136
147
|
icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { name: "CirclePlus" }),
|
|
137
148
|
type: "item",
|
|
138
149
|
id: "team-creation",
|
|
139
|
-
content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamCreation, {})
|
|
150
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.Suspense, { fallback: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamCreationSkeleton, {}), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamCreation, {}) })
|
|
140
151
|
}] : []
|
|
141
152
|
].filter((p) => p.type === "divider" || p.content),
|
|
142
153
|
title: t("Account Settings")
|
|
@@ -158,6 +169,88 @@ function Section(props) {
|
|
|
158
169
|
function PageLayout(props) {
|
|
159
170
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex flex-col gap-6", children: props.children });
|
|
160
171
|
}
|
|
172
|
+
function ApiKeysPage() {
|
|
173
|
+
const { t } = (0, import_translations.useTranslation)();
|
|
174
|
+
const user = (0, import__.useUser)({ or: "redirect" });
|
|
175
|
+
const apiKeys = user.useApiKeys();
|
|
176
|
+
const [isNewApiKeyDialogOpen, setIsNewApiKeyDialogOpen] = (0, import_react.useState)(false);
|
|
177
|
+
const [returnedApiKey, setReturnedApiKey] = (0, import_react.useState)(null);
|
|
178
|
+
const CreateDialog = import_api_key_dialogs.CreateApiKeyDialog;
|
|
179
|
+
const ShowDialog = import_api_key_dialogs.ShowApiKeyDialog;
|
|
180
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(PageLayout, { children: [
|
|
181
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { onClick: () => setIsNewApiKeyDialogOpen(true), children: t("Create API Key") }),
|
|
182
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_api_key_table.ApiKeyTable, { apiKeys }),
|
|
183
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
184
|
+
CreateDialog,
|
|
185
|
+
{
|
|
186
|
+
open: isNewApiKeyDialogOpen,
|
|
187
|
+
onOpenChange: setIsNewApiKeyDialogOpen,
|
|
188
|
+
onKeyCreated: setReturnedApiKey,
|
|
189
|
+
createApiKey: async (data) => {
|
|
190
|
+
const apiKey = await user.createApiKey(data);
|
|
191
|
+
return apiKey;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
),
|
|
195
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
196
|
+
ShowDialog,
|
|
197
|
+
{
|
|
198
|
+
apiKey: returnedApiKey,
|
|
199
|
+
onClose: () => setReturnedApiKey(null)
|
|
200
|
+
}
|
|
201
|
+
)
|
|
202
|
+
] });
|
|
203
|
+
}
|
|
204
|
+
function TeamApiKeysSection(props) {
|
|
205
|
+
const user = (0, import__.useUser)({ or: "redirect" });
|
|
206
|
+
const team = user.useTeam(props.team.id);
|
|
207
|
+
if (!team) {
|
|
208
|
+
throw new import_errors.StackAssertionError("Team not found");
|
|
209
|
+
}
|
|
210
|
+
const manageApiKeysPermission = user.usePermission(props.team, "$manage_api_keys");
|
|
211
|
+
if (!manageApiKeysPermission) {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamApiKeysSectionInner, { team: props.team });
|
|
215
|
+
}
|
|
216
|
+
function TeamApiKeysSectionInner(props) {
|
|
217
|
+
const { t } = (0, import_translations.useTranslation)();
|
|
218
|
+
const [isNewApiKeyDialogOpen, setIsNewApiKeyDialogOpen] = (0, import_react.useState)(false);
|
|
219
|
+
const [returnedApiKey, setReturnedApiKey] = (0, import_react.useState)(null);
|
|
220
|
+
const apiKeys = props.team.useApiKeys();
|
|
221
|
+
const CreateDialog = import_api_key_dialogs.CreateApiKeyDialog;
|
|
222
|
+
const ShowDialog = import_api_key_dialogs.ShowApiKeyDialog;
|
|
223
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
224
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
225
|
+
Section,
|
|
226
|
+
{
|
|
227
|
+
title: t("API Keys"),
|
|
228
|
+
description: t("API keys grant programmatic access to your team."),
|
|
229
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { onClick: () => setIsNewApiKeyDialogOpen(true), children: t("Create API Key") })
|
|
230
|
+
}
|
|
231
|
+
),
|
|
232
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_api_key_table.ApiKeyTable, { apiKeys }),
|
|
233
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
234
|
+
CreateDialog,
|
|
235
|
+
{
|
|
236
|
+
open: isNewApiKeyDialogOpen,
|
|
237
|
+
onOpenChange: setIsNewApiKeyDialogOpen,
|
|
238
|
+
onKeyCreated: setReturnedApiKey,
|
|
239
|
+
createApiKey: async (data) => {
|
|
240
|
+
const apiKey = await props.team.createApiKey(data);
|
|
241
|
+
return apiKey;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
),
|
|
245
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
246
|
+
ShowDialog,
|
|
247
|
+
{
|
|
248
|
+
apiKey: returnedApiKey,
|
|
249
|
+
onClose: () => setReturnedApiKey(null)
|
|
250
|
+
}
|
|
251
|
+
)
|
|
252
|
+
] });
|
|
253
|
+
}
|
|
161
254
|
function ProfilePage() {
|
|
162
255
|
const { t } = (0, import_translations.useTranslation)();
|
|
163
256
|
const user = (0, import__.useUser)({ or: "redirect" });
|
|
@@ -835,12 +928,13 @@ function SignOutSection() {
|
|
|
835
928
|
}
|
|
836
929
|
function TeamPage(props) {
|
|
837
930
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(PageLayout, { children: [
|
|
838
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamUserProfileSection, { team: props.team }),
|
|
839
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
840
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
841
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
842
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
843
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
931
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamUserProfileSection, { team: props.team }, `user-profile-${props.team.id}`),
|
|
932
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamProfileImageSection, { team: props.team }, `profile-image-${props.team.id}`),
|
|
933
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamDisplayNameSection, { team: props.team }, `display-name-${props.team.id}`),
|
|
934
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MemberListSection, { team: props.team }, `member-list-${props.team.id}`),
|
|
935
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MemberInvitationSection, { team: props.team }, `member-invitation-${props.team.id}`),
|
|
936
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamApiKeysSection, { team: props.team }, `api-keys-${props.team.id}`),
|
|
937
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(LeaveTeamSection, { team: props.team }, `leave-team-${props.team.id}`)
|
|
844
938
|
] });
|
|
845
939
|
}
|
|
846
940
|
function LeaveTeamSection(props) {
|
|
@@ -972,11 +1066,14 @@ function MemberInvitationsSectionInvitationsList(props) {
|
|
|
972
1066
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableHead, { className: "w-[60px]", children: t("Expires") }),
|
|
973
1067
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableHead, { className: "w-[36px] max-w-[36px]" })
|
|
974
1068
|
] }) }),
|
|
975
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
1069
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.TableBody, { children: [
|
|
1070
|
+
invitationsToShow.map((invitation, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.TableRow, { children: [
|
|
1071
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableCell, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { children: invitation.recipientEmail }) }),
|
|
1072
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableCell, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "secondary", children: invitation.expiresAt.toLocaleString() }) }),
|
|
1073
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableCell, { align: "right", className: "max-w-[36px]", children: removeMemberPermission && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { onClick: async () => await invitation.revoke(), size: "icon", variant: "ghost", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Trash, { className: "w-4 h-4" }) }) })
|
|
1074
|
+
] }, invitation.id)),
|
|
1075
|
+
invitationsToShow.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableRow, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableCell, { colSpan: 3, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "secondary", children: t("No outstanding invitations") }) }) })
|
|
1076
|
+
] })
|
|
980
1077
|
] }) });
|
|
981
1078
|
}
|
|
982
1079
|
function MemberInvitationSectionInner(props) {
|
|
@@ -1205,9 +1302,31 @@ function EditableText(props) {
|
|
|
1205
1302
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { onClick: () => setEditing(true), size: "icon", variant: "ghost", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Edit, { className: "w-4 h-4" }) })
|
|
1206
1303
|
] }) });
|
|
1207
1304
|
}
|
|
1305
|
+
function ApiKeysPageSkeleton() {
|
|
1306
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(PageLayout, { children: [
|
|
1307
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Skeleton, { className: "h-9 w-full mt-1" }),
|
|
1308
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Skeleton, { className: "h-[200px] w-full mt-1 rounded-md" })
|
|
1309
|
+
] });
|
|
1310
|
+
}
|
|
1311
|
+
function TeamPageSkeleton() {
|
|
1312
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(PageLayout, { children: [
|
|
1313
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Skeleton, { className: "h-9 w-full mt-1" }),
|
|
1314
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Skeleton, { className: "h-9 w-full mt-1" }),
|
|
1315
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Skeleton, { className: "h-9 w-full mt-1" }),
|
|
1316
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Skeleton, { className: "h-[200px] w-full mt-1 rounded-md" })
|
|
1317
|
+
] });
|
|
1318
|
+
}
|
|
1319
|
+
function TeamCreationSkeleton() {
|
|
1320
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(PageLayout, { children: [
|
|
1321
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Skeleton, { className: "h-9 w-full mt-1" }),
|
|
1322
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Skeleton, { className: "h-9 w-full mt-1" })
|
|
1323
|
+
] });
|
|
1324
|
+
}
|
|
1208
1325
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1209
1326
|
0 && (module.exports = {
|
|
1210
1327
|
AccountSettings,
|
|
1211
|
-
|
|
1328
|
+
ApiKeysPage,
|
|
1329
|
+
EditableText,
|
|
1330
|
+
TeamApiKeysSection
|
|
1212
1331
|
});
|
|
1213
1332
|
//# sourceMappingURL=account-settings.js.map
|