@emdash-cms/admin 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{config-BHC21FmY.d.ts → config-Dku9rWu6.d.ts} +1 -1
- package/dist/{config-BHC21FmY.d.ts.map → config-Dku9rWu6.d.ts.map} +1 -1
- package/dist/index.d.ts +19 -32
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1081 -492
- package/dist/index.js.map +1 -1
- package/dist/locales/de/messages.mjs +1 -1
- package/dist/locales/en/messages.mjs +1 -1
- package/dist/locales/fr/messages.mjs +1 -0
- package/dist/locales/index.d.ts +8 -2
- package/dist/locales/index.d.ts.map +1 -0
- package/dist/locales/index.js +18 -1
- package/dist/locales/index.js.map +1 -0
- package/dist/messages-2jYesPAq.js +6 -0
- package/dist/messages-2jYesPAq.js.map +1 -0
- package/dist/messages-BfrdxD3Y.js +6 -0
- package/dist/messages-BfrdxD3Y.js.map +1 -0
- package/dist/messages-CtrDoZ_2.js +6 -0
- package/dist/messages-CtrDoZ_2.js.map +1 -0
- package/dist/styles.css +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -204,9 +204,11 @@ function getMutationError(error) {
|
|
|
204
204
|
/** Inline error banner for use inside dialogs. */
|
|
205
205
|
function DialogError({ message, className }) {
|
|
206
206
|
if (!message) return null;
|
|
207
|
+
const lines = message.split("\n");
|
|
207
208
|
return /* @__PURE__ */ jsx("div", {
|
|
209
|
+
role: "alert",
|
|
208
210
|
className: cn("rounded-md bg-kumo-danger/10 p-3 text-sm text-kumo-danger", className),
|
|
209
|
-
children:
|
|
211
|
+
children: lines.map((line, i) => /* @__PURE__ */ jsx("div", { children: line }, i))
|
|
210
212
|
});
|
|
211
213
|
}
|
|
212
214
|
|
|
@@ -2037,44 +2039,19 @@ async function executeWpPluginImport(url, token, config) {
|
|
|
2037
2039
|
/**
|
|
2038
2040
|
* API token management client functions
|
|
2039
2041
|
*/
|
|
2040
|
-
/**
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
value: "media:read",
|
|
2054
|
-
label: "Media Read",
|
|
2055
|
-
description: "Read media files"
|
|
2056
|
-
},
|
|
2057
|
-
{
|
|
2058
|
-
value: "media:write",
|
|
2059
|
-
label: "Media Write",
|
|
2060
|
-
description: "Upload and delete media"
|
|
2061
|
-
},
|
|
2062
|
-
{
|
|
2063
|
-
value: "schema:read",
|
|
2064
|
-
label: "Schema Read",
|
|
2065
|
-
description: "Read collection schemas"
|
|
2066
|
-
},
|
|
2067
|
-
{
|
|
2068
|
-
value: "schema:write",
|
|
2069
|
-
label: "Schema Write",
|
|
2070
|
-
description: "Modify collection schemas"
|
|
2071
|
-
},
|
|
2072
|
-
{
|
|
2073
|
-
value: "admin",
|
|
2074
|
-
label: "Admin",
|
|
2075
|
-
description: "Full admin access"
|
|
2076
|
-
}
|
|
2077
|
-
];
|
|
2042
|
+
/**
|
|
2043
|
+
* Scope strings for personal API tokens (wire + UI iteration order).
|
|
2044
|
+
* Human-readable copy lives in `ApiTokenSettings` (`SCOPE_UI` + Lingui).
|
|
2045
|
+
*/
|
|
2046
|
+
const API_TOKEN_SCOPES = {
|
|
2047
|
+
ContentRead: "content:read",
|
|
2048
|
+
ContentWrite: "content:write",
|
|
2049
|
+
MediaRead: "media:read",
|
|
2050
|
+
MediaWrite: "media:write",
|
|
2051
|
+
SchemaRead: "schema:read",
|
|
2052
|
+
SchemaWrite: "schema:write",
|
|
2053
|
+
Admin: "admin"
|
|
2054
|
+
};
|
|
2078
2055
|
/**
|
|
2079
2056
|
* Fetch all API tokens for the current user
|
|
2080
2057
|
*/
|
|
@@ -4370,7 +4347,10 @@ var index_default = Suggestion;
|
|
|
4370
4347
|
const blockTransforms = [
|
|
4371
4348
|
{
|
|
4372
4349
|
id: "paragraph",
|
|
4373
|
-
label:
|
|
4350
|
+
label: {
|
|
4351
|
+
id: "bkQRMh",
|
|
4352
|
+
message: "Paragraph"
|
|
4353
|
+
},
|
|
4374
4354
|
icon: Paragraph,
|
|
4375
4355
|
transform: (editor) => {
|
|
4376
4356
|
editor.chain().focus().setNode("paragraph").run();
|
|
@@ -4378,7 +4358,10 @@ const blockTransforms = [
|
|
|
4378
4358
|
},
|
|
4379
4359
|
{
|
|
4380
4360
|
id: "heading1",
|
|
4381
|
-
label:
|
|
4361
|
+
label: {
|
|
4362
|
+
id: "lXKZGw",
|
|
4363
|
+
message: "Heading 1"
|
|
4364
|
+
},
|
|
4382
4365
|
icon: TextHOne,
|
|
4383
4366
|
transform: (editor) => {
|
|
4384
4367
|
editor.chain().focus().setNode("heading", { level: 1 }).run();
|
|
@@ -4386,7 +4369,10 @@ const blockTransforms = [
|
|
|
4386
4369
|
},
|
|
4387
4370
|
{
|
|
4388
4371
|
id: "heading2",
|
|
4389
|
-
label:
|
|
4372
|
+
label: {
|
|
4373
|
+
id: "El7NbA",
|
|
4374
|
+
message: "Heading 2"
|
|
4375
|
+
},
|
|
4390
4376
|
icon: TextHTwo,
|
|
4391
4377
|
transform: (editor) => {
|
|
4392
4378
|
editor.chain().focus().setNode("heading", { level: 2 }).run();
|
|
@@ -4394,7 +4380,10 @@ const blockTransforms = [
|
|
|
4394
4380
|
},
|
|
4395
4381
|
{
|
|
4396
4382
|
id: "heading3",
|
|
4397
|
-
label:
|
|
4383
|
+
label: {
|
|
4384
|
+
id: "SFN6dN",
|
|
4385
|
+
message: "Heading 3"
|
|
4386
|
+
},
|
|
4398
4387
|
icon: TextHThree,
|
|
4399
4388
|
transform: (editor) => {
|
|
4400
4389
|
editor.chain().focus().setNode("heading", { level: 3 }).run();
|
|
@@ -4402,7 +4391,10 @@ const blockTransforms = [
|
|
|
4402
4391
|
},
|
|
4403
4392
|
{
|
|
4404
4393
|
id: "blockquote",
|
|
4405
|
-
label:
|
|
4394
|
+
label: {
|
|
4395
|
+
id: "ZhhOwV",
|
|
4396
|
+
message: "Quote"
|
|
4397
|
+
},
|
|
4406
4398
|
icon: Quotes,
|
|
4407
4399
|
transform: (editor) => {
|
|
4408
4400
|
editor.chain().focus().toggleBlockquote().run();
|
|
@@ -4410,7 +4402,10 @@ const blockTransforms = [
|
|
|
4410
4402
|
},
|
|
4411
4403
|
{
|
|
4412
4404
|
id: "codeBlock",
|
|
4413
|
-
label:
|
|
4405
|
+
label: {
|
|
4406
|
+
id: "N2eHWq",
|
|
4407
|
+
message: "Code Block"
|
|
4408
|
+
},
|
|
4414
4409
|
icon: Code,
|
|
4415
4410
|
transform: (editor) => {
|
|
4416
4411
|
editor.chain().focus().toggleCodeBlock().run();
|
|
@@ -4418,7 +4413,10 @@ const blockTransforms = [
|
|
|
4418
4413
|
},
|
|
4419
4414
|
{
|
|
4420
4415
|
id: "bulletList",
|
|
4421
|
-
label:
|
|
4416
|
+
label: {
|
|
4417
|
+
id: "s1c0ja",
|
|
4418
|
+
message: "Bullet List"
|
|
4419
|
+
},
|
|
4422
4420
|
icon: List,
|
|
4423
4421
|
transform: (editor) => {
|
|
4424
4422
|
editor.chain().focus().toggleBulletList().run();
|
|
@@ -4426,7 +4424,10 @@ const blockTransforms = [
|
|
|
4426
4424
|
},
|
|
4427
4425
|
{
|
|
4428
4426
|
id: "orderedList",
|
|
4429
|
-
label:
|
|
4427
|
+
label: {
|
|
4428
|
+
id: "upFPtm",
|
|
4429
|
+
message: "Numbered List"
|
|
4430
|
+
},
|
|
4430
4431
|
icon: ListNumbers,
|
|
4431
4432
|
transform: (editor) => {
|
|
4432
4433
|
editor.chain().focus().toggleOrderedList().run();
|
|
@@ -4437,6 +4438,7 @@ const blockTransforms = [
|
|
|
4437
4438
|
* Block Menu - floating menu for block-level actions
|
|
4438
4439
|
*/
|
|
4439
4440
|
function BlockMenu({ editor, anchorElement, isOpen, onClose }) {
|
|
4441
|
+
const { _: _t } = useLingui();
|
|
4440
4442
|
const [showTransforms, setShowTransforms] = React.useState(false);
|
|
4441
4443
|
const menuRef = React.useRef(null);
|
|
4442
4444
|
const stableOnClose = useStableCallback(onClose);
|
|
@@ -4533,7 +4535,7 @@ function BlockMenu({ editor, anchorElement, isOpen, onClose }) {
|
|
|
4533
4535
|
type: "button",
|
|
4534
4536
|
className: "flex items-center gap-2 w-full px-3 py-2 text-sm hover:bg-kumo-tint text-left",
|
|
4535
4537
|
onClick: () => handleTransform(transform),
|
|
4536
|
-
children: [/* @__PURE__ */ jsx(transform.icon, { className: "h-4 w-4 text-kumo-subtle" }), /* @__PURE__ */ jsx("span", { children: transform.label })]
|
|
4538
|
+
children: [/* @__PURE__ */ jsx(transform.icon, { className: "h-4 w-4 text-kumo-subtle" }), /* @__PURE__ */ jsx("span", { children: _t(transform.label) })]
|
|
4537
4539
|
}, transform.id))
|
|
4538
4540
|
]
|
|
4539
4541
|
}) : /* @__PURE__ */ jsxs("div", {
|
|
@@ -5778,8 +5780,14 @@ function convertPTMarks(marks, markDefs) {
|
|
|
5778
5780
|
const defaultSlashCommands = [
|
|
5779
5781
|
{
|
|
5780
5782
|
id: "heading1",
|
|
5781
|
-
title:
|
|
5782
|
-
|
|
5783
|
+
title: {
|
|
5784
|
+
id: "lXKZGw",
|
|
5785
|
+
message: "Heading 1"
|
|
5786
|
+
},
|
|
5787
|
+
description: {
|
|
5788
|
+
id: "59o/ag",
|
|
5789
|
+
message: "Large section heading"
|
|
5790
|
+
},
|
|
5783
5791
|
icon: TextHOne,
|
|
5784
5792
|
aliases: ["h1", "title"],
|
|
5785
5793
|
command: ({ editor, range }) => {
|
|
@@ -5788,8 +5796,14 @@ const defaultSlashCommands = [
|
|
|
5788
5796
|
},
|
|
5789
5797
|
{
|
|
5790
5798
|
id: "heading2",
|
|
5791
|
-
title:
|
|
5792
|
-
|
|
5799
|
+
title: {
|
|
5800
|
+
id: "El7NbA",
|
|
5801
|
+
message: "Heading 2"
|
|
5802
|
+
},
|
|
5803
|
+
description: {
|
|
5804
|
+
id: "IAcjOi",
|
|
5805
|
+
message: "Medium section heading"
|
|
5806
|
+
},
|
|
5793
5807
|
icon: TextHTwo,
|
|
5794
5808
|
aliases: ["h2", "subtitle"],
|
|
5795
5809
|
command: ({ editor, range }) => {
|
|
@@ -5798,8 +5812,14 @@ const defaultSlashCommands = [
|
|
|
5798
5812
|
},
|
|
5799
5813
|
{
|
|
5800
5814
|
id: "heading3",
|
|
5801
|
-
title:
|
|
5802
|
-
|
|
5815
|
+
title: {
|
|
5816
|
+
id: "SFN6dN",
|
|
5817
|
+
message: "Heading 3"
|
|
5818
|
+
},
|
|
5819
|
+
description: {
|
|
5820
|
+
id: "Ik7fz5",
|
|
5821
|
+
message: "Small section heading"
|
|
5822
|
+
},
|
|
5803
5823
|
icon: TextHThree,
|
|
5804
5824
|
aliases: ["h3"],
|
|
5805
5825
|
command: ({ editor, range }) => {
|
|
@@ -5808,8 +5828,14 @@ const defaultSlashCommands = [
|
|
|
5808
5828
|
},
|
|
5809
5829
|
{
|
|
5810
5830
|
id: "bulletList",
|
|
5811
|
-
title:
|
|
5812
|
-
|
|
5831
|
+
title: {
|
|
5832
|
+
id: "s1c0ja",
|
|
5833
|
+
message: "Bullet List"
|
|
5834
|
+
},
|
|
5835
|
+
description: {
|
|
5836
|
+
id: "md7u2X",
|
|
5837
|
+
message: "Create a bullet list"
|
|
5838
|
+
},
|
|
5813
5839
|
icon: List,
|
|
5814
5840
|
aliases: ["ul", "unordered"],
|
|
5815
5841
|
command: ({ editor, range }) => {
|
|
@@ -5818,8 +5844,14 @@ const defaultSlashCommands = [
|
|
|
5818
5844
|
},
|
|
5819
5845
|
{
|
|
5820
5846
|
id: "numberedList",
|
|
5821
|
-
title:
|
|
5822
|
-
|
|
5847
|
+
title: {
|
|
5848
|
+
id: "upFPtm",
|
|
5849
|
+
message: "Numbered List"
|
|
5850
|
+
},
|
|
5851
|
+
description: {
|
|
5852
|
+
id: "fh33rM",
|
|
5853
|
+
message: "Create a numbered list"
|
|
5854
|
+
},
|
|
5823
5855
|
icon: ListNumbers,
|
|
5824
5856
|
aliases: ["ol", "ordered"],
|
|
5825
5857
|
command: ({ editor, range }) => {
|
|
@@ -5828,8 +5860,14 @@ const defaultSlashCommands = [
|
|
|
5828
5860
|
},
|
|
5829
5861
|
{
|
|
5830
5862
|
id: "quote",
|
|
5831
|
-
title:
|
|
5832
|
-
|
|
5863
|
+
title: {
|
|
5864
|
+
id: "ZhhOwV",
|
|
5865
|
+
message: "Quote"
|
|
5866
|
+
},
|
|
5867
|
+
description: {
|
|
5868
|
+
id: "l+2nGM",
|
|
5869
|
+
message: "Insert a blockquote"
|
|
5870
|
+
},
|
|
5833
5871
|
icon: Quotes,
|
|
5834
5872
|
aliases: ["blockquote", "cite"],
|
|
5835
5873
|
command: ({ editor, range }) => {
|
|
@@ -5838,8 +5876,14 @@ const defaultSlashCommands = [
|
|
|
5838
5876
|
},
|
|
5839
5877
|
{
|
|
5840
5878
|
id: "codeBlock",
|
|
5841
|
-
title:
|
|
5842
|
-
|
|
5879
|
+
title: {
|
|
5880
|
+
id: "N2eHWq",
|
|
5881
|
+
message: "Code Block"
|
|
5882
|
+
},
|
|
5883
|
+
description: {
|
|
5884
|
+
id: "12gVka",
|
|
5885
|
+
message: "Insert a code block"
|
|
5886
|
+
},
|
|
5843
5887
|
icon: CodeBlock,
|
|
5844
5888
|
aliases: [
|
|
5845
5889
|
"code",
|
|
@@ -5852,8 +5896,14 @@ const defaultSlashCommands = [
|
|
|
5852
5896
|
},
|
|
5853
5897
|
{
|
|
5854
5898
|
id: "divider",
|
|
5855
|
-
title:
|
|
5856
|
-
|
|
5899
|
+
title: {
|
|
5900
|
+
id: "R8AthW",
|
|
5901
|
+
message: "Divider"
|
|
5902
|
+
},
|
|
5903
|
+
description: {
|
|
5904
|
+
id: "9Jd2n5",
|
|
5905
|
+
message: "Insert a horizontal rule"
|
|
5906
|
+
},
|
|
5857
5907
|
icon: Minus,
|
|
5858
5908
|
aliases: [
|
|
5859
5909
|
"hr",
|
|
@@ -5962,6 +6012,7 @@ function createSlashCommandsExtension(options) {
|
|
|
5962
6012
|
* Slash command menu component using Floating UI
|
|
5963
6013
|
*/
|
|
5964
6014
|
function SlashCommandMenu({ state, onCommand, onClose: _onClose, setSelectedIndex }) {
|
|
6015
|
+
const { _: _t } = useLingui();
|
|
5965
6016
|
const containerRef = React.useRef(null);
|
|
5966
6017
|
const { refs, floatingStyles } = useFloating({
|
|
5967
6018
|
open: state.isOpen,
|
|
@@ -5996,7 +6047,10 @@ function SlashCommandMenu({ state, onCommand, onClose: _onClose, setSelectedInde
|
|
|
5996
6047
|
className: "z-[100] rounded-lg border bg-kumo-overlay p-1 shadow-lg min-w-[220px] max-h-[300px] overflow-y-auto",
|
|
5997
6048
|
children: state.items.length === 0 ? /* @__PURE__ */ jsx("p", {
|
|
5998
6049
|
className: "text-sm text-kumo-subtle px-3 py-2",
|
|
5999
|
-
children:
|
|
6050
|
+
children: _t({
|
|
6051
|
+
id: "Ev2r9A",
|
|
6052
|
+
message: "No results"
|
|
6053
|
+
})
|
|
6000
6054
|
}) : state.items.map((item, index) => /* @__PURE__ */ jsxs("button", {
|
|
6001
6055
|
type: "button",
|
|
6002
6056
|
"data-index": index,
|
|
@@ -6007,10 +6061,10 @@ function SlashCommandMenu({ state, onCommand, onClose: _onClose, setSelectedInde
|
|
|
6007
6061
|
className: "flex flex-col",
|
|
6008
6062
|
children: [/* @__PURE__ */ jsx("span", {
|
|
6009
6063
|
className: "font-medium",
|
|
6010
|
-
children: item.title
|
|
6064
|
+
children: typeof item.title === "string" ? item.title : _t(item.title)
|
|
6011
6065
|
}), /* @__PURE__ */ jsx("span", {
|
|
6012
6066
|
className: "text-xs text-kumo-subtle",
|
|
6013
|
-
children: item.description
|
|
6067
|
+
children: typeof item.description === "string" ? item.description : _t(item.description)
|
|
6014
6068
|
})]
|
|
6015
6069
|
})]
|
|
6016
6070
|
}, item.id))
|
|
@@ -6271,6 +6325,7 @@ function EditorFooter({ editor }) {
|
|
|
6271
6325
|
* Portable Text Editor Component
|
|
6272
6326
|
*/
|
|
6273
6327
|
function PortableTextEditor({ value, onChange, placeholder = "Start writing...", className, editable = true, "aria-labelledby": ariaLabelledby, pluginBlocks = [], focusMode: controlledFocusMode, onFocusModeChange, onEditorReady, minimal = false, onBlockSidebarOpen, onBlockSidebarClose }) {
|
|
6328
|
+
const { _: _t2 } = useLingui();
|
|
6274
6329
|
const onChangeRef = React.useRef(onChange);
|
|
6275
6330
|
React.useEffect(() => {
|
|
6276
6331
|
onChangeRef.current = onChange;
|
|
@@ -6302,8 +6357,14 @@ function PortableTextEditor({ value, onChange, placeholder = "Start writing...",
|
|
|
6302
6357
|
const cmds = [...defaultSlashCommands];
|
|
6303
6358
|
cmds.push({
|
|
6304
6359
|
id: "image",
|
|
6305
|
-
title:
|
|
6306
|
-
|
|
6360
|
+
title: {
|
|
6361
|
+
id: "hG89Ed",
|
|
6362
|
+
message: "Image"
|
|
6363
|
+
},
|
|
6364
|
+
description: {
|
|
6365
|
+
id: "3Lcj6W",
|
|
6366
|
+
message: "Insert an image"
|
|
6367
|
+
},
|
|
6307
6368
|
icon: Image$1,
|
|
6308
6369
|
aliases: [
|
|
6309
6370
|
"img",
|
|
@@ -6311,7 +6372,10 @@ function PortableTextEditor({ value, onChange, placeholder = "Start writing...",
|
|
|
6311
6372
|
"picture",
|
|
6312
6373
|
"url"
|
|
6313
6374
|
],
|
|
6314
|
-
category:
|
|
6375
|
+
category: {
|
|
6376
|
+
id: "xYilR2",
|
|
6377
|
+
message: "Media"
|
|
6378
|
+
},
|
|
6315
6379
|
command: ({ editor, range }) => {
|
|
6316
6380
|
editor.chain().focus().deleteRange(range).run();
|
|
6317
6381
|
setMediaPickerOpen(true);
|
|
@@ -6319,15 +6383,24 @@ function PortableTextEditor({ value, onChange, placeholder = "Start writing...",
|
|
|
6319
6383
|
});
|
|
6320
6384
|
cmds.push({
|
|
6321
6385
|
id: "section",
|
|
6322
|
-
title:
|
|
6323
|
-
|
|
6386
|
+
title: {
|
|
6387
|
+
id: "BhZ5PL",
|
|
6388
|
+
message: "Section"
|
|
6389
|
+
},
|
|
6390
|
+
description: {
|
|
6391
|
+
id: "Pkleyv",
|
|
6392
|
+
message: "Insert a reusable section"
|
|
6393
|
+
},
|
|
6324
6394
|
icon: Stack,
|
|
6325
6395
|
aliases: [
|
|
6326
6396
|
"pattern",
|
|
6327
6397
|
"block",
|
|
6328
6398
|
"template"
|
|
6329
6399
|
],
|
|
6330
|
-
category:
|
|
6400
|
+
category: {
|
|
6401
|
+
id: "4b3oEV",
|
|
6402
|
+
message: "Content"
|
|
6403
|
+
},
|
|
6331
6404
|
command: ({ editor, range }) => {
|
|
6332
6405
|
editor.chain().focus().deleteRange(range).run();
|
|
6333
6406
|
setSectionPickerOpen(true);
|
|
@@ -6336,25 +6409,36 @@ function PortableTextEditor({ value, onChange, placeholder = "Start writing...",
|
|
|
6336
6409
|
for (const block of pluginBlocks) cmds.push({
|
|
6337
6410
|
id: `plugin-${block.pluginId}-${block.type}`,
|
|
6338
6411
|
title: block.label,
|
|
6339
|
-
description: block.description
|
|
6412
|
+
description: block.description ?? _t2({
|
|
6413
|
+
id: "g0zqOw",
|
|
6414
|
+
message: "Embed a {0}",
|
|
6415
|
+
values: { 0: block.label }
|
|
6416
|
+
}),
|
|
6340
6417
|
icon: resolveIcon(block.icon),
|
|
6341
6418
|
aliases: [block.type],
|
|
6342
|
-
category:
|
|
6419
|
+
category: {
|
|
6420
|
+
id: "aTofd0",
|
|
6421
|
+
message: "Embeds"
|
|
6422
|
+
},
|
|
6343
6423
|
command: ({ editor, range }) => {
|
|
6344
6424
|
editor.chain().focus().deleteRange(range).run();
|
|
6345
6425
|
setPluginBlockModal(block);
|
|
6346
6426
|
}
|
|
6347
6427
|
});
|
|
6348
6428
|
return cmds;
|
|
6349
|
-
}, [pluginBlocks]);
|
|
6429
|
+
}, [pluginBlocks, _t2]);
|
|
6350
6430
|
const filterCommandsRef = React.useRef((_q) => []);
|
|
6351
6431
|
filterCommandsRef.current = (query) => {
|
|
6352
6432
|
if (!query) return slashCommands;
|
|
6353
6433
|
const searchText = query.toLowerCase();
|
|
6354
6434
|
const titleMatches = [];
|
|
6355
6435
|
const otherMatches = [];
|
|
6356
|
-
for (const item of slashCommands)
|
|
6357
|
-
|
|
6436
|
+
for (const item of slashCommands) {
|
|
6437
|
+
const titleStr = typeof item.title === "string" ? item.title : _t2(item.title);
|
|
6438
|
+
const descStr = typeof item.description === "string" ? item.description : _t2(item.description);
|
|
6439
|
+
if (titleStr.toLowerCase().includes(searchText)) titleMatches.push(item);
|
|
6440
|
+
else if (descStr.toLowerCase().includes(searchText) || item.aliases?.some((alias) => alias.toLowerCase().includes(searchText))) otherMatches.push(item);
|
|
6441
|
+
}
|
|
6358
6442
|
return [...titleMatches, ...otherMatches];
|
|
6359
6443
|
};
|
|
6360
6444
|
const initialContent = React.useMemo(() => portableTextToProsemirror(value || []), []);
|
|
@@ -10128,71 +10212,128 @@ const SLUG_LEADING_TRAILING_PATTERN = /^_|_$/g;
|
|
|
10128
10212
|
const SUPPORT_OPTIONS = [
|
|
10129
10213
|
{
|
|
10130
10214
|
value: "drafts",
|
|
10131
|
-
label:
|
|
10132
|
-
|
|
10215
|
+
label: {
|
|
10216
|
+
id: "M8kJqa",
|
|
10217
|
+
message: "Drafts"
|
|
10218
|
+
},
|
|
10219
|
+
description: {
|
|
10220
|
+
id: "ZpP0HR",
|
|
10221
|
+
message: "Save content as draft before publishing"
|
|
10222
|
+
}
|
|
10133
10223
|
},
|
|
10134
10224
|
{
|
|
10135
10225
|
value: "revisions",
|
|
10136
|
-
label:
|
|
10137
|
-
|
|
10226
|
+
label: {
|
|
10227
|
+
id: "ZdWn/b",
|
|
10228
|
+
message: "Revisions"
|
|
10229
|
+
},
|
|
10230
|
+
description: {
|
|
10231
|
+
id: "9kGBt9",
|
|
10232
|
+
message: "Track content history"
|
|
10233
|
+
}
|
|
10138
10234
|
},
|
|
10139
10235
|
{
|
|
10140
10236
|
value: "preview",
|
|
10141
|
-
label:
|
|
10142
|
-
|
|
10237
|
+
label: {
|
|
10238
|
+
id: "rdUucN",
|
|
10239
|
+
message: "Preview"
|
|
10240
|
+
},
|
|
10241
|
+
description: {
|
|
10242
|
+
id: "KRB02E",
|
|
10243
|
+
message: "Preview content before publishing"
|
|
10244
|
+
}
|
|
10143
10245
|
},
|
|
10144
10246
|
{
|
|
10145
10247
|
value: "search",
|
|
10146
|
-
label:
|
|
10147
|
-
|
|
10248
|
+
label: {
|
|
10249
|
+
id: "A1taO8",
|
|
10250
|
+
message: "Search"
|
|
10251
|
+
},
|
|
10252
|
+
description: {
|
|
10253
|
+
id: "T7NoTE",
|
|
10254
|
+
message: "Enable full-text search on this collection"
|
|
10255
|
+
}
|
|
10148
10256
|
}
|
|
10149
10257
|
];
|
|
10150
|
-
/**
|
|
10151
|
-
* System fields that exist on every collection
|
|
10152
|
-
* These are created automatically and cannot be modified
|
|
10153
|
-
*/
|
|
10154
10258
|
const SYSTEM_FIELDS = [
|
|
10155
10259
|
{
|
|
10156
10260
|
slug: "id",
|
|
10157
|
-
label:
|
|
10261
|
+
label: {
|
|
10262
|
+
id: "S0kLOH",
|
|
10263
|
+
message: "ID"
|
|
10264
|
+
},
|
|
10158
10265
|
type: "text",
|
|
10159
|
-
description:
|
|
10266
|
+
description: {
|
|
10267
|
+
id: "PUk2oG",
|
|
10268
|
+
message: "Unique identifier (ULID)"
|
|
10269
|
+
}
|
|
10160
10270
|
},
|
|
10161
10271
|
{
|
|
10162
10272
|
slug: "slug",
|
|
10163
|
-
label:
|
|
10273
|
+
label: {
|
|
10274
|
+
id: "L85WcV",
|
|
10275
|
+
message: "Slug"
|
|
10276
|
+
},
|
|
10164
10277
|
type: "text",
|
|
10165
|
-
description:
|
|
10278
|
+
description: {
|
|
10279
|
+
id: "f0WSdD",
|
|
10280
|
+
message: "URL-friendly identifier"
|
|
10281
|
+
}
|
|
10166
10282
|
},
|
|
10167
10283
|
{
|
|
10168
10284
|
slug: "status",
|
|
10169
|
-
label:
|
|
10285
|
+
label: {
|
|
10286
|
+
id: "uAQUqI",
|
|
10287
|
+
message: "Status"
|
|
10288
|
+
},
|
|
10170
10289
|
type: "text",
|
|
10171
|
-
description:
|
|
10290
|
+
description: {
|
|
10291
|
+
id: "khtYSH",
|
|
10292
|
+
message: "draft, published, or archived"
|
|
10293
|
+
}
|
|
10172
10294
|
},
|
|
10173
10295
|
{
|
|
10174
10296
|
slug: "created_at",
|
|
10175
|
-
label:
|
|
10297
|
+
label: {
|
|
10298
|
+
id: "88kg0+",
|
|
10299
|
+
message: "Created At"
|
|
10300
|
+
},
|
|
10176
10301
|
type: "datetime",
|
|
10177
|
-
description:
|
|
10302
|
+
description: {
|
|
10303
|
+
id: "SMcuRW",
|
|
10304
|
+
message: "When the entry was created"
|
|
10305
|
+
}
|
|
10178
10306
|
},
|
|
10179
10307
|
{
|
|
10180
10308
|
slug: "updated_at",
|
|
10181
|
-
label:
|
|
10309
|
+
label: {
|
|
10310
|
+
id: "Llcakz",
|
|
10311
|
+
message: "Updated At"
|
|
10312
|
+
},
|
|
10182
10313
|
type: "datetime",
|
|
10183
|
-
description:
|
|
10314
|
+
description: {
|
|
10315
|
+
id: "46AzZK",
|
|
10316
|
+
message: "When the entry was last modified"
|
|
10317
|
+
}
|
|
10184
10318
|
},
|
|
10185
10319
|
{
|
|
10186
10320
|
slug: "published_at",
|
|
10187
|
-
label:
|
|
10321
|
+
label: {
|
|
10322
|
+
id: "6QwXHP",
|
|
10323
|
+
message: "Published At"
|
|
10324
|
+
},
|
|
10188
10325
|
type: "datetime",
|
|
10189
|
-
description:
|
|
10326
|
+
description: {
|
|
10327
|
+
id: "MRpwV3",
|
|
10328
|
+
message: "When the entry was published"
|
|
10329
|
+
}
|
|
10190
10330
|
}
|
|
10191
10331
|
];
|
|
10192
10332
|
/**
|
|
10193
10333
|
* Content Type editor for creating/editing collections
|
|
10194
10334
|
*/
|
|
10195
10335
|
function ContentTypeEditor({ collection, isNew, isSaving, onSave, onAddField, onUpdateField, onDeleteField, onReorderFields }) {
|
|
10336
|
+
const { _: _t } = useLingui();
|
|
10196
10337
|
useNavigate$1();
|
|
10197
10338
|
const [slug, setSlug] = React.useState(collection?.slug ?? "");
|
|
10198
10339
|
const [label, setLabel] = React.useState(collection?.label ?? "");
|
|
@@ -10415,10 +10556,10 @@ function ContentTypeEditor({ collection, isNew, isSaving, onSave, onAddField, on
|
|
|
10415
10556
|
disabled: isFromCode
|
|
10416
10557
|
}), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("span", {
|
|
10417
10558
|
className: "text-sm font-medium",
|
|
10418
|
-
children: option.label
|
|
10559
|
+
children: _t(option.label)
|
|
10419
10560
|
}), /* @__PURE__ */ jsx("p", {
|
|
10420
10561
|
className: "text-xs text-kumo-subtle",
|
|
10421
|
-
children: option.description
|
|
10562
|
+
children: _t(option.description)
|
|
10422
10563
|
})] })]
|
|
10423
10564
|
}, option.value))]
|
|
10424
10565
|
}),
|
|
@@ -10698,6 +10839,7 @@ function FieldRow({ field, isFromCode, onEdit, onDelete }) {
|
|
|
10698
10839
|
});
|
|
10699
10840
|
}
|
|
10700
10841
|
function SystemFieldRow({ field }) {
|
|
10842
|
+
const { _: _t2 } = useLingui();
|
|
10701
10843
|
return /* @__PURE__ */ jsxs("div", {
|
|
10702
10844
|
className: "flex items-center px-4 py-2 opacity-75",
|
|
10703
10845
|
children: [
|
|
@@ -10710,7 +10852,7 @@ function SystemFieldRow({ field }) {
|
|
|
10710
10852
|
children: [
|
|
10711
10853
|
/* @__PURE__ */ jsx("span", {
|
|
10712
10854
|
className: "font-medium text-sm",
|
|
10713
|
-
children: field.label
|
|
10855
|
+
children: _t2(field.label)
|
|
10714
10856
|
}),
|
|
10715
10857
|
/* @__PURE__ */ jsx("code", {
|
|
10716
10858
|
className: "text-xs bg-kumo-tint px-1.5 py-0.5 rounded text-kumo-subtle",
|
|
@@ -10723,7 +10865,7 @@ function SystemFieldRow({ field }) {
|
|
|
10723
10865
|
]
|
|
10724
10866
|
}), /* @__PURE__ */ jsx("p", {
|
|
10725
10867
|
className: "text-xs text-kumo-subtle mt-0.5",
|
|
10726
|
-
children: field.description
|
|
10868
|
+
children: _t2(field.description)
|
|
10727
10869
|
})]
|
|
10728
10870
|
})
|
|
10729
10871
|
]
|
|
@@ -15620,6 +15762,7 @@ function Redirects() {
|
|
|
15620
15762
|
setTab("redirects");
|
|
15621
15763
|
}
|
|
15622
15764
|
const redirects = redirectsQuery.data?.items ?? [];
|
|
15765
|
+
const loopRedirectIds = new Set(redirectsQuery.data?.loopRedirectIds ?? []);
|
|
15623
15766
|
return /* @__PURE__ */ jsxs("div", {
|
|
15624
15767
|
className: "space-y-6",
|
|
15625
15768
|
children: [
|
|
@@ -15653,173 +15796,208 @@ function Redirects() {
|
|
|
15653
15796
|
children: "404 Errors"
|
|
15654
15797
|
})]
|
|
15655
15798
|
}),
|
|
15656
|
-
tab === "redirects" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
15657
|
-
|
|
15658
|
-
|
|
15659
|
-
/* @__PURE__ */ jsxs("div", {
|
|
15660
|
-
className: "relative flex-1 max-w-md",
|
|
15661
|
-
children: [/* @__PURE__ */ jsx(MagnifyingGlass, {
|
|
15662
|
-
className: "absolute left-3 top-1/2 -translate-y-1/2 text-kumo-subtle",
|
|
15663
|
-
size: 16
|
|
15664
|
-
}), /* @__PURE__ */ jsx(Input, {
|
|
15665
|
-
placeholder: "Search source or destination...",
|
|
15666
|
-
className: "pl-10",
|
|
15667
|
-
value: search,
|
|
15668
|
-
onChange: (e) => setSearch(e.target.value)
|
|
15669
|
-
})]
|
|
15670
|
-
}),
|
|
15671
|
-
/* @__PURE__ */ jsxs("select", {
|
|
15672
|
-
value: filterEnabled,
|
|
15673
|
-
onChange: (e) => setFilterEnabled(e.target.value),
|
|
15674
|
-
className: "h-10 rounded-md border border-kumo-line bg-kumo-base px-3 text-sm",
|
|
15675
|
-
children: [
|
|
15676
|
-
/* @__PURE__ */ jsx("option", {
|
|
15677
|
-
value: "all",
|
|
15678
|
-
children: "All statuses"
|
|
15679
|
-
}),
|
|
15680
|
-
/* @__PURE__ */ jsx("option", {
|
|
15681
|
-
value: "true",
|
|
15682
|
-
children: "Enabled"
|
|
15683
|
-
}),
|
|
15684
|
-
/* @__PURE__ */ jsx("option", {
|
|
15685
|
-
value: "false",
|
|
15686
|
-
children: "Disabled"
|
|
15687
|
-
})
|
|
15688
|
-
]
|
|
15689
|
-
}),
|
|
15690
|
-
/* @__PURE__ */ jsxs("select", {
|
|
15691
|
-
value: filterAuto,
|
|
15692
|
-
onChange: (e) => setFilterAuto(e.target.value),
|
|
15693
|
-
className: "h-10 rounded-md border border-kumo-line bg-kumo-base px-3 text-sm",
|
|
15694
|
-
children: [
|
|
15695
|
-
/* @__PURE__ */ jsx("option", {
|
|
15696
|
-
value: "all",
|
|
15697
|
-
children: "All types"
|
|
15698
|
-
}),
|
|
15699
|
-
/* @__PURE__ */ jsx("option", {
|
|
15700
|
-
value: "false",
|
|
15701
|
-
children: "Manual"
|
|
15702
|
-
}),
|
|
15703
|
-
/* @__PURE__ */ jsx("option", {
|
|
15704
|
-
value: "true",
|
|
15705
|
-
children: "Auto (slug change)"
|
|
15706
|
-
})
|
|
15707
|
-
]
|
|
15708
|
-
})
|
|
15709
|
-
]
|
|
15710
|
-
}), redirectsQuery.isLoading ? /* @__PURE__ */ jsx("div", {
|
|
15711
|
-
className: "py-12 text-center text-kumo-subtle",
|
|
15712
|
-
children: "Loading redirects..."
|
|
15713
|
-
}) : redirects.length === 0 ? /* @__PURE__ */ jsxs("div", {
|
|
15714
|
-
className: "py-12 text-center text-kumo-subtle",
|
|
15715
|
-
children: [
|
|
15716
|
-
/* @__PURE__ */ jsx(ArrowsLeftRight, {
|
|
15717
|
-
size: 48,
|
|
15718
|
-
className: "mx-auto mb-4 opacity-30"
|
|
15719
|
-
}),
|
|
15720
|
-
/* @__PURE__ */ jsx("p", {
|
|
15721
|
-
className: "text-lg font-medium",
|
|
15722
|
-
children: "No redirects yet"
|
|
15723
|
-
}),
|
|
15724
|
-
/* @__PURE__ */ jsx("p", {
|
|
15725
|
-
className: "text-sm mt-1",
|
|
15726
|
-
children: "Create redirect rules to manage URL changes."
|
|
15727
|
-
})
|
|
15728
|
-
]
|
|
15729
|
-
}) : /* @__PURE__ */ jsxs("div", {
|
|
15730
|
-
className: "border rounded-lg",
|
|
15731
|
-
children: [/* @__PURE__ */ jsxs("div", {
|
|
15732
|
-
className: "flex items-center gap-4 py-2 px-4 border-b bg-kumo-tint/50 text-sm font-medium text-kumo-subtle",
|
|
15733
|
-
children: [
|
|
15734
|
-
/* @__PURE__ */ jsx("div", {
|
|
15735
|
-
className: "flex-1",
|
|
15736
|
-
children: "Source"
|
|
15737
|
-
}),
|
|
15738
|
-
/* @__PURE__ */ jsx("div", { className: "w-8 text-center" }),
|
|
15739
|
-
/* @__PURE__ */ jsx("div", {
|
|
15740
|
-
className: "flex-1",
|
|
15741
|
-
children: "Destination"
|
|
15742
|
-
}),
|
|
15743
|
-
/* @__PURE__ */ jsx("div", {
|
|
15744
|
-
className: "w-14 text-center",
|
|
15745
|
-
children: "Code"
|
|
15746
|
-
}),
|
|
15747
|
-
/* @__PURE__ */ jsx("div", {
|
|
15748
|
-
className: "w-16 text-right",
|
|
15749
|
-
children: "Hits"
|
|
15750
|
-
}),
|
|
15751
|
-
/* @__PURE__ */ jsx("div", {
|
|
15752
|
-
className: "w-20 text-center",
|
|
15753
|
-
children: "Status"
|
|
15754
|
-
}),
|
|
15755
|
-
/* @__PURE__ */ jsx("div", { className: "w-20" })
|
|
15756
|
-
]
|
|
15757
|
-
}), redirects.map((r) => /* @__PURE__ */ jsxs("div", {
|
|
15758
|
-
className: cn("flex items-center gap-4 py-2 px-4 border-b last:border-0 text-sm", !r.enabled && "opacity-50"),
|
|
15799
|
+
tab === "redirects" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
15800
|
+
/* @__PURE__ */ jsxs("div", {
|
|
15801
|
+
className: "flex items-center gap-4",
|
|
15759
15802
|
children: [
|
|
15760
|
-
/* @__PURE__ */
|
|
15761
|
-
className: "flex-1
|
|
15762
|
-
|
|
15763
|
-
|
|
15764
|
-
|
|
15765
|
-
|
|
15766
|
-
|
|
15767
|
-
|
|
15768
|
-
|
|
15769
|
-
|
|
15770
|
-
|
|
15771
|
-
title: r.destination,
|
|
15772
|
-
children: r.destination
|
|
15773
|
-
}),
|
|
15774
|
-
/* @__PURE__ */ jsx("div", {
|
|
15775
|
-
className: "w-14 text-center",
|
|
15776
|
-
children: /* @__PURE__ */ jsx(Badge, {
|
|
15777
|
-
variant: "secondary",
|
|
15778
|
-
children: r.type
|
|
15779
|
-
})
|
|
15780
|
-
}),
|
|
15781
|
-
/* @__PURE__ */ jsx("div", {
|
|
15782
|
-
className: "w-16 text-right tabular-nums text-kumo-subtle",
|
|
15783
|
-
children: r.hits
|
|
15803
|
+
/* @__PURE__ */ jsxs("div", {
|
|
15804
|
+
className: "relative flex-1 max-w-md",
|
|
15805
|
+
children: [/* @__PURE__ */ jsx(MagnifyingGlass, {
|
|
15806
|
+
className: "absolute left-3 top-1/2 -translate-y-1/2 text-kumo-subtle",
|
|
15807
|
+
size: 16
|
|
15808
|
+
}), /* @__PURE__ */ jsx(Input, {
|
|
15809
|
+
placeholder: "Search source or destination...",
|
|
15810
|
+
className: "pl-10",
|
|
15811
|
+
value: search,
|
|
15812
|
+
onChange: (e) => setSearch(e.target.value)
|
|
15813
|
+
})]
|
|
15784
15814
|
}),
|
|
15785
|
-
/* @__PURE__ */
|
|
15786
|
-
|
|
15787
|
-
|
|
15788
|
-
|
|
15789
|
-
|
|
15790
|
-
|
|
15791
|
-
|
|
15815
|
+
/* @__PURE__ */ jsxs("select", {
|
|
15816
|
+
value: filterEnabled,
|
|
15817
|
+
onChange: (e) => setFilterEnabled(e.target.value),
|
|
15818
|
+
className: "h-10 rounded-md border border-kumo-line bg-kumo-base px-3 text-sm",
|
|
15819
|
+
children: [
|
|
15820
|
+
/* @__PURE__ */ jsx("option", {
|
|
15821
|
+
value: "all",
|
|
15822
|
+
children: "All statuses"
|
|
15792
15823
|
}),
|
|
15793
|
-
|
|
15794
|
-
|
|
15824
|
+
/* @__PURE__ */ jsx("option", {
|
|
15825
|
+
value: "true",
|
|
15826
|
+
children: "Enabled"
|
|
15827
|
+
}),
|
|
15828
|
+
/* @__PURE__ */ jsx("option", {
|
|
15829
|
+
value: "false",
|
|
15830
|
+
children: "Disabled"
|
|
15831
|
+
})
|
|
15832
|
+
]
|
|
15795
15833
|
}),
|
|
15796
|
-
/* @__PURE__ */ jsxs("
|
|
15797
|
-
|
|
15834
|
+
/* @__PURE__ */ jsxs("select", {
|
|
15835
|
+
value: filterAuto,
|
|
15836
|
+
onChange: (e) => setFilterAuto(e.target.value),
|
|
15837
|
+
className: "h-10 rounded-md border border-kumo-line bg-kumo-base px-3 text-sm",
|
|
15798
15838
|
children: [
|
|
15799
|
-
|
|
15800
|
-
|
|
15801
|
-
|
|
15802
|
-
children: "auto"
|
|
15839
|
+
/* @__PURE__ */ jsx("option", {
|
|
15840
|
+
value: "all",
|
|
15841
|
+
children: "All types"
|
|
15803
15842
|
}),
|
|
15804
|
-
/* @__PURE__ */ jsx("
|
|
15805
|
-
|
|
15806
|
-
|
|
15807
|
-
title: "Edit redirect",
|
|
15808
|
-
"aria-label": `Edit redirect ${r.source}`,
|
|
15809
|
-
children: /* @__PURE__ */ jsx(PencilSimple, { size: 14 })
|
|
15843
|
+
/* @__PURE__ */ jsx("option", {
|
|
15844
|
+
value: "false",
|
|
15845
|
+
children: "Manual"
|
|
15810
15846
|
}),
|
|
15811
|
-
/* @__PURE__ */ jsx("
|
|
15812
|
-
|
|
15813
|
-
|
|
15814
|
-
title: "Delete redirect",
|
|
15815
|
-
"aria-label": `Delete redirect ${r.source}`,
|
|
15816
|
-
children: /* @__PURE__ */ jsx(Trash, { size: 14 })
|
|
15847
|
+
/* @__PURE__ */ jsx("option", {
|
|
15848
|
+
value: "true",
|
|
15849
|
+
children: "Auto (slug change)"
|
|
15817
15850
|
})
|
|
15818
15851
|
]
|
|
15819
15852
|
})
|
|
15820
15853
|
]
|
|
15821
|
-
},
|
|
15822
|
-
|
|
15854
|
+
}),
|
|
15855
|
+
loopRedirectIds.size > 0 && /* @__PURE__ */ jsxs("div", {
|
|
15856
|
+
role: "alert",
|
|
15857
|
+
className: "flex items-start gap-3 rounded-lg border border-kumo-warning/50 bg-kumo-warning-tint p-4",
|
|
15858
|
+
children: [/* @__PURE__ */ jsx(WarningCircle, {
|
|
15859
|
+
size: 20,
|
|
15860
|
+
className: "mt-0.5 shrink-0 text-kumo-warning",
|
|
15861
|
+
weight: "fill",
|
|
15862
|
+
"aria-hidden": "true"
|
|
15863
|
+
}), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("p", {
|
|
15864
|
+
className: "text-sm font-medium text-kumo-warning",
|
|
15865
|
+
children: "Redirect loop detected"
|
|
15866
|
+
}), /* @__PURE__ */ jsxs("p", {
|
|
15867
|
+
className: "mt-1 text-sm text-kumo-subtle",
|
|
15868
|
+
children: [
|
|
15869
|
+
loopRedirectIds.size,
|
|
15870
|
+
" ",
|
|
15871
|
+
loopRedirectIds.size === 1 ? "redirect is" : "redirects are",
|
|
15872
|
+
" part of a loop. Visitors hitting these paths will see an error."
|
|
15873
|
+
]
|
|
15874
|
+
})] })]
|
|
15875
|
+
}),
|
|
15876
|
+
redirectsQuery.isLoading ? /* @__PURE__ */ jsx("div", {
|
|
15877
|
+
className: "py-12 text-center text-kumo-subtle",
|
|
15878
|
+
children: "Loading redirects..."
|
|
15879
|
+
}) : redirects.length === 0 ? /* @__PURE__ */ jsxs("div", {
|
|
15880
|
+
className: "py-12 text-center text-kumo-subtle",
|
|
15881
|
+
children: [
|
|
15882
|
+
/* @__PURE__ */ jsx(ArrowsLeftRight, {
|
|
15883
|
+
size: 48,
|
|
15884
|
+
className: "mx-auto mb-4 opacity-30"
|
|
15885
|
+
}),
|
|
15886
|
+
/* @__PURE__ */ jsx("p", {
|
|
15887
|
+
className: "text-lg font-medium",
|
|
15888
|
+
children: "No redirects yet"
|
|
15889
|
+
}),
|
|
15890
|
+
/* @__PURE__ */ jsx("p", {
|
|
15891
|
+
className: "text-sm mt-1",
|
|
15892
|
+
children: "Create redirect rules to manage URL changes."
|
|
15893
|
+
})
|
|
15894
|
+
]
|
|
15895
|
+
}) : /* @__PURE__ */ jsxs("div", {
|
|
15896
|
+
className: "border rounded-lg",
|
|
15897
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
15898
|
+
className: "flex items-center gap-4 py-2 px-4 border-b bg-kumo-tint/50 text-sm font-medium text-kumo-subtle",
|
|
15899
|
+
children: [
|
|
15900
|
+
/* @__PURE__ */ jsx("div", {
|
|
15901
|
+
className: "flex-1",
|
|
15902
|
+
children: "Source"
|
|
15903
|
+
}),
|
|
15904
|
+
/* @__PURE__ */ jsx("div", { className: "w-8 text-center" }),
|
|
15905
|
+
/* @__PURE__ */ jsx("div", {
|
|
15906
|
+
className: "flex-1",
|
|
15907
|
+
children: "Destination"
|
|
15908
|
+
}),
|
|
15909
|
+
/* @__PURE__ */ jsx("div", {
|
|
15910
|
+
className: "w-14 text-center",
|
|
15911
|
+
children: "Code"
|
|
15912
|
+
}),
|
|
15913
|
+
/* @__PURE__ */ jsx("div", {
|
|
15914
|
+
className: "w-16 text-right",
|
|
15915
|
+
children: "Hits"
|
|
15916
|
+
}),
|
|
15917
|
+
/* @__PURE__ */ jsx("div", {
|
|
15918
|
+
className: "w-20 text-center",
|
|
15919
|
+
children: "Status"
|
|
15920
|
+
}),
|
|
15921
|
+
/* @__PURE__ */ jsx("div", { className: "w-20" })
|
|
15922
|
+
]
|
|
15923
|
+
}), redirects.map((r) => /* @__PURE__ */ jsxs("div", {
|
|
15924
|
+
className: cn("flex items-center gap-4 py-2 px-4 border-b last:border-0 text-sm", !r.enabled && "opacity-50"),
|
|
15925
|
+
children: [
|
|
15926
|
+
/* @__PURE__ */ jsx("div", {
|
|
15927
|
+
className: "flex-1 font-mono text-xs truncate",
|
|
15928
|
+
title: r.source,
|
|
15929
|
+
children: r.source
|
|
15930
|
+
}),
|
|
15931
|
+
/* @__PURE__ */ jsx("div", {
|
|
15932
|
+
className: "w-8 text-center text-kumo-subtle",
|
|
15933
|
+
children: /* @__PURE__ */ jsx(ArrowRight, { size: 14 })
|
|
15934
|
+
}),
|
|
15935
|
+
/* @__PURE__ */ jsx("div", {
|
|
15936
|
+
className: "flex-1 font-mono text-xs truncate",
|
|
15937
|
+
title: r.destination,
|
|
15938
|
+
children: r.destination
|
|
15939
|
+
}),
|
|
15940
|
+
/* @__PURE__ */ jsx("div", {
|
|
15941
|
+
className: "w-14 text-center",
|
|
15942
|
+
children: /* @__PURE__ */ jsx(Badge, {
|
|
15943
|
+
variant: "secondary",
|
|
15944
|
+
children: r.type
|
|
15945
|
+
})
|
|
15946
|
+
}),
|
|
15947
|
+
/* @__PURE__ */ jsx("div", {
|
|
15948
|
+
className: "w-16 text-right tabular-nums text-kumo-subtle",
|
|
15949
|
+
children: r.hits
|
|
15950
|
+
}),
|
|
15951
|
+
/* @__PURE__ */ jsx("div", {
|
|
15952
|
+
className: "w-20 text-center",
|
|
15953
|
+
children: /* @__PURE__ */ jsx(Switch, {
|
|
15954
|
+
checked: r.enabled,
|
|
15955
|
+
onCheckedChange: (checked) => toggleMutation.mutate({
|
|
15956
|
+
id: r.id,
|
|
15957
|
+
enabled: checked
|
|
15958
|
+
}),
|
|
15959
|
+
"aria-label": r.enabled ? "Disable redirect" : "Enable redirect"
|
|
15960
|
+
})
|
|
15961
|
+
}),
|
|
15962
|
+
/* @__PURE__ */ jsxs("div", {
|
|
15963
|
+
className: "w-20 flex items-center justify-end gap-1",
|
|
15964
|
+
children: [
|
|
15965
|
+
loopRedirectIds.has(r.id) && /* @__PURE__ */ jsx("span", {
|
|
15966
|
+
title: "Part of a redirect loop",
|
|
15967
|
+
className: "mr-1 inline-flex",
|
|
15968
|
+
children: /* @__PURE__ */ jsx(WarningCircle, {
|
|
15969
|
+
size: 14,
|
|
15970
|
+
weight: "fill",
|
|
15971
|
+
className: "text-kumo-warning",
|
|
15972
|
+
role: "img",
|
|
15973
|
+
"aria-label": "Part of a redirect loop"
|
|
15974
|
+
})
|
|
15975
|
+
}),
|
|
15976
|
+
r.auto && /* @__PURE__ */ jsx(Badge, {
|
|
15977
|
+
variant: "outline",
|
|
15978
|
+
className: "mr-1 text-xs",
|
|
15979
|
+
children: "auto"
|
|
15980
|
+
}),
|
|
15981
|
+
/* @__PURE__ */ jsx("button", {
|
|
15982
|
+
onClick: () => setEditRedirect(r),
|
|
15983
|
+
className: "p-1 text-kumo-subtle hover:text-kumo-default",
|
|
15984
|
+
title: "Edit redirect",
|
|
15985
|
+
"aria-label": `Edit redirect ${r.source}`,
|
|
15986
|
+
children: /* @__PURE__ */ jsx(PencilSimple, { size: 14 })
|
|
15987
|
+
}),
|
|
15988
|
+
/* @__PURE__ */ jsx("button", {
|
|
15989
|
+
onClick: () => setDeleteId(r.id),
|
|
15990
|
+
className: "p-1 text-kumo-subtle hover:text-kumo-danger",
|
|
15991
|
+
title: "Delete redirect",
|
|
15992
|
+
"aria-label": `Delete redirect ${r.source}`,
|
|
15993
|
+
children: /* @__PURE__ */ jsx(Trash, { size: 14 })
|
|
15994
|
+
})
|
|
15995
|
+
]
|
|
15996
|
+
})
|
|
15997
|
+
]
|
|
15998
|
+
}, r.id))]
|
|
15999
|
+
})
|
|
16000
|
+
] }),
|
|
15823
16001
|
tab === "404s" && /* @__PURE__ */ jsx(NotFoundPanel, {
|
|
15824
16002
|
items: notFoundQuery.data ?? [],
|
|
15825
16003
|
onCreateRedirect: handleCreateFrom404
|
|
@@ -16709,35 +16887,159 @@ function Settings() {
|
|
|
16709
16887
|
}
|
|
16710
16888
|
|
|
16711
16889
|
//#endregion
|
|
16712
|
-
//#region src/components/
|
|
16890
|
+
//#region src/components/users/roleDefinitions.ts
|
|
16713
16891
|
/**
|
|
16714
|
-
*
|
|
16715
|
-
*
|
|
16716
|
-
* Only available when using passkey auth. When external auth (e.g., Cloudflare Access)
|
|
16717
|
-
* is configured, this page shows an informational message instead.
|
|
16892
|
+
* Canonical role levels for admin UI (badge colors, selects, labels).
|
|
16893
|
+
* Allowed Domains UI only offers default roles up to Editor (40), not Admin (50).
|
|
16718
16894
|
*/
|
|
16719
|
-
const
|
|
16895
|
+
const ROLE_ENTRIES = [
|
|
16720
16896
|
{
|
|
16721
16897
|
value: 10,
|
|
16722
|
-
|
|
16898
|
+
color: "gray",
|
|
16899
|
+
label: {
|
|
16900
|
+
id: "M2vfqB",
|
|
16901
|
+
message: "Subscriber"
|
|
16902
|
+
},
|
|
16903
|
+
description: {
|
|
16904
|
+
id: "m7BmGK",
|
|
16905
|
+
message: "Can view content"
|
|
16906
|
+
}
|
|
16723
16907
|
},
|
|
16724
16908
|
{
|
|
16725
16909
|
value: 20,
|
|
16726
|
-
|
|
16910
|
+
color: "blue",
|
|
16911
|
+
label: {
|
|
16912
|
+
id: "3L51iw",
|
|
16913
|
+
message: "Contributor"
|
|
16914
|
+
},
|
|
16915
|
+
description: {
|
|
16916
|
+
id: "WzyYFi",
|
|
16917
|
+
message: "Can create content"
|
|
16918
|
+
}
|
|
16727
16919
|
},
|
|
16728
16920
|
{
|
|
16729
16921
|
value: 30,
|
|
16730
|
-
|
|
16922
|
+
color: "green",
|
|
16923
|
+
label: {
|
|
16924
|
+
id: "VbeIOx",
|
|
16925
|
+
message: "Author"
|
|
16926
|
+
},
|
|
16927
|
+
description: {
|
|
16928
|
+
id: "1onhKx",
|
|
16929
|
+
message: "Can publish own content"
|
|
16930
|
+
}
|
|
16731
16931
|
},
|
|
16732
16932
|
{
|
|
16733
16933
|
value: 40,
|
|
16734
|
-
|
|
16934
|
+
color: "purple",
|
|
16935
|
+
label: {
|
|
16936
|
+
id: "uBAxNB",
|
|
16937
|
+
message: "Editor"
|
|
16938
|
+
},
|
|
16939
|
+
description: {
|
|
16940
|
+
id: "ppZiw8",
|
|
16941
|
+
message: "Can manage all content"
|
|
16942
|
+
}
|
|
16943
|
+
},
|
|
16944
|
+
{
|
|
16945
|
+
value: 50,
|
|
16946
|
+
color: "red",
|
|
16947
|
+
label: {
|
|
16948
|
+
id: "U3pytU",
|
|
16949
|
+
message: "Admin"
|
|
16950
|
+
},
|
|
16951
|
+
description: {
|
|
16952
|
+
id: "scmRyR",
|
|
16953
|
+
message: "Full access"
|
|
16954
|
+
}
|
|
16735
16955
|
}
|
|
16736
16956
|
];
|
|
16737
|
-
|
|
16738
|
-
|
|
16957
|
+
const ROLE_CONFIG = Object.fromEntries(ROLE_ENTRIES.map((e) => [e.value, {
|
|
16958
|
+
label: e.label,
|
|
16959
|
+
description: e.description,
|
|
16960
|
+
color: e.color
|
|
16961
|
+
}]));
|
|
16962
|
+
function unknownRoleConfig(role) {
|
|
16963
|
+
return {
|
|
16964
|
+
label: {
|
|
16965
|
+
id: "h4POyA",
|
|
16966
|
+
message: "Role {role}",
|
|
16967
|
+
values: { role }
|
|
16968
|
+
},
|
|
16969
|
+
description: {
|
|
16970
|
+
id: "C52+JH",
|
|
16971
|
+
message: "Unknown role"
|
|
16972
|
+
},
|
|
16973
|
+
color: "gray"
|
|
16974
|
+
};
|
|
16975
|
+
}
|
|
16976
|
+
/** Badge / display config for a numeric role level */
|
|
16977
|
+
function getRoleConfig(role) {
|
|
16978
|
+
return ROLE_CONFIG[role] ?? unknownRoleConfig(role);
|
|
16979
|
+
}
|
|
16980
|
+
|
|
16981
|
+
//#endregion
|
|
16982
|
+
//#region src/components/users/useRolesConfig.ts
|
|
16983
|
+
const MSG_ROLE_UNKNOWN = {
|
|
16984
|
+
id: "Ef7StM",
|
|
16985
|
+
message: "Unknown"
|
|
16986
|
+
};
|
|
16987
|
+
/**
|
|
16988
|
+
* Shared resolved role strings + descriptor rows for selects (after `i18n` is active).
|
|
16989
|
+
*/
|
|
16990
|
+
function useRolesConfig() {
|
|
16991
|
+
const { _: _t } = useLingui();
|
|
16992
|
+
const roles = React.useMemo(() => ROLE_ENTRIES.map(({ value, label, description }) => ({
|
|
16993
|
+
value,
|
|
16994
|
+
label: _t(label),
|
|
16995
|
+
description: _t(description)
|
|
16996
|
+
})), [_t]);
|
|
16997
|
+
const roleLabels = React.useMemo(() => Object.fromEntries(ROLE_ENTRIES.map((r) => [String(r.value), _t(r.label)])), [_t]);
|
|
16998
|
+
return {
|
|
16999
|
+
roleLabels,
|
|
17000
|
+
getRoleLabel: React.useCallback((level) => roleLabels[String(level)] ?? _t(MSG_ROLE_UNKNOWN), [roleLabels, _t]),
|
|
17001
|
+
roles
|
|
17002
|
+
};
|
|
16739
17003
|
}
|
|
17004
|
+
|
|
17005
|
+
//#endregion
|
|
17006
|
+
//#region src/components/settings/useAllowedDomainsRolesConfig.ts
|
|
17007
|
+
/** Self-signup default role must not be Admin (API / product rule). */
|
|
17008
|
+
const MAX_SELF_SIGNUP_DEFAULT_ROLE = 40;
|
|
17009
|
+
/**
|
|
17010
|
+
* Role labels and selects for Allowed Domains (Subscriber–Editor only for defaults).
|
|
17011
|
+
* Built on {@link useRolesConfig}; keeps the filter + `Select` `items` shape in one place.
|
|
17012
|
+
*/
|
|
17013
|
+
function useAllowedDomainsRolesConfig() {
|
|
17014
|
+
const { roleLabels, getRoleLabel, roles } = useRolesConfig();
|
|
17015
|
+
const signupRoles = React.useMemo(() => roles.filter((r) => r.value <= MAX_SELF_SIGNUP_DEFAULT_ROLE), [roles]);
|
|
17016
|
+
return {
|
|
17017
|
+
getRoleLabel,
|
|
17018
|
+
signupRoles,
|
|
17019
|
+
signupRoleItems: React.useMemo(() => {
|
|
17020
|
+
const entries = signupRoles.map((r) => {
|
|
17021
|
+
const label = roleLabels[String(r.value)];
|
|
17022
|
+
return [String(r.value), label ?? getRoleLabel(r.value)];
|
|
17023
|
+
});
|
|
17024
|
+
return Object.fromEntries(entries);
|
|
17025
|
+
}, [
|
|
17026
|
+
signupRoles,
|
|
17027
|
+
roleLabels,
|
|
17028
|
+
getRoleLabel
|
|
17029
|
+
])
|
|
17030
|
+
};
|
|
17031
|
+
}
|
|
17032
|
+
|
|
17033
|
+
//#endregion
|
|
17034
|
+
//#region src/components/settings/AllowedDomainsSettings.tsx
|
|
17035
|
+
/**
|
|
17036
|
+
* Allowed Domains Settings - Self-signup domain management
|
|
17037
|
+
*
|
|
17038
|
+
* Only available when using passkey auth. When external auth (e.g., Cloudflare Access)
|
|
17039
|
+
* is configured, this page shows an informational message instead.
|
|
17040
|
+
*/
|
|
16740
17041
|
function AllowedDomainsSettings() {
|
|
17042
|
+
const { getRoleLabel, signupRoles, signupRoleItems } = useAllowedDomainsRolesConfig();
|
|
16741
17043
|
const queryClient = useQueryClient();
|
|
16742
17044
|
const [isAddingDomain, setIsAddingDomain] = React.useState(false);
|
|
16743
17045
|
const [editingDomain, setEditingDomain] = React.useState(null);
|
|
@@ -16929,7 +17231,7 @@ function AllowedDomainsSettings() {
|
|
|
16929
17231
|
children: domain.domain
|
|
16930
17232
|
}), /* @__PURE__ */ jsxs("div", {
|
|
16931
17233
|
className: "text-sm text-kumo-subtle",
|
|
16932
|
-
children: ["Default role: ",
|
|
17234
|
+
children: ["Default role: ", getRoleLabel(domain.defaultRole)]
|
|
16933
17235
|
})] })]
|
|
16934
17236
|
}), /* @__PURE__ */ jsxs("div", {
|
|
16935
17237
|
className: "flex items-center gap-2",
|
|
@@ -16990,8 +17292,8 @@ function AllowedDomainsSettings() {
|
|
|
16990
17292
|
label: "Default Role",
|
|
16991
17293
|
value: String(newRole),
|
|
16992
17294
|
onValueChange: (v) => v !== null && setNewRole(Number(v)),
|
|
16993
|
-
items:
|
|
16994
|
-
children:
|
|
17295
|
+
items: signupRoleItems,
|
|
17296
|
+
children: signupRoles.map((role) => /* @__PURE__ */ jsx(Select.Option, {
|
|
16995
17297
|
value: String(role.value),
|
|
16996
17298
|
children: role.label
|
|
16997
17299
|
}, role.value))
|
|
@@ -17051,8 +17353,8 @@ function AllowedDomainsSettings() {
|
|
|
17051
17353
|
label: "Default Role",
|
|
17052
17354
|
value: String(editingDomain?.defaultRole ?? 30),
|
|
17053
17355
|
onValueChange: (v) => v !== null && editingDomain && handleUpdateRole(editingDomain.domain, Number(v)),
|
|
17054
|
-
items:
|
|
17055
|
-
children:
|
|
17356
|
+
items: signupRoleItems,
|
|
17357
|
+
children: signupRoles.map((role) => /* @__PURE__ */ jsx(Select.Option, {
|
|
17056
17358
|
value: String(role.value),
|
|
17057
17359
|
children: role.label
|
|
17058
17360
|
}, role.value))
|
|
@@ -17111,25 +17413,121 @@ function AllowedDomainsSettings() {
|
|
|
17111
17413
|
const EXPIRY_OPTIONS = [
|
|
17112
17414
|
{
|
|
17113
17415
|
value: "none",
|
|
17114
|
-
label:
|
|
17416
|
+
label: {
|
|
17417
|
+
id: "JYZYJA",
|
|
17418
|
+
message: "No expiry"
|
|
17419
|
+
}
|
|
17115
17420
|
},
|
|
17116
17421
|
{
|
|
17117
17422
|
value: "7d",
|
|
17118
|
-
label:
|
|
17423
|
+
label: {
|
|
17424
|
+
id: "rJe6vw",
|
|
17425
|
+
message: "7 days"
|
|
17426
|
+
}
|
|
17119
17427
|
},
|
|
17120
17428
|
{
|
|
17121
17429
|
value: "30d",
|
|
17122
|
-
label:
|
|
17430
|
+
label: {
|
|
17431
|
+
id: "P9cEa2",
|
|
17432
|
+
message: "30 days"
|
|
17433
|
+
}
|
|
17123
17434
|
},
|
|
17124
17435
|
{
|
|
17125
17436
|
value: "90d",
|
|
17126
|
-
label:
|
|
17437
|
+
label: {
|
|
17438
|
+
id: "h28hXf",
|
|
17439
|
+
message: "90 days"
|
|
17440
|
+
}
|
|
17127
17441
|
},
|
|
17128
17442
|
{
|
|
17129
17443
|
value: "365d",
|
|
17130
|
-
label:
|
|
17444
|
+
label: {
|
|
17445
|
+
id: "+N7uug",
|
|
17446
|
+
message: "1 year"
|
|
17447
|
+
}
|
|
17131
17448
|
}
|
|
17132
17449
|
];
|
|
17450
|
+
const API_TOKEN_SCOPE_VALUES = [
|
|
17451
|
+
{
|
|
17452
|
+
scope: API_TOKEN_SCOPES.ContentRead,
|
|
17453
|
+
label: {
|
|
17454
|
+
id: "DqsyRK",
|
|
17455
|
+
message: "Content Read"
|
|
17456
|
+
},
|
|
17457
|
+
description: {
|
|
17458
|
+
id: "Pho0BC",
|
|
17459
|
+
message: "Read content entries"
|
|
17460
|
+
}
|
|
17461
|
+
},
|
|
17462
|
+
{
|
|
17463
|
+
scope: API_TOKEN_SCOPES.ContentWrite,
|
|
17464
|
+
label: {
|
|
17465
|
+
id: "js1bld",
|
|
17466
|
+
message: "Content Write"
|
|
17467
|
+
},
|
|
17468
|
+
description: {
|
|
17469
|
+
id: "e48Hn6",
|
|
17470
|
+
message: "Create, update, delete content"
|
|
17471
|
+
}
|
|
17472
|
+
},
|
|
17473
|
+
{
|
|
17474
|
+
scope: API_TOKEN_SCOPES.MediaRead,
|
|
17475
|
+
label: {
|
|
17476
|
+
id: "TNFBJj",
|
|
17477
|
+
message: "Media Read"
|
|
17478
|
+
},
|
|
17479
|
+
description: {
|
|
17480
|
+
id: "IxcUJS",
|
|
17481
|
+
message: "Read media files"
|
|
17482
|
+
}
|
|
17483
|
+
},
|
|
17484
|
+
{
|
|
17485
|
+
scope: API_TOKEN_SCOPES.MediaWrite,
|
|
17486
|
+
label: {
|
|
17487
|
+
id: "nAGBQY",
|
|
17488
|
+
message: "Media Write"
|
|
17489
|
+
},
|
|
17490
|
+
description: {
|
|
17491
|
+
id: "SrZ1jh",
|
|
17492
|
+
message: "Upload and delete media"
|
|
17493
|
+
}
|
|
17494
|
+
},
|
|
17495
|
+
{
|
|
17496
|
+
scope: API_TOKEN_SCOPES.SchemaRead,
|
|
17497
|
+
label: {
|
|
17498
|
+
id: "19WSvR",
|
|
17499
|
+
message: "Schema Read"
|
|
17500
|
+
},
|
|
17501
|
+
description: {
|
|
17502
|
+
id: "nEEs8e",
|
|
17503
|
+
message: "Read collection schemas"
|
|
17504
|
+
}
|
|
17505
|
+
},
|
|
17506
|
+
{
|
|
17507
|
+
scope: API_TOKEN_SCOPES.SchemaWrite,
|
|
17508
|
+
label: {
|
|
17509
|
+
id: "n6+BBp",
|
|
17510
|
+
message: "Schema Write"
|
|
17511
|
+
},
|
|
17512
|
+
description: {
|
|
17513
|
+
id: "UgmJPq",
|
|
17514
|
+
message: "Modify collection schemas"
|
|
17515
|
+
}
|
|
17516
|
+
},
|
|
17517
|
+
{
|
|
17518
|
+
scope: API_TOKEN_SCOPES.Admin,
|
|
17519
|
+
label: {
|
|
17520
|
+
id: "U3pytU",
|
|
17521
|
+
message: "Admin"
|
|
17522
|
+
},
|
|
17523
|
+
description: {
|
|
17524
|
+
id: "5SaI4f",
|
|
17525
|
+
message: "Full admin access"
|
|
17526
|
+
}
|
|
17527
|
+
}
|
|
17528
|
+
];
|
|
17529
|
+
/** Wire scopes shown on the create-token form (contract-tested vs `API_TOKEN_SCOPES` and `@emdash-cms/auth`). */
|
|
17530
|
+
const API_TOKEN_SCOPE_FORM_SCOPES = API_TOKEN_SCOPE_VALUES.map((row) => row.scope);
|
|
17133
17531
|
function computeExpiryDate(option) {
|
|
17134
17532
|
if (option === "none") return void 0;
|
|
17135
17533
|
const days = parseInt(option, 10);
|
|
@@ -17139,6 +17537,7 @@ function computeExpiryDate(option) {
|
|
|
17139
17537
|
return date.toISOString();
|
|
17140
17538
|
}
|
|
17141
17539
|
function ApiTokenSettings() {
|
|
17540
|
+
const { _: _t } = useLingui();
|
|
17142
17541
|
const queryClient = useQueryClient();
|
|
17143
17542
|
const [showCreateForm, setShowCreateForm] = React.useState(false);
|
|
17144
17543
|
const [newToken, setNewToken] = React.useState(null);
|
|
@@ -17180,6 +17579,7 @@ function ApiTokenSettings() {
|
|
|
17180
17579
|
copyTimeoutRef.current = setTimeout(setCopied, 2e3, false);
|
|
17181
17580
|
} catch {}
|
|
17182
17581
|
};
|
|
17582
|
+
const expirySelectItems = React.useMemo(() => Object.fromEntries(EXPIRY_OPTIONS.map((o) => [o.value, _t(o.label)])), [_t]);
|
|
17183
17583
|
return /* @__PURE__ */ jsxs("div", {
|
|
17184
17584
|
className: "space-y-6",
|
|
17185
17585
|
children: [
|
|
@@ -17190,15 +17590,24 @@ function ApiTokenSettings() {
|
|
|
17190
17590
|
children: /* @__PURE__ */ jsx(Button, {
|
|
17191
17591
|
variant: "ghost",
|
|
17192
17592
|
shape: "square",
|
|
17193
|
-
"aria-label":
|
|
17593
|
+
"aria-label": _t({
|
|
17594
|
+
id: "9aZHfH",
|
|
17595
|
+
message: "Back to settings"
|
|
17596
|
+
}),
|
|
17194
17597
|
children: /* @__PURE__ */ jsx(ArrowLeft, { className: "h-4 w-4" })
|
|
17195
17598
|
})
|
|
17196
17599
|
}), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h1", {
|
|
17197
17600
|
className: "text-2xl font-bold",
|
|
17198
|
-
children:
|
|
17601
|
+
children: _t({
|
|
17602
|
+
id: "ZiooJI",
|
|
17603
|
+
message: "API Tokens"
|
|
17604
|
+
})
|
|
17199
17605
|
}), /* @__PURE__ */ jsx("p", {
|
|
17200
17606
|
className: "text-sm text-kumo-subtle",
|
|
17201
|
-
children:
|
|
17607
|
+
children: _t({
|
|
17608
|
+
id: "dhH+RW",
|
|
17609
|
+
message: "Create personal access tokens for programmatic API access"
|
|
17610
|
+
})
|
|
17202
17611
|
})] })]
|
|
17203
17612
|
}),
|
|
17204
17613
|
newToken && /* @__PURE__ */ jsx("div", {
|
|
@@ -17210,13 +17619,20 @@ function ApiTokenSettings() {
|
|
|
17210
17619
|
/* @__PURE__ */ jsxs("div", {
|
|
17211
17620
|
className: "flex-1 min-w-0",
|
|
17212
17621
|
children: [
|
|
17213
|
-
/* @__PURE__ */
|
|
17622
|
+
/* @__PURE__ */ jsx("p", {
|
|
17214
17623
|
className: "font-medium text-green-800 dark:text-green-200",
|
|
17215
|
-
children:
|
|
17624
|
+
children: _t({
|
|
17625
|
+
id: "eoLxnB",
|
|
17626
|
+
message: "Token created: {0}",
|
|
17627
|
+
values: { 0: newToken.info.name }
|
|
17628
|
+
})
|
|
17216
17629
|
}),
|
|
17217
17630
|
/* @__PURE__ */ jsx("p", {
|
|
17218
17631
|
className: "text-sm text-green-700 dark:text-green-300 mt-1",
|
|
17219
|
-
children:
|
|
17632
|
+
children: _t({
|
|
17633
|
+
id: "DyPcUA",
|
|
17634
|
+
message: "Copy this token now — it won't be shown again."
|
|
17635
|
+
})
|
|
17220
17636
|
}),
|
|
17221
17637
|
/* @__PURE__ */ jsxs("div", {
|
|
17222
17638
|
className: "mt-3 flex items-center gap-2",
|
|
@@ -17229,21 +17645,33 @@ function ApiTokenSettings() {
|
|
|
17229
17645
|
variant: "ghost",
|
|
17230
17646
|
shape: "square",
|
|
17231
17647
|
onClick: () => setTokenVisible(!tokenVisible),
|
|
17232
|
-
"aria-label": tokenVisible ?
|
|
17648
|
+
"aria-label": tokenVisible ? _t({
|
|
17649
|
+
id: "NEZFJN",
|
|
17650
|
+
message: "Hide token"
|
|
17651
|
+
}) : _t({
|
|
17652
|
+
id: "10eUfR",
|
|
17653
|
+
message: "Show token"
|
|
17654
|
+
}),
|
|
17233
17655
|
children: tokenVisible ? /* @__PURE__ */ jsx(EyeSlash, {}) : /* @__PURE__ */ jsx(Eye, {})
|
|
17234
17656
|
}),
|
|
17235
17657
|
/* @__PURE__ */ jsx(Button, {
|
|
17236
17658
|
variant: "ghost",
|
|
17237
17659
|
shape: "square",
|
|
17238
17660
|
onClick: handleCopyToken,
|
|
17239
|
-
"aria-label":
|
|
17661
|
+
"aria-label": _t({
|
|
17662
|
+
id: "BddwrJ",
|
|
17663
|
+
message: "Copy token"
|
|
17664
|
+
}),
|
|
17240
17665
|
children: /* @__PURE__ */ jsx(Copy, {})
|
|
17241
17666
|
})
|
|
17242
17667
|
]
|
|
17243
17668
|
}),
|
|
17244
17669
|
copied && /* @__PURE__ */ jsx("p", {
|
|
17245
17670
|
className: "text-xs text-green-600 dark:text-green-400 mt-1",
|
|
17246
|
-
children:
|
|
17671
|
+
children: _t({
|
|
17672
|
+
id: "FxVG/l",
|
|
17673
|
+
message: "Copied to clipboard"
|
|
17674
|
+
})
|
|
17247
17675
|
})
|
|
17248
17676
|
]
|
|
17249
17677
|
}),
|
|
@@ -17251,13 +17679,20 @@ function ApiTokenSettings() {
|
|
|
17251
17679
|
variant: "ghost",
|
|
17252
17680
|
size: "sm",
|
|
17253
17681
|
onClick: () => setNewToken(null),
|
|
17254
|
-
"aria-label":
|
|
17255
|
-
|
|
17682
|
+
"aria-label": _t({
|
|
17683
|
+
id: "1QfxQT",
|
|
17684
|
+
message: "Dismiss"
|
|
17685
|
+
}),
|
|
17686
|
+
children: _t({
|
|
17687
|
+
id: "1QfxQT",
|
|
17688
|
+
message: "Dismiss"
|
|
17689
|
+
})
|
|
17256
17690
|
})
|
|
17257
17691
|
]
|
|
17258
17692
|
})
|
|
17259
17693
|
}),
|
|
17260
17694
|
showCreateForm ? /* @__PURE__ */ jsx(CreateTokenForm, {
|
|
17695
|
+
expirySelectItems,
|
|
17261
17696
|
isCreating: createMutation.isPending,
|
|
17262
17697
|
error: createMutation.error?.message ?? null,
|
|
17263
17698
|
onSubmit: (input) => createMutation.mutate({
|
|
@@ -17269,7 +17704,10 @@ function ApiTokenSettings() {
|
|
|
17269
17704
|
}) : /* @__PURE__ */ jsx(Button, {
|
|
17270
17705
|
icon: /* @__PURE__ */ jsx(Plus, {}),
|
|
17271
17706
|
onClick: () => setShowCreateForm(true),
|
|
17272
|
-
children:
|
|
17707
|
+
children: _t({
|
|
17708
|
+
id: "JkdaXO",
|
|
17709
|
+
message: "Create Token"
|
|
17710
|
+
})
|
|
17273
17711
|
}),
|
|
17274
17712
|
/* @__PURE__ */ jsx("div", {
|
|
17275
17713
|
className: "rounded-lg border bg-kumo-base",
|
|
@@ -17278,7 +17716,10 @@ function ApiTokenSettings() {
|
|
|
17278
17716
|
children: /* @__PURE__ */ jsx(Loader, {})
|
|
17279
17717
|
}) : !tokens || tokens.length === 0 ? /* @__PURE__ */ jsx("div", {
|
|
17280
17718
|
className: "py-8 text-center text-sm text-kumo-subtle",
|
|
17281
|
-
children:
|
|
17719
|
+
children: _t({
|
|
17720
|
+
id: "aio6Hc",
|
|
17721
|
+
message: "No API tokens yet. Create one to get started."
|
|
17722
|
+
})
|
|
17282
17723
|
}) : /* @__PURE__ */ jsx("div", {
|
|
17283
17724
|
className: "divide-y",
|
|
17284
17725
|
children: tokens.map((token) => /* @__PURE__ */ jsxs("div", {
|
|
@@ -17299,14 +17740,30 @@ function ApiTokenSettings() {
|
|
|
17299
17740
|
/* @__PURE__ */ jsxs("div", {
|
|
17300
17741
|
className: "flex gap-3 mt-1 text-xs text-kumo-subtle",
|
|
17301
17742
|
children: [
|
|
17302
|
-
/* @__PURE__ */
|
|
17303
|
-
|
|
17304
|
-
|
|
17743
|
+
/* @__PURE__ */ jsx("span", { children: _t({
|
|
17744
|
+
id: "NSzA6n",
|
|
17745
|
+
message: "Scopes: {0}",
|
|
17746
|
+
values: { 0: token.scopes.join(", ") }
|
|
17747
|
+
}) }),
|
|
17748
|
+
token.expiresAt && /* @__PURE__ */ jsx("span", { children: _t({
|
|
17749
|
+
id: "oOfJ56",
|
|
17750
|
+
message: "Expires {0}",
|
|
17751
|
+
values: { 0: new Date(token.expiresAt).toLocaleDateString() }
|
|
17752
|
+
}) }),
|
|
17753
|
+
token.lastUsedAt && /* @__PURE__ */ jsx("span", { children: _t({
|
|
17754
|
+
id: "ylo1I0",
|
|
17755
|
+
message: "Last used {0}",
|
|
17756
|
+
values: { 0: new Date(token.lastUsedAt).toLocaleDateString() }
|
|
17757
|
+
}) })
|
|
17305
17758
|
]
|
|
17306
17759
|
}),
|
|
17307
|
-
/* @__PURE__ */
|
|
17760
|
+
/* @__PURE__ */ jsx("div", {
|
|
17308
17761
|
className: "text-xs text-kumo-subtle mt-0.5",
|
|
17309
|
-
children:
|
|
17762
|
+
children: _t({
|
|
17763
|
+
id: "MXSt4t",
|
|
17764
|
+
message: "Created {0}",
|
|
17765
|
+
values: { 0: new Date(token.createdAt).toLocaleDateString() }
|
|
17766
|
+
})
|
|
17310
17767
|
})
|
|
17311
17768
|
]
|
|
17312
17769
|
}), revokeConfirmId === token.id ? /* @__PURE__ */ jsxs("div", {
|
|
@@ -17318,14 +17775,23 @@ function ApiTokenSettings() {
|
|
|
17318
17775
|
}),
|
|
17319
17776
|
/* @__PURE__ */ jsx("span", {
|
|
17320
17777
|
className: "text-sm text-kumo-danger",
|
|
17321
|
-
children:
|
|
17778
|
+
children: _t({
|
|
17779
|
+
id: "U4/l0o",
|
|
17780
|
+
message: "Revoke?"
|
|
17781
|
+
})
|
|
17322
17782
|
}),
|
|
17323
17783
|
/* @__PURE__ */ jsx(Button, {
|
|
17324
17784
|
variant: "destructive",
|
|
17325
17785
|
size: "sm",
|
|
17326
17786
|
disabled: revokeMutation.isPending,
|
|
17327
17787
|
onClick: () => revokeMutation.mutate(token.id),
|
|
17328
|
-
children: revokeMutation.isPending ?
|
|
17788
|
+
children: revokeMutation.isPending ? _t({
|
|
17789
|
+
id: "zzTOEt",
|
|
17790
|
+
message: "Revoking..."
|
|
17791
|
+
}) : _t({
|
|
17792
|
+
id: "7VpPHA",
|
|
17793
|
+
message: "Confirm"
|
|
17794
|
+
})
|
|
17329
17795
|
}),
|
|
17330
17796
|
/* @__PURE__ */ jsx(Button, {
|
|
17331
17797
|
variant: "outline",
|
|
@@ -17334,14 +17800,20 @@ function ApiTokenSettings() {
|
|
|
17334
17800
|
setRevokeConfirmId(null);
|
|
17335
17801
|
revokeMutation.reset();
|
|
17336
17802
|
},
|
|
17337
|
-
children:
|
|
17803
|
+
children: _t({
|
|
17804
|
+
id: "dEgA5A",
|
|
17805
|
+
message: "Cancel"
|
|
17806
|
+
})
|
|
17338
17807
|
})
|
|
17339
17808
|
]
|
|
17340
17809
|
}) : /* @__PURE__ */ jsx(Button, {
|
|
17341
17810
|
variant: "ghost",
|
|
17342
17811
|
shape: "square",
|
|
17343
17812
|
onClick: () => setRevokeConfirmId(token.id),
|
|
17344
|
-
"aria-label":
|
|
17813
|
+
"aria-label": _t({
|
|
17814
|
+
id: "7/ePoE",
|
|
17815
|
+
message: "Revoke token"
|
|
17816
|
+
}),
|
|
17345
17817
|
children: /* @__PURE__ */ jsx(Trash, { className: "h-4 w-4 text-kumo-subtle hover:text-kumo-danger" })
|
|
17346
17818
|
})]
|
|
17347
17819
|
}, token.id))
|
|
@@ -17350,7 +17822,8 @@ function ApiTokenSettings() {
|
|
|
17350
17822
|
]
|
|
17351
17823
|
});
|
|
17352
17824
|
}
|
|
17353
|
-
function CreateTokenForm({ isCreating, error, onSubmit, onCancel }) {
|
|
17825
|
+
function CreateTokenForm({ expirySelectItems, isCreating, error, onSubmit, onCancel }) {
|
|
17826
|
+
const { _: _t2 } = useLingui();
|
|
17354
17827
|
const [name, setName] = React.useState("");
|
|
17355
17828
|
const [selectedScopes, setSelectedScopes] = React.useState(/* @__PURE__ */ new Set());
|
|
17356
17829
|
const [expiry, setExpiry] = React.useState("30d");
|
|
@@ -17376,7 +17849,10 @@ function CreateTokenForm({ isCreating, error, onSubmit, onCancel }) {
|
|
|
17376
17849
|
children: [
|
|
17377
17850
|
/* @__PURE__ */ jsx("h2", {
|
|
17378
17851
|
className: "text-lg font-semibold mb-4",
|
|
17379
|
-
children:
|
|
17852
|
+
children: _t2({
|
|
17853
|
+
id: "IBeakM",
|
|
17854
|
+
message: "Create New Token"
|
|
17855
|
+
})
|
|
17380
17856
|
}),
|
|
17381
17857
|
error && /* @__PURE__ */ jsxs("div", {
|
|
17382
17858
|
className: "mb-4 rounded-lg border border-kumo-danger/50 bg-kumo-danger/10 p-3 flex items-center gap-2 text-sm text-kumo-danger",
|
|
@@ -17387,40 +17863,54 @@ function CreateTokenForm({ isCreating, error, onSubmit, onCancel }) {
|
|
|
17387
17863
|
className: "space-y-4",
|
|
17388
17864
|
children: [
|
|
17389
17865
|
/* @__PURE__ */ jsx(Input, {
|
|
17390
|
-
label:
|
|
17866
|
+
label: _t2({
|
|
17867
|
+
id: "jJrqb1",
|
|
17868
|
+
message: "Token Name"
|
|
17869
|
+
}),
|
|
17391
17870
|
value: name,
|
|
17392
17871
|
onChange: (e) => setName(e.target.value),
|
|
17393
|
-
placeholder:
|
|
17872
|
+
placeholder: _t2({
|
|
17873
|
+
id: "O1SmJ+",
|
|
17874
|
+
message: "e.g., CI/CD Pipeline"
|
|
17875
|
+
}),
|
|
17394
17876
|
required: true,
|
|
17395
17877
|
autoFocus: true
|
|
17396
17878
|
}),
|
|
17397
17879
|
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
|
|
17398
17880
|
className: "text-sm font-medium mb-2",
|
|
17399
|
-
children:
|
|
17881
|
+
children: _t2({
|
|
17882
|
+
id: "N/rFzD",
|
|
17883
|
+
message: "Scopes"
|
|
17884
|
+
})
|
|
17400
17885
|
}), /* @__PURE__ */ jsx("div", {
|
|
17401
17886
|
className: "space-y-2",
|
|
17402
|
-
children:
|
|
17403
|
-
|
|
17404
|
-
|
|
17405
|
-
|
|
17406
|
-
|
|
17407
|
-
|
|
17408
|
-
|
|
17409
|
-
|
|
17410
|
-
|
|
17411
|
-
|
|
17412
|
-
|
|
17413
|
-
|
|
17414
|
-
|
|
17887
|
+
children: API_TOKEN_SCOPE_VALUES.map(({ scope, label, description }) => {
|
|
17888
|
+
return /* @__PURE__ */ jsxs("label", {
|
|
17889
|
+
className: "flex items-start gap-2 cursor-pointer",
|
|
17890
|
+
children: [/* @__PURE__ */ jsx(Checkbox, {
|
|
17891
|
+
checked: selectedScopes.has(scope),
|
|
17892
|
+
onCheckedChange: () => toggleScope(scope)
|
|
17893
|
+
}), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
|
|
17894
|
+
className: "text-sm font-medium",
|
|
17895
|
+
children: _t2(label)
|
|
17896
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
17897
|
+
className: "text-xs text-kumo-subtle",
|
|
17898
|
+
children: _t2(description)
|
|
17899
|
+
})] })]
|
|
17900
|
+
}, scope);
|
|
17901
|
+
})
|
|
17415
17902
|
})] }),
|
|
17416
17903
|
/* @__PURE__ */ jsx(Select, {
|
|
17417
|
-
label:
|
|
17904
|
+
label: _t2({
|
|
17905
|
+
id: "agO/T/",
|
|
17906
|
+
message: "Expiry"
|
|
17907
|
+
}),
|
|
17418
17908
|
value: expiry,
|
|
17419
17909
|
onValueChange: (v) => v !== null && setExpiry(v),
|
|
17420
|
-
items:
|
|
17910
|
+
items: expirySelectItems,
|
|
17421
17911
|
children: EXPIRY_OPTIONS.map((option) => /* @__PURE__ */ jsx(Select.Option, {
|
|
17422
17912
|
value: option.value,
|
|
17423
|
-
children: option.label
|
|
17913
|
+
children: _t2(option.label)
|
|
17424
17914
|
}, option.value))
|
|
17425
17915
|
}),
|
|
17426
17916
|
/* @__PURE__ */ jsxs("div", {
|
|
@@ -17428,12 +17918,21 @@ function CreateTokenForm({ isCreating, error, onSubmit, onCancel }) {
|
|
|
17428
17918
|
children: [/* @__PURE__ */ jsx(Button, {
|
|
17429
17919
|
type: "submit",
|
|
17430
17920
|
disabled: !isValid || isCreating,
|
|
17431
|
-
children: isCreating ?
|
|
17921
|
+
children: isCreating ? _t2({
|
|
17922
|
+
id: "HM56Bx",
|
|
17923
|
+
message: "Creating..."
|
|
17924
|
+
}) : _t2({
|
|
17925
|
+
id: "JkdaXO",
|
|
17926
|
+
message: "Create Token"
|
|
17927
|
+
})
|
|
17432
17928
|
}), /* @__PURE__ */ jsx(Button, {
|
|
17433
17929
|
type: "button",
|
|
17434
17930
|
variant: "outline",
|
|
17435
17931
|
onClick: onCancel,
|
|
17436
|
-
children:
|
|
17932
|
+
children: _t2({
|
|
17933
|
+
id: "dEgA5A",
|
|
17934
|
+
message: "Cancel"
|
|
17935
|
+
})
|
|
17437
17936
|
})]
|
|
17438
17937
|
})
|
|
17439
17938
|
]
|
|
@@ -19326,7 +19825,10 @@ async function searchContent(query) {
|
|
|
19326
19825
|
function buildNavItems(manifest, userRole) {
|
|
19327
19826
|
const items = [{
|
|
19328
19827
|
id: "dashboard",
|
|
19329
|
-
title:
|
|
19828
|
+
title: {
|
|
19829
|
+
id: "7p5kLi",
|
|
19830
|
+
message: "Dashboard"
|
|
19831
|
+
},
|
|
19330
19832
|
to: "/",
|
|
19331
19833
|
icon: SquaresFour,
|
|
19332
19834
|
keywords: ["home", "overview"]
|
|
@@ -19341,7 +19843,10 @@ function buildNavItems(manifest, userRole) {
|
|
|
19341
19843
|
});
|
|
19342
19844
|
items.push({
|
|
19343
19845
|
id: "media",
|
|
19344
|
-
title:
|
|
19846
|
+
title: {
|
|
19847
|
+
id: "ia4TsE",
|
|
19848
|
+
message: "Media Library"
|
|
19849
|
+
},
|
|
19345
19850
|
to: "/media",
|
|
19346
19851
|
icon: Image$1,
|
|
19347
19852
|
keywords: [
|
|
@@ -19351,35 +19856,50 @@ function buildNavItems(manifest, userRole) {
|
|
|
19351
19856
|
]
|
|
19352
19857
|
}, {
|
|
19353
19858
|
id: "menus",
|
|
19354
|
-
title:
|
|
19859
|
+
title: {
|
|
19860
|
+
id: "NXjnVQ",
|
|
19861
|
+
message: "Menus"
|
|
19862
|
+
},
|
|
19355
19863
|
to: "/menus",
|
|
19356
19864
|
icon: List,
|
|
19357
19865
|
minRole: ROLE_EDITOR$2,
|
|
19358
19866
|
keywords: ["navigation"]
|
|
19359
19867
|
}, {
|
|
19360
19868
|
id: "widgets",
|
|
19361
|
-
title:
|
|
19869
|
+
title: {
|
|
19870
|
+
id: "tL6W2K",
|
|
19871
|
+
message: "Widgets"
|
|
19872
|
+
},
|
|
19362
19873
|
to: "/widgets",
|
|
19363
19874
|
icon: GridFour,
|
|
19364
19875
|
minRole: ROLE_EDITOR$2,
|
|
19365
19876
|
keywords: ["sidebar", "footer"]
|
|
19366
19877
|
}, {
|
|
19367
19878
|
id: "sections",
|
|
19368
|
-
title:
|
|
19879
|
+
title: {
|
|
19880
|
+
id: "R4OWFD",
|
|
19881
|
+
message: "Sections"
|
|
19882
|
+
},
|
|
19369
19883
|
to: "/sections",
|
|
19370
19884
|
icon: Stack,
|
|
19371
19885
|
minRole: ROLE_EDITOR$2,
|
|
19372
19886
|
keywords: ["page builder", "blocks"]
|
|
19373
19887
|
}, {
|
|
19374
19888
|
id: "content-types",
|
|
19375
|
-
title:
|
|
19889
|
+
title: {
|
|
19890
|
+
id: "F7Jcuy",
|
|
19891
|
+
message: "Content Types"
|
|
19892
|
+
},
|
|
19376
19893
|
to: "/content-types",
|
|
19377
19894
|
icon: Database,
|
|
19378
19895
|
minRole: ROLE_ADMIN$2,
|
|
19379
19896
|
keywords: ["schema", "collections"]
|
|
19380
19897
|
}, {
|
|
19381
19898
|
id: "categories",
|
|
19382
|
-
title:
|
|
19899
|
+
title: {
|
|
19900
|
+
id: "NUrY9o",
|
|
19901
|
+
message: "Categories"
|
|
19902
|
+
},
|
|
19383
19903
|
to: "/taxonomies/$taxonomy",
|
|
19384
19904
|
params: { taxonomy: "category" },
|
|
19385
19905
|
icon: FileText,
|
|
@@ -19387,7 +19907,10 @@ function buildNavItems(manifest, userRole) {
|
|
|
19387
19907
|
keywords: ["taxonomy"]
|
|
19388
19908
|
}, {
|
|
19389
19909
|
id: "tags",
|
|
19390
|
-
title:
|
|
19910
|
+
title: {
|
|
19911
|
+
id: "OYHzN1",
|
|
19912
|
+
message: "Tags"
|
|
19913
|
+
},
|
|
19391
19914
|
to: "/taxonomies/$taxonomy",
|
|
19392
19915
|
params: { taxonomy: "tag" },
|
|
19393
19916
|
icon: FileText,
|
|
@@ -19395,35 +19918,50 @@ function buildNavItems(manifest, userRole) {
|
|
|
19395
19918
|
keywords: ["taxonomy"]
|
|
19396
19919
|
}, {
|
|
19397
19920
|
id: "users",
|
|
19398
|
-
title:
|
|
19921
|
+
title: {
|
|
19922
|
+
id: "Sxm8rQ",
|
|
19923
|
+
message: "Users"
|
|
19924
|
+
},
|
|
19399
19925
|
to: "/users",
|
|
19400
19926
|
icon: Users,
|
|
19401
19927
|
minRole: ROLE_ADMIN$2,
|
|
19402
19928
|
keywords: ["accounts", "team"]
|
|
19403
19929
|
}, {
|
|
19404
19930
|
id: "plugins",
|
|
19405
|
-
title:
|
|
19931
|
+
title: {
|
|
19932
|
+
id: "ohUJJM",
|
|
19933
|
+
message: "Plugins"
|
|
19934
|
+
},
|
|
19406
19935
|
to: "/plugins-manager",
|
|
19407
19936
|
icon: PuzzlePiece,
|
|
19408
19937
|
minRole: ROLE_ADMIN$2,
|
|
19409
19938
|
keywords: ["extensions", "add-ons"]
|
|
19410
19939
|
}, {
|
|
19411
19940
|
id: "import",
|
|
19412
|
-
title:
|
|
19941
|
+
title: {
|
|
19942
|
+
id: "l3s5ri",
|
|
19943
|
+
message: "Import"
|
|
19944
|
+
},
|
|
19413
19945
|
to: "/import/wordpress",
|
|
19414
19946
|
icon: Upload,
|
|
19415
19947
|
minRole: ROLE_ADMIN$2,
|
|
19416
19948
|
keywords: ["wordpress", "migrate"]
|
|
19417
19949
|
}, {
|
|
19418
19950
|
id: "settings",
|
|
19419
|
-
title:
|
|
19951
|
+
title: {
|
|
19952
|
+
id: "Tz0i8g",
|
|
19953
|
+
message: "Settings"
|
|
19954
|
+
},
|
|
19420
19955
|
to: "/settings",
|
|
19421
19956
|
icon: Gear,
|
|
19422
19957
|
minRole: ROLE_ADMIN$2,
|
|
19423
19958
|
keywords: ["configuration", "preferences"]
|
|
19424
19959
|
}, {
|
|
19425
19960
|
id: "security",
|
|
19426
|
-
title:
|
|
19961
|
+
title: {
|
|
19962
|
+
id: "zro6wS",
|
|
19963
|
+
message: "Security Settings"
|
|
19964
|
+
},
|
|
19427
19965
|
to: "/settings/security",
|
|
19428
19966
|
icon: Gear,
|
|
19429
19967
|
minRole: ROLE_ADMIN$2,
|
|
@@ -19444,16 +19982,17 @@ function buildNavItems(manifest, userRole) {
|
|
|
19444
19982
|
}
|
|
19445
19983
|
return items.filter((item) => !item.minRole || userRole >= item.minRole);
|
|
19446
19984
|
}
|
|
19447
|
-
function filterNavItems(items, query) {
|
|
19985
|
+
function filterNavItems(items, query, translate) {
|
|
19448
19986
|
if (!query) return items;
|
|
19449
19987
|
const lowerQuery = query.toLowerCase();
|
|
19450
19988
|
return items.filter((item) => {
|
|
19451
|
-
const titleMatch = item.title.toLowerCase().includes(lowerQuery);
|
|
19989
|
+
const titleMatch = (typeof item.title === "string" ? item.title : translate(item.title)).toLowerCase().includes(lowerQuery);
|
|
19452
19990
|
const keywordMatch = item.keywords?.some((k) => k.toLowerCase().includes(lowerQuery));
|
|
19453
19991
|
return titleMatch || keywordMatch;
|
|
19454
19992
|
});
|
|
19455
19993
|
}
|
|
19456
19994
|
function AdminCommandPalette({ manifest }) {
|
|
19995
|
+
const { _: _t } = useLingui();
|
|
19457
19996
|
const [open, setOpen] = React.useState(false);
|
|
19458
19997
|
const [query, setQuery] = React.useState("");
|
|
19459
19998
|
const navigate = useNavigate$1();
|
|
@@ -19468,14 +20007,22 @@ function AdminCommandPalette({ manifest }) {
|
|
|
19468
20007
|
});
|
|
19469
20008
|
const isPendingSearch = query.length >= 2 && query !== debouncedQuery || isSearching;
|
|
19470
20009
|
const allNavItems = React.useMemo(() => buildNavItems(manifest, userRole), [manifest, userRole]);
|
|
19471
|
-
const filteredNavItems = React.useMemo(() => filterNavItems(allNavItems, query), [
|
|
20010
|
+
const filteredNavItems = React.useMemo(() => filterNavItems(allNavItems, query, _t), [
|
|
20011
|
+
allNavItems,
|
|
20012
|
+
query,
|
|
20013
|
+
_t
|
|
20014
|
+
]);
|
|
19472
20015
|
const resultGroups = React.useMemo(() => {
|
|
19473
20016
|
const groups = [];
|
|
19474
20017
|
if (filteredNavItems.length > 0) groups.push({
|
|
19475
|
-
|
|
20018
|
+
id: "navigation",
|
|
20019
|
+
label: {
|
|
20020
|
+
id: "UxKoFf",
|
|
20021
|
+
message: "Navigation"
|
|
20022
|
+
},
|
|
19476
20023
|
items: filteredNavItems.map((item) => ({
|
|
19477
20024
|
id: item.id,
|
|
19478
|
-
title: item.title,
|
|
20025
|
+
title: typeof item.title === "string" ? item.title : _t(item.title),
|
|
19479
20026
|
to: item.to,
|
|
19480
20027
|
params: item.params,
|
|
19481
20028
|
icon: /* @__PURE__ */ jsx(item.icon, { className: "h-4 w-4" })
|
|
@@ -19483,7 +20030,7 @@ function AdminCommandPalette({ manifest }) {
|
|
|
19483
20030
|
});
|
|
19484
20031
|
if (searchResults?.items && searchResults.items.length > 0) {
|
|
19485
20032
|
const contentItems = searchResults.items.map((result) => {
|
|
19486
|
-
const
|
|
20033
|
+
const collectionLabel = manifest.collections[result.collection]?.label ?? result.collection;
|
|
19487
20034
|
return {
|
|
19488
20035
|
id: `content-${result.id}`,
|
|
19489
20036
|
title: result.title || result.slug,
|
|
@@ -19493,12 +20040,16 @@ function AdminCommandPalette({ manifest }) {
|
|
|
19493
20040
|
id: result.id
|
|
19494
20041
|
},
|
|
19495
20042
|
icon: /* @__PURE__ */ jsx(FileText, { className: "h-4 w-4" }),
|
|
19496
|
-
description:
|
|
20043
|
+
description: collectionLabel,
|
|
19497
20044
|
collection: result.collection
|
|
19498
20045
|
};
|
|
19499
20046
|
});
|
|
19500
20047
|
groups.push({
|
|
19501
|
-
|
|
20048
|
+
id: "content",
|
|
20049
|
+
label: {
|
|
20050
|
+
id: "4b3oEV",
|
|
20051
|
+
message: "Content"
|
|
20052
|
+
},
|
|
19502
20053
|
items: contentItems
|
|
19503
20054
|
});
|
|
19504
20055
|
}
|
|
@@ -19506,7 +20057,8 @@ function AdminCommandPalette({ manifest }) {
|
|
|
19506
20057
|
}, [
|
|
19507
20058
|
filteredNavItems,
|
|
19508
20059
|
searchResults,
|
|
19509
|
-
manifest.collections
|
|
20060
|
+
manifest.collections,
|
|
20061
|
+
_t
|
|
19510
20062
|
]);
|
|
19511
20063
|
useHotkeys("mod+k", (e) => {
|
|
19512
20064
|
e.preventDefault();
|
|
@@ -19534,12 +20086,15 @@ function AdminCommandPalette({ manifest }) {
|
|
|
19534
20086
|
items: resultGroups,
|
|
19535
20087
|
value: query,
|
|
19536
20088
|
onValueChange: setQuery,
|
|
19537
|
-
itemToStringValue: (group) => group.label,
|
|
20089
|
+
itemToStringValue: (group) => _t(group.label),
|
|
19538
20090
|
onSelect: handleSelect,
|
|
19539
20091
|
getSelectableItems: (groups) => groups.flatMap((g) => g.items),
|
|
19540
20092
|
children: [
|
|
19541
20093
|
/* @__PURE__ */ jsx(CommandPalette.Input, {
|
|
19542
|
-
placeholder:
|
|
20094
|
+
placeholder: _t({
|
|
20095
|
+
id: "z/bggT",
|
|
20096
|
+
message: "Search pages and content..."
|
|
20097
|
+
}),
|
|
19543
20098
|
leading: /* @__PURE__ */ jsx(MagnifyingGlass, {
|
|
19544
20099
|
className: "h-4 w-4 text-kumo-subtle",
|
|
19545
20100
|
weight: "bold"
|
|
@@ -19547,14 +20102,17 @@ function AdminCommandPalette({ manifest }) {
|
|
|
19547
20102
|
}),
|
|
19548
20103
|
/* @__PURE__ */ jsx(CommandPalette.List, { children: isPendingSearch ? /* @__PURE__ */ jsx(CommandPalette.Loading, {}) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(CommandPalette.Results, { children: (group) => /* @__PURE__ */ jsxs(CommandPalette.Group, {
|
|
19549
20104
|
items: group.items,
|
|
19550
|
-
children: [/* @__PURE__ */ jsx(CommandPalette.GroupLabel, { children: group.label }), /* @__PURE__ */ jsx(CommandPalette.Items, { children: (item) => /* @__PURE__ */ jsx(CommandPalette.ResultItem, {
|
|
20105
|
+
children: [/* @__PURE__ */ jsx(CommandPalette.GroupLabel, { children: _t(group.label) }), /* @__PURE__ */ jsx(CommandPalette.Items, { children: (item) => /* @__PURE__ */ jsx(CommandPalette.ResultItem, {
|
|
19551
20106
|
value: item,
|
|
19552
20107
|
title: item.title,
|
|
19553
20108
|
description: item.description,
|
|
19554
20109
|
icon: item.icon,
|
|
19555
20110
|
onClick: (e) => handleItemClick(item, e)
|
|
19556
20111
|
}, item.id) })]
|
|
19557
|
-
}, group.
|
|
20112
|
+
}, group.id) }), /* @__PURE__ */ jsx(CommandPalette.Empty, { children: _t({
|
|
20113
|
+
id: "AxPAXW",
|
|
20114
|
+
message: "No results found"
|
|
20115
|
+
}) })] }) }),
|
|
19558
20116
|
/* @__PURE__ */ jsx(CommandPalette.Footer, { children: /* @__PURE__ */ jsxs("div", {
|
|
19559
20117
|
className: "flex items-center gap-4 text-kumo-subtle",
|
|
19560
20118
|
children: [
|
|
@@ -19563,21 +20121,30 @@ function AdminCommandPalette({ manifest }) {
|
|
|
19563
20121
|
children: [/* @__PURE__ */ jsx("kbd", {
|
|
19564
20122
|
className: "rounded bg-kumo-control px-1.5 py-0.5 text-xs",
|
|
19565
20123
|
children: "Enter"
|
|
19566
|
-
}), /* @__PURE__ */ jsx("span", { children:
|
|
20124
|
+
}), /* @__PURE__ */ jsx("span", { children: _t({
|
|
20125
|
+
id: "jpBN9M",
|
|
20126
|
+
message: "to select"
|
|
20127
|
+
}) })]
|
|
19567
20128
|
}),
|
|
19568
20129
|
/* @__PURE__ */ jsxs("span", {
|
|
19569
20130
|
className: "flex items-center gap-1",
|
|
19570
20131
|
children: [/* @__PURE__ */ jsxs("kbd", {
|
|
19571
20132
|
className: "rounded bg-kumo-control px-1.5 py-0.5 text-xs",
|
|
19572
20133
|
children: [IS_MAC ? "Cmd" : "Ctrl", "+Enter"]
|
|
19573
|
-
}), /* @__PURE__ */ jsx("span", { children:
|
|
20134
|
+
}), /* @__PURE__ */ jsx("span", { children: _t({
|
|
20135
|
+
id: "k2rZ7L",
|
|
20136
|
+
message: "new tab"
|
|
20137
|
+
}) })]
|
|
19574
20138
|
}),
|
|
19575
20139
|
/* @__PURE__ */ jsxs("span", {
|
|
19576
20140
|
className: "flex items-center gap-1",
|
|
19577
20141
|
children: [/* @__PURE__ */ jsx("kbd", {
|
|
19578
20142
|
className: "rounded bg-kumo-control px-1.5 py-0.5 text-xs",
|
|
19579
20143
|
children: "Esc"
|
|
19580
|
-
}), /* @__PURE__ */ jsx("span", { children:
|
|
20144
|
+
}), /* @__PURE__ */ jsx("span", { children: _t({
|
|
20145
|
+
id: "UbVgIu",
|
|
20146
|
+
message: "to close"
|
|
20147
|
+
}) })]
|
|
19581
20148
|
})
|
|
19582
20149
|
]
|
|
19583
20150
|
}) })
|
|
@@ -19906,7 +20473,11 @@ function SidebarNav({ manifest }) {
|
|
|
19906
20473
|
] }),
|
|
19907
20474
|
/* @__PURE__ */ jsx(KumoSidebar.Footer, { children: /* @__PURE__ */ jsxs("p", {
|
|
19908
20475
|
className: "emdash-nav-label px-3 py-2 text-[11px] text-white/30",
|
|
19909
|
-
children: [
|
|
20476
|
+
children: [
|
|
20477
|
+
"EmDash CMS v",
|
|
20478
|
+
manifest.version || "0.0.0",
|
|
20479
|
+
manifest.commit && ` (${manifest.commit})`
|
|
20480
|
+
]
|
|
19910
20481
|
}) })
|
|
19911
20482
|
]
|
|
19912
20483
|
})] });
|
|
@@ -20047,13 +20618,71 @@ function Header() {
|
|
|
20047
20618
|
*
|
|
20048
20619
|
* Shown to new users on their first login to welcome them to EmDash.
|
|
20049
20620
|
*/
|
|
20050
|
-
|
|
20051
|
-
|
|
20052
|
-
|
|
20053
|
-
|
|
20054
|
-
|
|
20055
|
-
|
|
20056
|
-
|
|
20621
|
+
const MSG_ROLE_ADMINISTRATOR = {
|
|
20622
|
+
id: "Faptqt",
|
|
20623
|
+
message: "Administrator"
|
|
20624
|
+
};
|
|
20625
|
+
const MSG_ROLE_EDITOR = {
|
|
20626
|
+
id: "uBAxNB",
|
|
20627
|
+
message: "Editor"
|
|
20628
|
+
};
|
|
20629
|
+
const MSG_ROLE_AUTHOR = {
|
|
20630
|
+
id: "VbeIOx",
|
|
20631
|
+
message: "Author"
|
|
20632
|
+
};
|
|
20633
|
+
const MSG_ROLE_CONTRIBUTOR = {
|
|
20634
|
+
id: "3L51iw",
|
|
20635
|
+
message: "Contributor"
|
|
20636
|
+
};
|
|
20637
|
+
const MSG_ROLE_SUBSCRIBER = {
|
|
20638
|
+
id: "M2vfqB",
|
|
20639
|
+
message: "Subscriber"
|
|
20640
|
+
};
|
|
20641
|
+
function roleDescriptor(role) {
|
|
20642
|
+
if (role >= 50) return MSG_ROLE_ADMINISTRATOR;
|
|
20643
|
+
if (role >= 40) return MSG_ROLE_EDITOR;
|
|
20644
|
+
if (role >= 30) return MSG_ROLE_AUTHOR;
|
|
20645
|
+
if (role >= 20) return MSG_ROLE_CONTRIBUTOR;
|
|
20646
|
+
return MSG_ROLE_SUBSCRIBER;
|
|
20647
|
+
}
|
|
20648
|
+
const MSG_ACCOUNT_CREATED = {
|
|
20649
|
+
id: "ATCJJC",
|
|
20650
|
+
message: "Your account has been created successfully."
|
|
20651
|
+
};
|
|
20652
|
+
const MSG_YOUR_ROLE = {
|
|
20653
|
+
id: "T25KCz",
|
|
20654
|
+
message: "Your Role"
|
|
20655
|
+
};
|
|
20656
|
+
const MSG_SCOPE_ADMIN = {
|
|
20657
|
+
id: "T8yDG9",
|
|
20658
|
+
message: "You have full access to manage this site, including users, settings, and all content."
|
|
20659
|
+
};
|
|
20660
|
+
const MSG_SCOPE_EDITOR = {
|
|
20661
|
+
id: "Ic/8JR",
|
|
20662
|
+
message: "You can manage content, media, menus, and taxonomies."
|
|
20663
|
+
};
|
|
20664
|
+
const MSG_SCOPE_AUTHOR = {
|
|
20665
|
+
id: "kKNInt",
|
|
20666
|
+
message: "You can create and edit your own content."
|
|
20667
|
+
};
|
|
20668
|
+
const MSG_SCOPE_CONTRIBUTOR = {
|
|
20669
|
+
id: "nzN9WF",
|
|
20670
|
+
message: "You can view and contribute to the site."
|
|
20671
|
+
};
|
|
20672
|
+
function scopeDescriptor(isAdmin, userRole) {
|
|
20673
|
+
if (isAdmin) return MSG_SCOPE_ADMIN;
|
|
20674
|
+
if (userRole >= 40) return MSG_SCOPE_EDITOR;
|
|
20675
|
+
if (userRole >= 30) return MSG_SCOPE_AUTHOR;
|
|
20676
|
+
return MSG_SCOPE_CONTRIBUTOR;
|
|
20677
|
+
}
|
|
20678
|
+
const MSG_ADMIN_INVITE = {
|
|
20679
|
+
id: "QwxfcZ",
|
|
20680
|
+
message: "As an administrator, you can invite other users from the Users section."
|
|
20681
|
+
};
|
|
20682
|
+
const MSG_CLOSE = {
|
|
20683
|
+
id: "yz7wBu",
|
|
20684
|
+
message: "Close"
|
|
20685
|
+
};
|
|
20057
20686
|
async function dismissWelcome() {
|
|
20058
20687
|
const response = await apiFetch("/_emdash/api/auth/me", {
|
|
20059
20688
|
method: "POST",
|
|
@@ -20063,6 +20692,7 @@ async function dismissWelcome() {
|
|
|
20063
20692
|
if (!response.ok) await throwResponseError(response, "Failed to dismiss welcome");
|
|
20064
20693
|
}
|
|
20065
20694
|
function WelcomeModal({ open, onClose, userName, userRole }) {
|
|
20695
|
+
const { _: _t } = useLingui();
|
|
20066
20696
|
const queryClient = useQueryClient();
|
|
20067
20697
|
const dismissMutation = useMutation({
|
|
20068
20698
|
mutationFn: dismissWelcome,
|
|
@@ -20083,8 +20713,17 @@ function WelcomeModal({ open, onClose, userName, userRole }) {
|
|
|
20083
20713
|
const handleGetStarted = () => {
|
|
20084
20714
|
dismissMutation.mutate();
|
|
20085
20715
|
};
|
|
20086
|
-
const roleLabel =
|
|
20716
|
+
const roleLabel = _t(roleDescriptor(userRole));
|
|
20087
20717
|
const isAdmin = userRole >= 50;
|
|
20718
|
+
const firstName = userName?.split(" ")?.[0]?.trim() ?? "";
|
|
20719
|
+
const titleDescriptor = firstName.length > 0 ? {
|
|
20720
|
+
id: "7vQyJA",
|
|
20721
|
+
message: "Welcome to EmDash, {firstName}!",
|
|
20722
|
+
values: { firstName }
|
|
20723
|
+
} : {
|
|
20724
|
+
id: "N5RCak",
|
|
20725
|
+
message: "Welcome to EmDash!"
|
|
20726
|
+
};
|
|
20088
20727
|
return /* @__PURE__ */ jsx(Dialog.Root, {
|
|
20089
20728
|
open,
|
|
20090
20729
|
onOpenChange: (isOpen) => !isOpen && handleGetStarted(),
|
|
@@ -20094,16 +20733,16 @@ function WelcomeModal({ open, onClose, userName, userRole }) {
|
|
|
20094
20733
|
/* @__PURE__ */ jsxs("div", {
|
|
20095
20734
|
className: "flex items-start justify-between gap-4",
|
|
20096
20735
|
children: [/* @__PURE__ */ jsx("div", { className: "flex-1" }), /* @__PURE__ */ jsx(Dialog.Close, {
|
|
20097
|
-
"aria-label":
|
|
20736
|
+
"aria-label": _t(MSG_CLOSE),
|
|
20098
20737
|
render: (props) => /* @__PURE__ */ jsxs(Button, {
|
|
20099
20738
|
...props,
|
|
20100
20739
|
variant: "ghost",
|
|
20101
20740
|
shape: "square",
|
|
20102
|
-
"aria-label":
|
|
20741
|
+
"aria-label": _t(MSG_CLOSE),
|
|
20103
20742
|
className: "absolute right-4 top-4",
|
|
20104
20743
|
children: [/* @__PURE__ */ jsx(X, { className: "h-4 w-4" }), /* @__PURE__ */ jsx("span", {
|
|
20105
20744
|
className: "sr-only",
|
|
20106
|
-
children:
|
|
20745
|
+
children: _t(MSG_CLOSE)
|
|
20107
20746
|
})]
|
|
20108
20747
|
})
|
|
20109
20748
|
})]
|
|
@@ -20115,17 +20754,13 @@ function WelcomeModal({ open, onClose, userName, userRole }) {
|
|
|
20115
20754
|
className: "mx-auto mb-4",
|
|
20116
20755
|
children: /* @__PURE__ */ jsx(LogoIcon, { className: "h-16 w-16" })
|
|
20117
20756
|
}),
|
|
20118
|
-
/* @__PURE__ */
|
|
20757
|
+
/* @__PURE__ */ jsx(Dialog.Title, {
|
|
20119
20758
|
className: "text-2xl font-semibold leading-none tracking-tight",
|
|
20120
|
-
children:
|
|
20121
|
-
"Welcome to EmDash",
|
|
20122
|
-
userName ? `, ${userName.split(" ")[0]}` : "",
|
|
20123
|
-
"!"
|
|
20124
|
-
]
|
|
20759
|
+
children: _t(titleDescriptor)
|
|
20125
20760
|
}),
|
|
20126
20761
|
/* @__PURE__ */ jsx(Dialog.Description, {
|
|
20127
20762
|
className: "text-base text-kumo-subtle",
|
|
20128
|
-
children:
|
|
20763
|
+
children: _t(MSG_ACCOUNT_CREATED)
|
|
20129
20764
|
})
|
|
20130
20765
|
]
|
|
20131
20766
|
}),
|
|
@@ -20136,7 +20771,7 @@ function WelcomeModal({ open, onClose, userName, userRole }) {
|
|
|
20136
20771
|
children: [
|
|
20137
20772
|
/* @__PURE__ */ jsx("div", {
|
|
20138
20773
|
className: "text-sm font-medium",
|
|
20139
|
-
children:
|
|
20774
|
+
children: _t(MSG_YOUR_ROLE)
|
|
20140
20775
|
}),
|
|
20141
20776
|
/* @__PURE__ */ jsx("div", {
|
|
20142
20777
|
className: "text-lg font-semibold text-kumo-brand",
|
|
@@ -20144,20 +20779,12 @@ function WelcomeModal({ open, onClose, userName, userRole }) {
|
|
|
20144
20779
|
}),
|
|
20145
20780
|
/* @__PURE__ */ jsx("p", {
|
|
20146
20781
|
className: "text-sm text-kumo-subtle mt-1",
|
|
20147
|
-
children: isAdmin
|
|
20782
|
+
children: _t(scopeDescriptor(isAdmin, userRole))
|
|
20148
20783
|
})
|
|
20149
20784
|
]
|
|
20150
|
-
}), isAdmin && /* @__PURE__ */
|
|
20785
|
+
}), isAdmin && /* @__PURE__ */ jsx("p", {
|
|
20151
20786
|
className: "text-sm text-kumo-subtle",
|
|
20152
|
-
children:
|
|
20153
|
-
"As an administrator, you can invite other users from the",
|
|
20154
|
-
" ",
|
|
20155
|
-
/* @__PURE__ */ jsx("span", {
|
|
20156
|
-
className: "font-medium",
|
|
20157
|
-
children: "Users"
|
|
20158
|
-
}),
|
|
20159
|
-
" section."
|
|
20160
|
-
]
|
|
20787
|
+
children: _t(MSG_ADMIN_INVITE)
|
|
20161
20788
|
})]
|
|
20162
20789
|
}),
|
|
20163
20790
|
/* @__PURE__ */ jsx("div", {
|
|
@@ -20166,7 +20793,13 @@ function WelcomeModal({ open, onClose, userName, userRole }) {
|
|
|
20166
20793
|
onClick: handleGetStarted,
|
|
20167
20794
|
disabled: dismissMutation.isPending,
|
|
20168
20795
|
size: "lg",
|
|
20169
|
-
children: dismissMutation.isPending ?
|
|
20796
|
+
children: dismissMutation.isPending ? _t({
|
|
20797
|
+
id: "Z3FXyt",
|
|
20798
|
+
message: "Loading..."
|
|
20799
|
+
}) : _t({
|
|
20800
|
+
id: "c3b0B0",
|
|
20801
|
+
message: "Get Started"
|
|
20802
|
+
})
|
|
20170
20803
|
})
|
|
20171
20804
|
})
|
|
20172
20805
|
]
|
|
@@ -21645,22 +22278,29 @@ function isPaletteItem(data) {
|
|
|
21645
22278
|
/** Built-in widget types available in the palette */
|
|
21646
22279
|
const BUILTIN_WIDGETS = [{
|
|
21647
22280
|
id: "palette-content",
|
|
21648
|
-
label:
|
|
21649
|
-
|
|
21650
|
-
|
|
21651
|
-
|
|
21652
|
-
|
|
21653
|
-
|
|
22281
|
+
label: {
|
|
22282
|
+
id: "ESoS5n",
|
|
22283
|
+
message: "Content Block"
|
|
22284
|
+
},
|
|
22285
|
+
description: {
|
|
22286
|
+
id: "oYoiTA",
|
|
22287
|
+
message: "Rich text content"
|
|
22288
|
+
},
|
|
22289
|
+
input: { type: "content" }
|
|
21654
22290
|
}, {
|
|
21655
22291
|
id: "palette-menu",
|
|
21656
|
-
label:
|
|
21657
|
-
|
|
21658
|
-
|
|
21659
|
-
|
|
21660
|
-
|
|
21661
|
-
|
|
22292
|
+
label: {
|
|
22293
|
+
id: "zucql+",
|
|
22294
|
+
message: "Menu"
|
|
22295
|
+
},
|
|
22296
|
+
description: {
|
|
22297
|
+
id: "an2U5p",
|
|
22298
|
+
message: "Display a navigation menu"
|
|
22299
|
+
},
|
|
22300
|
+
input: { type: "menu" }
|
|
21662
22301
|
}];
|
|
21663
22302
|
function Widgets() {
|
|
22303
|
+
const { _: _t } = useLingui();
|
|
21664
22304
|
const queryClient = useQueryClient();
|
|
21665
22305
|
const toastManager = Toast.useToastManager();
|
|
21666
22306
|
const [isCreateAreaOpen, setIsCreateAreaOpen] = React.useState(false);
|
|
@@ -21902,9 +22542,12 @@ function Widgets() {
|
|
|
21902
22542
|
className: "space-y-2",
|
|
21903
22543
|
children: [BUILTIN_WIDGETS.map((item) => /* @__PURE__ */ jsx(DraggablePaletteItem, {
|
|
21904
22544
|
id: item.id,
|
|
21905
|
-
label: item.label,
|
|
21906
|
-
description: item.description,
|
|
21907
|
-
widgetInput:
|
|
22545
|
+
label: _t(item.label),
|
|
22546
|
+
description: _t(item.description),
|
|
22547
|
+
widgetInput: {
|
|
22548
|
+
...item.input,
|
|
22549
|
+
title: _t(item.label)
|
|
22550
|
+
}
|
|
21908
22551
|
}, item.id)), components.map((comp) => /* @__PURE__ */ jsx(DraggablePaletteItem, {
|
|
21909
22552
|
id: `palette-comp-${comp.id}`,
|
|
21910
22553
|
label: comp.label,
|
|
@@ -24668,50 +25311,11 @@ function BylinesPage() {
|
|
|
24668
25311
|
|
|
24669
25312
|
//#endregion
|
|
24670
25313
|
//#region src/components/users/RoleBadge.tsx
|
|
24671
|
-
/** Role level to name mapping */
|
|
24672
|
-
const ROLE_CONFIG = {
|
|
24673
|
-
10: {
|
|
24674
|
-
label: "Subscriber",
|
|
24675
|
-
color: "gray",
|
|
24676
|
-
description: "Can view content"
|
|
24677
|
-
},
|
|
24678
|
-
20: {
|
|
24679
|
-
label: "Contributor",
|
|
24680
|
-
color: "blue",
|
|
24681
|
-
description: "Can create content"
|
|
24682
|
-
},
|
|
24683
|
-
30: {
|
|
24684
|
-
label: "Author",
|
|
24685
|
-
color: "green",
|
|
24686
|
-
description: "Can publish own content"
|
|
24687
|
-
},
|
|
24688
|
-
40: {
|
|
24689
|
-
label: "Editor",
|
|
24690
|
-
color: "purple",
|
|
24691
|
-
description: "Can manage all content"
|
|
24692
|
-
},
|
|
24693
|
-
50: {
|
|
24694
|
-
label: "Admin",
|
|
24695
|
-
color: "red",
|
|
24696
|
-
description: "Full access"
|
|
24697
|
-
}
|
|
24698
|
-
};
|
|
24699
|
-
/** Get role config, with fallback for unknown roles */
|
|
24700
|
-
function getRoleConfig(role) {
|
|
24701
|
-
return ROLE_CONFIG[role] ?? {
|
|
24702
|
-
label: `Role ${role}`,
|
|
24703
|
-
color: "gray",
|
|
24704
|
-
description: "Unknown role"
|
|
24705
|
-
};
|
|
24706
|
-
}
|
|
24707
|
-
/** Get role label from role level */
|
|
24708
|
-
function getRoleLabel(role) {
|
|
24709
|
-
return getRoleConfig(role).label;
|
|
24710
|
-
}
|
|
24711
25314
|
/**
|
|
24712
25315
|
* Role badge component with semantic colors
|
|
24713
25316
|
*/
|
|
24714
25317
|
function RoleBadge({ role, size = "sm", showDescription = false, className }) {
|
|
25318
|
+
const { _: _t } = useLingui();
|
|
24715
25319
|
const config = getRoleConfig(role);
|
|
24716
25320
|
return /* @__PURE__ */ jsxs("span", {
|
|
24717
25321
|
className: cn("inline-flex items-center rounded-full font-medium", {
|
|
@@ -24724,41 +25328,13 @@ function RoleBadge({ role, size = "sm", showDescription = false, className }) {
|
|
|
24724
25328
|
purple: "bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-200",
|
|
24725
25329
|
red: "bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200"
|
|
24726
25330
|
}[config.color], className),
|
|
24727
|
-
title: showDescription ? void 0 : config.description,
|
|
24728
|
-
children: [config.label, showDescription && /* @__PURE__ */ jsxs("span", {
|
|
25331
|
+
title: showDescription ? void 0 : _t(config.description),
|
|
25332
|
+
children: [_t(config.label), showDescription && /* @__PURE__ */ jsxs("span", {
|
|
24729
25333
|
className: "ml-1 opacity-75",
|
|
24730
|
-
children: ["- ", config.description]
|
|
25334
|
+
children: ["- ", _t(config.description)]
|
|
24731
25335
|
})]
|
|
24732
25336
|
});
|
|
24733
25337
|
}
|
|
24734
|
-
/** List of all roles for dropdowns */
|
|
24735
|
-
const ROLES = [
|
|
24736
|
-
{
|
|
24737
|
-
value: 10,
|
|
24738
|
-
label: "Subscriber",
|
|
24739
|
-
description: "Can view content"
|
|
24740
|
-
},
|
|
24741
|
-
{
|
|
24742
|
-
value: 20,
|
|
24743
|
-
label: "Contributor",
|
|
24744
|
-
description: "Can create content"
|
|
24745
|
-
},
|
|
24746
|
-
{
|
|
24747
|
-
value: 30,
|
|
24748
|
-
label: "Author",
|
|
24749
|
-
description: "Can publish own content"
|
|
24750
|
-
},
|
|
24751
|
-
{
|
|
24752
|
-
value: 40,
|
|
24753
|
-
label: "Editor",
|
|
24754
|
-
description: "Can manage all content"
|
|
24755
|
-
},
|
|
24756
|
-
{
|
|
24757
|
-
value: 50,
|
|
24758
|
-
label: "Admin",
|
|
24759
|
-
description: "Full access"
|
|
24760
|
-
}
|
|
24761
|
-
];
|
|
24762
25338
|
|
|
24763
25339
|
//#endregion
|
|
24764
25340
|
//#region src/components/users/UserList.tsx
|
|
@@ -24766,6 +25342,22 @@ const ROLES = [
|
|
|
24766
25342
|
* User list component with search, filter, and table display
|
|
24767
25343
|
*/
|
|
24768
25344
|
function UserList({ users, isLoading, hasMore, searchQuery, roleFilter, onSearchChange, onRoleFilterChange, onSelectUser, onInviteUser, onLoadMore }) {
|
|
25345
|
+
const { _: _t } = useLingui();
|
|
25346
|
+
const { roles, roleLabels } = useRolesConfig();
|
|
25347
|
+
const roleFilterSelectItems = React.useMemo(() => ({
|
|
25348
|
+
all: _t({
|
|
25349
|
+
id: "Hm90t3",
|
|
25350
|
+
message: "All roles"
|
|
25351
|
+
}),
|
|
25352
|
+
...roleLabels
|
|
25353
|
+
}), [_t, roleLabels]);
|
|
25354
|
+
const roleFilterSelectOptions = React.useMemo(() => [{
|
|
25355
|
+
value: "all",
|
|
25356
|
+
label: _t({
|
|
25357
|
+
id: "Hm90t3",
|
|
25358
|
+
message: "All roles"
|
|
25359
|
+
})
|
|
25360
|
+
}, ...roles], [_t, roles]);
|
|
24769
25361
|
return /* @__PURE__ */ jsxs("div", {
|
|
24770
25362
|
className: "space-y-4",
|
|
24771
25363
|
children: [
|
|
@@ -24795,21 +25387,15 @@ function UserList({ users, isLoading, hasMore, searchQuery, roleFilter, onSearch
|
|
|
24795
25387
|
onChange: (e) => onSearchChange(e.target.value),
|
|
24796
25388
|
"aria-label": "Search users"
|
|
24797
25389
|
})]
|
|
24798
|
-
}), /* @__PURE__ */
|
|
25390
|
+
}), /* @__PURE__ */ jsx(Select, {
|
|
24799
25391
|
value: roleFilter?.toString() ?? "all",
|
|
24800
25392
|
onValueChange: (value) => onRoleFilterChange(value === "all" || value === null ? void 0 : parseInt(value, 10)),
|
|
24801
|
-
items:
|
|
24802
|
-
all: "All roles",
|
|
24803
|
-
...Object.fromEntries(ROLES.map((r) => [r.value.toString(), r.label]))
|
|
24804
|
-
},
|
|
25393
|
+
items: roleFilterSelectItems,
|
|
24805
25394
|
"aria-label": "Filter by role",
|
|
24806
|
-
children:
|
|
24807
|
-
value:
|
|
24808
|
-
children:
|
|
24809
|
-
}
|
|
24810
|
-
value: role.value.toString(),
|
|
24811
|
-
children: role.label
|
|
24812
|
-
}, role.value))]
|
|
25395
|
+
children: roleFilterSelectOptions.map((option) => /* @__PURE__ */ jsx(Select.Option, {
|
|
25396
|
+
value: option.value,
|
|
25397
|
+
children: option.label
|
|
25398
|
+
}, option.value))
|
|
24813
25399
|
})]
|
|
24814
25400
|
}),
|
|
24815
25401
|
/* @__PURE__ */ jsx("div", {
|
|
@@ -24986,6 +25572,7 @@ function UserListSkeleton() {
|
|
|
24986
25572
|
* User detail slide-over panel with inline editing
|
|
24987
25573
|
*/
|
|
24988
25574
|
function UserDetail({ user, isLoading, isOpen, isSaving, isSendingRecovery, recoverySent, recoveryError, currentUserId, onClose, onSave, onDisable, onEnable, onSendRecovery }) {
|
|
25575
|
+
const { roles, roleLabels, getRoleLabel } = useRolesConfig();
|
|
24989
25576
|
const [name, setName] = React.useState(user?.name ?? "");
|
|
24990
25577
|
const [email, setEmail] = React.useState(user?.email ?? "");
|
|
24991
25578
|
const [role, setRole] = React.useState(user?.role ?? 30);
|
|
@@ -25097,8 +25684,8 @@ function UserDetail({ user, isLoading, isOpen, isSaving, isSendingRecovery, reco
|
|
|
25097
25684
|
label: "Role",
|
|
25098
25685
|
value: role.toString(),
|
|
25099
25686
|
onValueChange: (v) => v !== null && setRole(parseInt(v, 10)),
|
|
25100
|
-
items:
|
|
25101
|
-
children:
|
|
25687
|
+
items: roleLabels,
|
|
25688
|
+
children: roles.map((r) => /* @__PURE__ */ jsx(Select.Option, {
|
|
25102
25689
|
value: r.value.toString(),
|
|
25103
25690
|
children: /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", { children: r.label }), /* @__PURE__ */ jsx("div", {
|
|
25104
25691
|
className: "text-xs text-kumo-subtle",
|
|
@@ -25309,6 +25896,7 @@ function UserDetailSkeleton() {
|
|
|
25309
25896
|
* Invite user modal — sends invite email or shows copy-link fallback
|
|
25310
25897
|
*/
|
|
25311
25898
|
function InviteUserModal({ open, isSending, error, inviteUrl, onOpenChange, onInvite }) {
|
|
25899
|
+
const { roles, roleLabels } = useRolesConfig();
|
|
25312
25900
|
const [email, setEmail] = React.useState("");
|
|
25313
25901
|
const [role, setRole] = React.useState(30);
|
|
25314
25902
|
const [copied, setCopied] = React.useState(false);
|
|
@@ -25436,8 +26024,8 @@ function InviteUserModal({ open, isSending, error, inviteUrl, onOpenChange, onIn
|
|
|
25436
26024
|
label: "Role",
|
|
25437
26025
|
value: role.toString(),
|
|
25438
26026
|
onValueChange: (v) => v !== null && setRole(parseInt(v, 10)),
|
|
25439
|
-
items:
|
|
25440
|
-
children:
|
|
26027
|
+
items: roleLabels,
|
|
26028
|
+
children: roles.map((r) => /* @__PURE__ */ jsx(Select.Option, {
|
|
25441
26029
|
value: r.value.toString(),
|
|
25442
26030
|
children: /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", { children: r.label }), /* @__PURE__ */ jsx("div", {
|
|
25443
26031
|
className: "text-xs text-kumo-subtle",
|
|
@@ -25492,6 +26080,7 @@ function useDebounce(value, delay) {
|
|
|
25492
26080
|
return debouncedValue;
|
|
25493
26081
|
}
|
|
25494
26082
|
function UsersPage() {
|
|
26083
|
+
const { getRoleLabel } = useRolesConfig();
|
|
25495
26084
|
const queryClient = useQueryClient();
|
|
25496
26085
|
const [searchQuery, setSearchQuery] = React.useState("");
|
|
25497
26086
|
const [roleFilter, setRoleFilter] = React.useState();
|