rimecms 0.24.5 → 0.25.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/adapter-sqlite/generate-schema/index.server.js +9 -9
- package/dist/adapter-sqlite/generate-schema/root.server.d.ts +5 -0
- package/dist/adapter-sqlite/generate-schema/root.server.js +5 -0
- package/dist/adapter-sqlite/generate-schema/templates.server.js +9 -6
- package/dist/core/collections/upload/hooks/convert-base64.server.js +2 -1
- package/dist/core/collections/upload/upload.d.ts +2 -1
- package/dist/core/collections/upload/util/converter.js +4 -3
- package/dist/core/config/client/augment-directories.d.ts +6 -0
- package/dist/core/config/client/augment-directories.js +11 -0
- package/dist/core/config/client/build-config.d.ts +2 -0
- package/dist/core/config/client/build-config.js +3 -1
- package/dist/core/config/server/augment-directories.server.d.ts +6 -0
- package/dist/core/config/server/augment-directories.server.js +37 -0
- package/dist/core/config/server/build-config.server.d.ts +2 -0
- package/dist/core/config/server/build-config.server.js +4 -6
- package/dist/core/config/shared/upload-directories.d.ts +7 -2
- package/dist/core/config/shared/upload-directories.js +118 -48
- package/dist/core/config/types.d.ts +6 -0
- package/dist/core/naming.d.ts +1 -1
- package/dist/core/naming.js +1 -1
- package/dist/fields/relation/component/Relation.svelte +2 -1
- package/dist/fields/relation/index.d.ts +3 -2
- package/dist/panel/components/fields/RenderFields.svelte +5 -2
- package/dist/panel/components/fields/RenderFields.svelte.d.ts +3 -1
- package/dist/panel/components/sections/collection/grid/CollectionGrid.svelte +6 -14
- package/dist/panel/components/sections/collection/grid/grid-item/FolderEdit.svelte +79 -0
- package/dist/panel/components/sections/collection/grid/grid-item/FolderEdit.svelte.d.ts +10 -0
- package/dist/panel/components/sections/collection/grid/grid-item/FolderWithActions.svelte +11 -44
- package/dist/panel/components/sections/collection/grid/grid-item/FolderWithActions.svelte.d.ts +0 -2
- package/dist/panel/components/sections/collection/header/Header.svelte +1 -1
- package/dist/panel/components/sections/collection/header/create-folder/CreateFolder.svelte +90 -0
- package/dist/panel/components/sections/collection/header/create-folder/CreateFolder.svelte.d.ts +7 -0
- package/dist/panel/components/sections/collection/tree/CollectionTree.svelte +1 -1
- package/dist/panel/components/sections/document/AuthFooter.svelte +11 -2
- package/dist/panel/components/sections/document/Settings.svelte +6 -2
- package/dist/panel/components/ui/dialog/dialog-content.svelte +20 -5
- package/dist/panel/components/ui/dialog/dialog-content.svelte.d.ts +7 -2
- package/dist/panel/context/collection.svelte.js +3 -1
- package/dist/panel/context/documentForm.svelte.d.ts +14 -6
- package/dist/panel/context/documentForm.svelte.js +15 -7
- package/dist/panel/pages/auth/forgot-password/ForgotPassword.svelte +1 -0
- package/dist/util/string.d.ts +14 -0
- package/dist/util/string.js +19 -0
- package/package.json +1 -1
- package/dist/core/collections/upload/directory-input-config.d.ts +0 -2
- package/dist/core/collections/upload/directory-input-config.js +0 -12
- package/dist/panel/components/sections/collection/header/CreateUploadFolder.svelte +0 -68
- package/dist/panel/components/sections/collection/header/CreateUploadFolder.svelte.d.ts +0 -7
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Directory } from '../../../../../../core/collections/upload/upload';
|
|
3
|
+
import type { BuiltCollectionClient } from '../../../../../../core/config/types';
|
|
4
|
+
import { withDirectoriesSuffix } from '../../../../../../core/naming';
|
|
5
|
+
import * as Dialog from '../../../../ui/dialog/index.js';
|
|
6
|
+
import { t__ } from '../../../../../../core/i18n';
|
|
7
|
+
import RenderFields from '../../../../../index.server.js/components/fields/RenderFields.svelte';
|
|
8
|
+
import Button from '../../../../../index.server.js/components/ui/button/button.svelte';
|
|
9
|
+
import { API_PROXY, setAPIProxyContext } from '../../../../../index.server.js/context/api-proxy.svelte';
|
|
10
|
+
import { getConfigContext } from '../../../../../index.server.js/context/config.svelte';
|
|
11
|
+
import {
|
|
12
|
+
setDocumentFormContext,
|
|
13
|
+
type FormSuccessData
|
|
14
|
+
} from '../../../../../index.server.js/context/documentForm.svelte';
|
|
15
|
+
import { getUserContext } from '../../../../../index.server.js/context/user.svelte';
|
|
16
|
+
|
|
17
|
+
type Props = {
|
|
18
|
+
open: boolean;
|
|
19
|
+
folder: Directory;
|
|
20
|
+
collection: BuiltCollectionClient;
|
|
21
|
+
};
|
|
22
|
+
let { folder, collection, open = $bindable() }: Props = $props();
|
|
23
|
+
|
|
24
|
+
const user = getUserContext();
|
|
25
|
+
const configCtx = getConfigContext();
|
|
26
|
+
const config = configCtx.getCollection(withDirectoriesSuffix(collection.slug));
|
|
27
|
+
setAPIProxyContext(API_PROXY.DOCUMENT);
|
|
28
|
+
let formElement = $state<HTMLFormElement>();
|
|
29
|
+
|
|
30
|
+
async function beforeRedirect(data?: FormSuccessData) {
|
|
31
|
+
open = false;
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const form = setDocumentFormContext({
|
|
36
|
+
element: () => formElement,
|
|
37
|
+
initial: folder,
|
|
38
|
+
config,
|
|
39
|
+
readOnly: !config.access.update(user.attributes, { id: folder.id }),
|
|
40
|
+
key: folder._type,
|
|
41
|
+
beforeRedirect: beforeRedirect
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
function handleKeyDown(event: KeyboardEvent) {
|
|
45
|
+
if (!open) return;
|
|
46
|
+
if (!formElement) throw Error('formElement is not defined');
|
|
47
|
+
if ((event.ctrlKey || event.metaKey) && event.key === 's') {
|
|
48
|
+
event.preventDefault();
|
|
49
|
+
if (!form.canSubmit) return;
|
|
50
|
+
const saveButton = formElement.querySelector('button[data-submit]');
|
|
51
|
+
if (saveButton) {
|
|
52
|
+
formElement.requestSubmit(saveButton as HTMLButtonElement);
|
|
53
|
+
} else {
|
|
54
|
+
// Fallback to default submit if no specific button found
|
|
55
|
+
formElement.requestSubmit();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
</script>
|
|
60
|
+
|
|
61
|
+
<svelte:window onkeydown={handleKeyDown} />
|
|
62
|
+
|
|
63
|
+
<Dialog.Root bind:open>
|
|
64
|
+
<Dialog.Content>
|
|
65
|
+
{#snippet child({ props })}
|
|
66
|
+
<form use:form.enhance action={form.buildPanelActionUrl()} bind:this={formElement} {...props}>
|
|
67
|
+
<Dialog.Header>
|
|
68
|
+
{t__('common.rename_dialog_title', folder.name)}
|
|
69
|
+
</Dialog.Header>
|
|
70
|
+
<RenderFields {form} fields={config.fields} />
|
|
71
|
+
|
|
72
|
+
<Dialog.Footer --rz-justify-content="space-between">
|
|
73
|
+
<Button data-submit disabled={!form.canSubmit} type="submit">{t__('common.save')}</Button>
|
|
74
|
+
<Button onclick={() => (open = false)} variant="secondary">{t__('common.cancel')}</Button>
|
|
75
|
+
</Dialog.Footer>
|
|
76
|
+
</form>
|
|
77
|
+
{/snippet}
|
|
78
|
+
</Dialog.Content>
|
|
79
|
+
</Dialog.Root>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Directory } from '../../../../../../core/collections/upload/upload';
|
|
2
|
+
import type { BuiltCollectionClient } from '../../../../../../core/config/types';
|
|
3
|
+
type Props = {
|
|
4
|
+
open: boolean;
|
|
5
|
+
folder: Directory;
|
|
6
|
+
collection: BuiltCollectionClient;
|
|
7
|
+
};
|
|
8
|
+
declare const FolderEdit: import("svelte").Component<Props, {}, "open">;
|
|
9
|
+
type FolderEdit = ReturnType<typeof FolderEdit>;
|
|
10
|
+
export default FolderEdit;
|
|
@@ -1,72 +1,50 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { goto, invalidateAll } from '$app/navigation';
|
|
3
3
|
import { apiUrl } from '../../../../../../core/api/index.js';
|
|
4
|
-
import { directoryInput } from '../../../../../../core/collections/upload/directory-input-config.js';
|
|
5
4
|
import type { Directory } from '../../../../../../core/collections/upload/upload.js';
|
|
6
|
-
import type { UploadPath } from '../../../../../../core/collections/upload/util/path.js';
|
|
7
5
|
import type { BuiltCollectionClient } from '../../../../../../core/config/types.js';
|
|
8
6
|
import { PARAMS } from '../../../../../../core/constant.js';
|
|
9
7
|
import { withDirectoriesSuffix } from '../../../../../../core/naming.js';
|
|
10
8
|
import type { GenericDoc } from '../../../../../../core/types/doc.js';
|
|
11
|
-
import Input from '../../../../../../fields/text/component/Text.svelte';
|
|
12
9
|
import Button from '../../../../ui/button/button.svelte';
|
|
13
10
|
import ContextMenu from '../../../../ui/context-menu/ContextMenu.svelte';
|
|
14
11
|
import ContextMenuItem from '../../../../ui/context-menu/ContextMenuItem.svelte';
|
|
15
12
|
import * as Dialog from '../../../../ui/dialog/index.js';
|
|
16
13
|
import { API_PROXY, getAPIProxyContext } from '../../../../../context/api-proxy.svelte.js';
|
|
17
|
-
import { setFormContext } from '../../../../../context/form.svelte.js';
|
|
18
14
|
import { panelUrl } from '../../../../../util/url.js';
|
|
19
15
|
import { trycatchFetch } from '../../../../../../util/function.js';
|
|
20
16
|
import { toast } from 'svelte-sonner';
|
|
21
17
|
import { t__ } from '../../../../../../core/i18n/index.js';
|
|
22
18
|
import Folder from './Folder.svelte';
|
|
19
|
+
import FolderEdit from './FolderEdit.svelte';
|
|
23
20
|
|
|
24
21
|
type Props = {
|
|
25
22
|
folder: Directory;
|
|
26
23
|
collection: BuiltCollectionClient;
|
|
27
24
|
onDelete?: (path: string) => void;
|
|
28
|
-
onRename?: (oldPath: UploadPath, newPath: UploadPath) => void;
|
|
29
25
|
onDocumentDrop: (args: { documentId: string; path: string }) => void;
|
|
30
26
|
draggable?: 'true';
|
|
31
27
|
};
|
|
32
|
-
const { folder, collection, onDelete,
|
|
28
|
+
const { folder, collection, onDelete, onDocumentDrop, draggable }: Props = $props();
|
|
33
29
|
|
|
34
30
|
let deleteConfirmOpen = $state(false);
|
|
35
|
-
let
|
|
31
|
+
let editFolderDialogOpen = $state(false);
|
|
36
32
|
let message = $state('');
|
|
37
33
|
let rootElement = $state<HTMLButtonElement>();
|
|
38
34
|
let isDragging = $state(false);
|
|
39
35
|
const isRoot = $derived(folder.name === '...');
|
|
40
36
|
const APIProxy = getAPIProxyContext(API_PROXY.ROOT);
|
|
41
|
-
const childFilesURL = $derived(
|
|
37
|
+
const childFilesURL = $derived(
|
|
38
|
+
`${apiUrl(collection.kebab)}?where[_path][equals]=${folder.id}&select=id`
|
|
39
|
+
);
|
|
42
40
|
const childFiles = $derived(APIProxy.getRessource<{ docs: GenericDoc[] }>(childFilesURL));
|
|
43
41
|
const childFilesCount = $derived(childFiles.data?.docs?.length || 0);
|
|
44
42
|
const baseFolderApiURL = $derived(`${apiUrl(withDirectoriesSuffix(collection.kebab))}`);
|
|
45
|
-
const childFoldersURL = $derived(
|
|
43
|
+
const childFoldersURL = $derived(
|
|
44
|
+
`${baseFolderApiURL}?where[parent][equals]=${folder.id}&select=id`
|
|
45
|
+
);
|
|
46
46
|
const childFolders = $derived(APIProxy.getRessource<{ docs: GenericDoc[] }>(childFoldersURL));
|
|
47
47
|
const childFoldersCount = $derived(childFolders.data?.docs?.length || 0);
|
|
48
|
-
const renameFolderForm = setFormContext({ name: '' }, 'rename-folder');
|
|
49
|
-
|
|
50
|
-
const renameField = renameFolderForm.useField('name', directoryInput);
|
|
51
|
-
|
|
52
|
-
async function handleRename() {
|
|
53
|
-
const renameURL = `${baseFolderApiURL}/${folder.id}`;
|
|
54
|
-
const newPath = `${folder.parent}:${renameField.value}` as UploadPath;
|
|
55
|
-
const [error] = await trycatchFetch(renameURL, {
|
|
56
|
-
method: 'PATCH',
|
|
57
|
-
body: JSON.stringify({
|
|
58
|
-
id: newPath
|
|
59
|
-
})
|
|
60
|
-
});
|
|
61
|
-
if (error) {
|
|
62
|
-
return toast.error('Error renaming folder');
|
|
63
|
-
}
|
|
64
|
-
toast.success(t__('rename_success'));
|
|
65
|
-
renameDialogOpen = false;
|
|
66
|
-
if (onRename) {
|
|
67
|
-
onRename(folder.id, newPath);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
48
|
|
|
71
49
|
async function handleGetDeleteInfos() {
|
|
72
50
|
message = t__(
|
|
@@ -184,7 +162,7 @@
|
|
|
184
162
|
<!-- -->
|
|
185
163
|
{#snippet content()}
|
|
186
164
|
<ContextMenuItem onclick={handleGetDeleteInfos}>Delete</ContextMenuItem>
|
|
187
|
-
<ContextMenuItem onclick={() => (
|
|
165
|
+
<ContextMenuItem onclick={() => (editFolderDialogOpen = true)}>Edit</ContextMenuItem>
|
|
188
166
|
{/snippet}
|
|
189
167
|
<!-- -->
|
|
190
168
|
</ContextMenu>
|
|
@@ -208,18 +186,7 @@
|
|
|
208
186
|
</Dialog.Content>
|
|
209
187
|
</Dialog.Root>
|
|
210
188
|
|
|
211
|
-
<
|
|
212
|
-
<Dialog.Content>
|
|
213
|
-
<Dialog.Header>
|
|
214
|
-
{t__('common.rename_dialog_title', folder.name)}
|
|
215
|
-
</Dialog.Header>
|
|
216
|
-
<Input form={renameFolderForm} config={directoryInput} />
|
|
217
|
-
<Dialog.Footer --rz-justify-content="space-between">
|
|
218
|
-
<Button disabled={!renameFolderForm.canSubmit} onclick={handleRename}>Rename</Button>
|
|
219
|
-
<Button onclick={() => (renameDialogOpen = false)} variant="secondary">Cancel</Button>
|
|
220
|
-
</Dialog.Footer>
|
|
221
|
-
</Dialog.Content>
|
|
222
|
-
</Dialog.Root>
|
|
189
|
+
<FolderEdit bind:open={editFolderDialogOpen} {folder} {collection} />
|
|
223
190
|
|
|
224
191
|
<style>
|
|
225
192
|
:root {
|
package/dist/panel/components/sections/collection/grid/grid-item/FolderWithActions.svelte.d.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import type { Directory } from '../../../../../../core/collections/upload/upload.js';
|
|
2
|
-
import type { UploadPath } from '../../../../../../core/collections/upload/util/path.js';
|
|
3
2
|
import type { BuiltCollectionClient } from '../../../../../../core/config/types.js';
|
|
4
3
|
type Props = {
|
|
5
4
|
folder: Directory;
|
|
6
5
|
collection: BuiltCollectionClient;
|
|
7
6
|
onDelete?: (path: string) => void;
|
|
8
|
-
onRename?: (oldPath: UploadPath, newPath: UploadPath) => void;
|
|
9
7
|
onDocumentDrop: (args: {
|
|
10
8
|
documentId: string;
|
|
11
9
|
path: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { type CollectionContext } from '../../../../context/collection.svelte.js';
|
|
3
3
|
import { getContext } from 'svelte';
|
|
4
|
-
import CreateUploadFolder from './
|
|
4
|
+
import CreateUploadFolder from './create-folder/CreateFolder.svelte';
|
|
5
5
|
import DisplayMode from './DisplayMode.svelte';
|
|
6
6
|
import SelectUI from './SelectUI.svelte';
|
|
7
7
|
import Separator from './Separator.svelte';
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { invalidateAll } from '$app/navigation';
|
|
3
|
+
import { t__ } from '../../../../../../core/i18n/index.js';
|
|
4
|
+
import { withDirectoriesSuffix } from '../../../../../../core/naming';
|
|
5
|
+
import Button from '../../../../ui/button/button.svelte';
|
|
6
|
+
import * as Dialog from '../../../../ui/dialog/index.js';
|
|
7
|
+
import type { CollectionContext } from '../../../../../context/collection.svelte.js';
|
|
8
|
+
import { FolderPlus } from '@lucide/svelte';
|
|
9
|
+
import RenderFields from '../../../../../index.server.js/components/fields/RenderFields.svelte';
|
|
10
|
+
import { API_PROXY, setAPIProxyContext } from '../../../../../index.server.js/context/api-proxy.svelte';
|
|
11
|
+
import { getConfigContext } from '../../../../../index.server.js/context/config.svelte';
|
|
12
|
+
import {
|
|
13
|
+
setDocumentFormContext,
|
|
14
|
+
type FormSuccessData
|
|
15
|
+
} from '../../../../../index.server.js/context/documentForm.svelte';
|
|
16
|
+
|
|
17
|
+
type Props = { collection: CollectionContext };
|
|
18
|
+
const { collection }: Props = $props();
|
|
19
|
+
|
|
20
|
+
const configCtx = getConfigContext();
|
|
21
|
+
const directoriesConfig = configCtx.getCollection(withDirectoriesSuffix(collection.config.slug));
|
|
22
|
+
let open = $state(false);
|
|
23
|
+
setAPIProxyContext(API_PROXY.DOCUMENT);
|
|
24
|
+
let formElement = $state<HTMLFormElement>();
|
|
25
|
+
|
|
26
|
+
async function beforeRedirect(data?: FormSuccessData) {
|
|
27
|
+
open = false;
|
|
28
|
+
invalidateAll();
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const form = setDocumentFormContext({
|
|
33
|
+
element: () => formElement,
|
|
34
|
+
initial: {
|
|
35
|
+
parent: collection.upload.currentPath
|
|
36
|
+
},
|
|
37
|
+
readOnly: false,
|
|
38
|
+
config: directoriesConfig,
|
|
39
|
+
key: withDirectoriesSuffix(collection.config.slug),
|
|
40
|
+
beforeRedirect: beforeRedirect
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
function handleKeyDown(event: KeyboardEvent) {
|
|
44
|
+
if (!open) return;
|
|
45
|
+
if (!formElement) throw Error('formElement is not defined');
|
|
46
|
+
if ((event.ctrlKey || event.metaKey) && event.key === 's') {
|
|
47
|
+
event.preventDefault();
|
|
48
|
+
if (!form.canSubmit) return;
|
|
49
|
+
const saveButton = formElement.querySelector('button[data-submit]');
|
|
50
|
+
if (saveButton) {
|
|
51
|
+
formElement.requestSubmit(saveButton as HTMLButtonElement);
|
|
52
|
+
} else {
|
|
53
|
+
// Fallback to default submit if no specific button found
|
|
54
|
+
formElement.requestSubmit();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
</script>
|
|
59
|
+
|
|
60
|
+
<svelte:window onkeydown={handleKeyDown} />
|
|
61
|
+
|
|
62
|
+
<Dialog.Root bind:open>
|
|
63
|
+
<Dialog.Trigger>
|
|
64
|
+
{#snippet child(props)}
|
|
65
|
+
<Button
|
|
66
|
+
disabled={collection.selectMode}
|
|
67
|
+
onclick={() => (open = true)}
|
|
68
|
+
size="icon-sm"
|
|
69
|
+
variant="ghost"
|
|
70
|
+
{...props}
|
|
71
|
+
>
|
|
72
|
+
<FolderPlus size={17} />
|
|
73
|
+
</Button>
|
|
74
|
+
{/snippet}
|
|
75
|
+
</Dialog.Trigger>
|
|
76
|
+
<Dialog.Content class="rz-status-dialog">
|
|
77
|
+
{#snippet child({ props })}
|
|
78
|
+
<form use:form.enhance action={form.buildPanelActionUrl()} bind:this={formElement} {...props}>
|
|
79
|
+
<Dialog.Header>{t__('common.create_folder')}</Dialog.Header>
|
|
80
|
+
<RenderFields {form} fields={directoriesConfig.fields} />
|
|
81
|
+
<Dialog.Footer --rz-justify-content="space-between">
|
|
82
|
+
<Button data-submit disabled={!form.canSubmit} type="submit">
|
|
83
|
+
{t__('common.create')}
|
|
84
|
+
</Button>
|
|
85
|
+
<Button variant="secondary" onclick={() => (open = false)}>Cancel</Button>
|
|
86
|
+
</Dialog.Footer>
|
|
87
|
+
</form>
|
|
88
|
+
{/snippet}
|
|
89
|
+
</Dialog.Content>
|
|
90
|
+
</Dialog.Root>
|
package/dist/panel/components/sections/collection/header/create-folder/CreateFolder.svelte.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { CollectionContext } from '../../../../../context/collection.svelte.js';
|
|
2
|
+
type Props = {
|
|
3
|
+
collection: CollectionContext;
|
|
4
|
+
};
|
|
5
|
+
declare const CreateFolder: import("svelte").Component<Props, {}, "">;
|
|
6
|
+
type CreateFolder = ReturnType<typeof CreateFolder>;
|
|
7
|
+
export default CreateFolder;
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
onEnd: function (evt) {
|
|
28
28
|
const { newIndex, oldIndex } = evt;
|
|
29
29
|
|
|
30
|
-
//@ts-expect-error annoying
|
|
31
30
|
const fromParentId =
|
|
31
|
+
//@ts-expect-error annoying
|
|
32
32
|
evt.item.getAttribute('data-parent') || evt.item.__attributes?.['data-parent'];
|
|
33
33
|
//@ts-expect-error annoying
|
|
34
34
|
const toParentId = evt.to.getAttribute('data-id') || evt.to.__attributes?.['data-id'];
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
async function sendPasswordResetLink() {
|
|
28
|
+
// @ts-expect-error better-auth type issue to resolve
|
|
28
29
|
const { data, error } = await authClient.forgetPassword({
|
|
29
30
|
email: form.values.email,
|
|
30
31
|
redirectTo: `/reset-password?slug=staff`
|
|
@@ -37,7 +38,10 @@
|
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
const passwordConfig = text('password')
|
|
41
|
+
const passwordConfig = text('password')
|
|
42
|
+
.placeholder(t__('fields.password'))
|
|
43
|
+
.required()
|
|
44
|
+
.validate(validate.password);
|
|
41
45
|
const Text = text('mock').component;
|
|
42
46
|
|
|
43
47
|
const confirmPasswordConfig = text('confirmPassword')
|
|
@@ -59,7 +63,12 @@
|
|
|
59
63
|
{#if operation === 'create'}
|
|
60
64
|
{#if isAuthConfig(collection) && collection.auth.type === 'password'}
|
|
61
65
|
<Text {form} type="password" config={passwordConfig.compile()} path="password" />
|
|
62
|
-
<Text
|
|
66
|
+
<Text
|
|
67
|
+
{form}
|
|
68
|
+
type="password"
|
|
69
|
+
config={confirmPasswordConfig.compile()}
|
|
70
|
+
path="confirmPassword"
|
|
71
|
+
/>
|
|
63
72
|
{/if}
|
|
64
73
|
{:else if user.attributes.roles.includes('admin') && page.data?.hasMailer}
|
|
65
74
|
{#if isAuthConfig(collection) && collection.auth.type === 'password'}
|
|
@@ -21,7 +21,9 @@
|
|
|
21
21
|
let deleteConfirmOpen = $state(false);
|
|
22
22
|
let dupplicateConfirmOpen = $state(false);
|
|
23
23
|
const isCollection = $derived(form.config.type === 'collection');
|
|
24
|
-
const allowDuplicate = $derived(
|
|
24
|
+
const allowDuplicate = $derived(
|
|
25
|
+
form.config.type === 'collection' && !form.config.auth && !form.config.upload
|
|
26
|
+
);
|
|
25
27
|
const locale = getLocaleContext();
|
|
26
28
|
|
|
27
29
|
function handleNewDraft() {
|
|
@@ -42,7 +44,9 @@
|
|
|
42
44
|
const isVersionPage = $derived(page.url.pathname.includes('/versions'));
|
|
43
45
|
|
|
44
46
|
function handleViewVersion() {
|
|
45
|
-
const basUrl = isCollection
|
|
47
|
+
const basUrl = isCollection
|
|
48
|
+
? panelUrl(form.config.kebab, form.values.id)
|
|
49
|
+
: panelUrl(form.config.kebab);
|
|
46
50
|
return goto(`${basUrl}/versions?${PARAMS.VERSION_ID}=${form.values.versionId}`);
|
|
47
51
|
}
|
|
48
52
|
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
Dialog as DialogPrimitive,
|
|
4
|
+
type DialogContentSnippetProps,
|
|
5
|
+
type WithoutChildrenOrChild
|
|
6
|
+
} from 'bits-ui';
|
|
3
7
|
import type { Snippet } from 'svelte';
|
|
4
|
-
import * as Dialog from './index.js';
|
|
5
8
|
import './dialog-content.css';
|
|
9
|
+
import * as Dialog from './index.js';
|
|
6
10
|
|
|
7
11
|
let {
|
|
8
12
|
ref = $bindable(null),
|
|
@@ -11,14 +15,25 @@
|
|
|
11
15
|
children,
|
|
12
16
|
...restProps
|
|
13
17
|
}: WithoutChildrenOrChild<DialogPrimitive.ContentProps> & {
|
|
14
|
-
children
|
|
15
|
-
|
|
18
|
+
children?: Snippet;
|
|
19
|
+
child?: Snippet<
|
|
20
|
+
[
|
|
21
|
+
DialogContentSnippetProps & {
|
|
22
|
+
props: Record<string, unknown>;
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
>;
|
|
26
|
+
size?: 'sm' | 'default' | 'lg';
|
|
16
27
|
} = $props();
|
|
17
28
|
</script>
|
|
18
29
|
|
|
19
30
|
<Dialog.Portal>
|
|
20
31
|
<Dialog.Overlay />
|
|
21
|
-
<DialogPrimitive.Content
|
|
32
|
+
<DialogPrimitive.Content
|
|
33
|
+
bind:ref
|
|
34
|
+
class="rz-dialog-content rz-dialog-content--{size} {className}"
|
|
35
|
+
{...restProps}
|
|
36
|
+
>
|
|
22
37
|
{@render children?.()}
|
|
23
38
|
</DialogPrimitive.Content>
|
|
24
39
|
</Dialog.Portal>
|
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
import { Dialog as DialogPrimitive, type WithoutChildrenOrChild } from 'bits-ui';
|
|
1
|
+
import { Dialog as DialogPrimitive, type DialogContentSnippetProps, type WithoutChildrenOrChild } from 'bits-ui';
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import './dialog-content.css';
|
|
4
4
|
type $$ComponentProps = WithoutChildrenOrChild<DialogPrimitive.ContentProps> & {
|
|
5
|
-
children
|
|
5
|
+
children?: Snippet;
|
|
6
|
+
child?: Snippet<[
|
|
7
|
+
DialogContentSnippetProps & {
|
|
8
|
+
props: Record<string, unknown>;
|
|
9
|
+
}
|
|
10
|
+
]>;
|
|
6
11
|
size?: 'sm' | 'default' | 'lg';
|
|
7
12
|
};
|
|
8
13
|
declare const DialogContent: import("svelte").Component<$$ComponentProps, {}, "ref">;
|
|
@@ -37,7 +37,9 @@ function createCollectionStore(args) {
|
|
|
37
37
|
const hasVersions = $derived(!!config.versions);
|
|
38
38
|
const hasDraft = $derived(config.versions && config.versions.draft);
|
|
39
39
|
onMount(() => {
|
|
40
|
-
displayMode =
|
|
40
|
+
displayMode =
|
|
41
|
+
localStorage.getItem(`collection.${config.slug}.display`) ||
|
|
42
|
+
DISPLAY_MODE.LIST;
|
|
41
43
|
const localSortBy = localStorage.getItem(`collection.${config.slug}.sortBy`);
|
|
42
44
|
sortingBy = localSortBy || 'updatedAt';
|
|
43
45
|
const localSortOrder = localStorage.getItem(`collection.${config.slug}.sortOrder`);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { BuiltAreaClient, BuiltCollectionClient } from '../../core/config/types.js';
|
|
2
2
|
import type { AreaSlug, GenericBlock, GenericDoc, TreeBlock } from '../../core/types/doc.js';
|
|
3
3
|
import type { FormField, SimplerField } from '../../fields/types.js';
|
|
4
|
-
import type { Dic } from '../../util/types.js';
|
|
5
|
-
export declare function setDocumentFormContext<T extends GenericDoc
|
|
4
|
+
import type { Dic, WithOptional } from '../../util/types.js';
|
|
5
|
+
export declare function setDocumentFormContext<T extends WithOptional<GenericDoc, 'id'>>(args: Args<T>): {
|
|
6
6
|
key: string;
|
|
7
7
|
setValue: (path: string, value: any) => void;
|
|
8
8
|
getRawValue: <T_1>(path: string) => NonNullable<T_1> | null;
|
|
@@ -43,7 +43,11 @@ export declare function setDocumentFormContext<T extends GenericDoc>(args: Args<
|
|
|
43
43
|
readonly element: HTMLFormElement;
|
|
44
44
|
readonly canSubmit: boolean;
|
|
45
45
|
readonly processing: boolean;
|
|
46
|
-
values: T
|
|
46
|
+
values: T & {
|
|
47
|
+
_type: any;
|
|
48
|
+
_prototype: any;
|
|
49
|
+
title: any;
|
|
50
|
+
};
|
|
47
51
|
readonly changes: Partial<GenericDoc>;
|
|
48
52
|
readonly errors: {
|
|
49
53
|
readonly length: number;
|
|
@@ -67,7 +71,7 @@ export declare function setDocumentFormContext<T extends GenericDoc>(args: Args<
|
|
|
67
71
|
readonly isLive: boolean;
|
|
68
72
|
setFocusedField(path: string): void;
|
|
69
73
|
};
|
|
70
|
-
export declare function getDocumentFormContext<T extends GenericDoc>(key?: string): {
|
|
74
|
+
export declare function getDocumentFormContext<T extends WithOptional<GenericDoc, 'id'> = GenericDoc>(key?: string): {
|
|
71
75
|
key: string;
|
|
72
76
|
setValue: (path: string, value: any) => void;
|
|
73
77
|
getRawValue: <T_1>(path: string) => NonNullable<T_1> | null;
|
|
@@ -108,7 +112,11 @@ export declare function getDocumentFormContext<T extends GenericDoc>(key?: strin
|
|
|
108
112
|
readonly element: HTMLFormElement;
|
|
109
113
|
readonly canSubmit: boolean;
|
|
110
114
|
readonly processing: boolean;
|
|
111
|
-
values: T
|
|
115
|
+
values: T & {
|
|
116
|
+
_type: any;
|
|
117
|
+
_prototype: any;
|
|
118
|
+
title: any;
|
|
119
|
+
};
|
|
112
120
|
readonly changes: Partial<GenericDoc>;
|
|
113
121
|
readonly errors: {
|
|
114
122
|
readonly length: number;
|
|
@@ -132,7 +140,7 @@ export declare function getDocumentFormContext<T extends GenericDoc>(key?: strin
|
|
|
132
140
|
readonly isLive: boolean;
|
|
133
141
|
setFocusedField(path: string): void;
|
|
134
142
|
};
|
|
135
|
-
export type DocumentFormContext<T extends GenericDoc = GenericDoc> = ReturnType<typeof setDocumentFormContext<T>>;
|
|
143
|
+
export type DocumentFormContext<T extends WithOptional<GenericDoc, 'id'> = GenericDoc> = ReturnType<typeof setDocumentFormContext<T>>;
|
|
136
144
|
type AddBlock = (block: Omit<GenericBlock, 'id' | 'path'>) => void;
|
|
137
145
|
type MoveBlock = (from: number, to: number) => void;
|
|
138
146
|
export type FormSuccessData = {
|
|
@@ -12,6 +12,7 @@ import { isObjectLiteral, omit } from '../../util/object.js';
|
|
|
12
12
|
import cloneDeep from 'clone-deep';
|
|
13
13
|
import { diff } from 'deep-object-diff';
|
|
14
14
|
import { flatten } from 'flat';
|
|
15
|
+
import { richTextJSONToText } from '../../fields/rich-text/client.js';
|
|
15
16
|
import { getContext, setContext } from 'svelte';
|
|
16
17
|
import { toast } from 'svelte-sonner';
|
|
17
18
|
import { t__ } from '../../core/i18n/index.js';
|
|
@@ -23,16 +24,15 @@ import { getCollectionContext } from './collection.svelte.js';
|
|
|
23
24
|
import { setErrorsContext } from './errors.svelte.js';
|
|
24
25
|
import { getLocaleContext } from './locale.svelte.js';
|
|
25
26
|
import { getUserContext } from './user.svelte.js';
|
|
26
|
-
import { richTextJSONToText } from '../../fields/rich-text/client.js';
|
|
27
27
|
function createDocumentFormState({ initial, element, config, readOnly, key, onNestedDocumentCreated, onDataChange, beforeSubmit, beforeRedirect, onFieldFocus }) {
|
|
28
28
|
//
|
|
29
|
-
let
|
|
29
|
+
let initialDoc = $state(initial);
|
|
30
30
|
let doc = $state(initial);
|
|
31
31
|
const documentConfig = compileDocumentConfig(config);
|
|
32
|
-
const changes = $derived(diff(
|
|
32
|
+
const changes = $derived(diff(initialDoc, doc));
|
|
33
33
|
let isDisabled = $state(readOnly);
|
|
34
34
|
let processing = $state(false);
|
|
35
|
-
const operation =
|
|
35
|
+
const operation = doc.id ? 'update' : 'create';
|
|
36
36
|
const user = getUserContext();
|
|
37
37
|
const errors = setErrorsContext(key);
|
|
38
38
|
const isCollection = documentConfig.type === 'collection';
|
|
@@ -65,7 +65,7 @@ function createDocumentFormState({ initial, element, config, readOnly, key, onNe
|
|
|
65
65
|
if (typeof value === 'string') {
|
|
66
66
|
return value;
|
|
67
67
|
}
|
|
68
|
-
return initialTitle || doc.id;
|
|
68
|
+
return initialTitle || doc.id || '[untitled]';
|
|
69
69
|
}
|
|
70
70
|
$effect(() => {
|
|
71
71
|
const rawTitle = getValueAtPath(documentConfig.asTitle, doc) || '[untitled]';
|
|
@@ -511,7 +511,7 @@ function createDocumentFormState({ initial, element, config, readOnly, key, onNe
|
|
|
511
511
|
doc = (data?.document || doc);
|
|
512
512
|
if (nestedLevel === 0) {
|
|
513
513
|
await invalidateAll();
|
|
514
|
-
|
|
514
|
+
initialDoc = doc;
|
|
515
515
|
}
|
|
516
516
|
else {
|
|
517
517
|
toast.success(t__('common.doc_created'));
|
|
@@ -578,6 +578,8 @@ function createDocumentFormState({ initial, element, config, readOnly, key, onNe
|
|
|
578
578
|
};
|
|
579
579
|
};
|
|
580
580
|
const buildPanelActionUrl = () => {
|
|
581
|
+
console.log('@buildPanelActionUrl----');
|
|
582
|
+
console.log(operation);
|
|
581
583
|
// Start with the base URI for the panel
|
|
582
584
|
let panelUri = `/panel/${config.kebab}`;
|
|
583
585
|
// Add the item ID to the URI if we're updating a collection doc
|
|
@@ -686,7 +688,13 @@ function createDocumentFormState({ initial, element, config, readOnly, key, onNe
|
|
|
686
688
|
}
|
|
687
689
|
const FORM_KEY = 'rime.form';
|
|
688
690
|
export function setDocumentFormContext(args) {
|
|
689
|
-
const
|
|
691
|
+
const initial = {
|
|
692
|
+
...args.initial,
|
|
693
|
+
_type: args.initial._type || args.config.type,
|
|
694
|
+
_prototype: args.initial._prototype || args.config.slug,
|
|
695
|
+
title: args.initial.title || '[untitled]'
|
|
696
|
+
};
|
|
697
|
+
const store = createDocumentFormState({ ...args, initial });
|
|
690
698
|
return setContext(`${FORM_KEY}.${args.key}`, store);
|
|
691
699
|
}
|
|
692
700
|
export function getDocumentFormContext(key = 'root') {
|
package/dist/util/string.d.ts
CHANGED
|
@@ -15,6 +15,20 @@ export declare const capitalize: (str: string) => string;
|
|
|
15
15
|
* toCamelCase("hello-world");
|
|
16
16
|
*/
|
|
17
17
|
export declare const toCamelCase: (str: string) => string;
|
|
18
|
+
/**
|
|
19
|
+
* Converts a string to camelCase while preserving a trailing _suffix if it exists.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* // Returns "helloWorld"
|
|
23
|
+
* toCamelCasePreserveTrailingUnderscoreSuffix("helloWorld");
|
|
24
|
+
*
|
|
25
|
+
* // Returns "helloWorld_directories"
|
|
26
|
+
* toCamelCasePreserveTrailingUnderscoreSuffix("hello-world_directories");
|
|
27
|
+
|
|
28
|
+
* // Returns "helloWorld_"
|
|
29
|
+
* toCamelCasePreserveTrailingUnderscoreSuffix("hello-world");
|
|
30
|
+
*/
|
|
31
|
+
export declare const toCamelCasePreserveTrailingUnderscoreSuffix: (str: string) => string;
|
|
18
32
|
export declare function toKebabCase(str: string): string;
|
|
19
33
|
/**
|
|
20
34
|
* Converts a string to PascalCase.
|
package/dist/util/string.js
CHANGED
|
@@ -18,6 +18,25 @@ export const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
|
|
18
18
|
* toCamelCase("hello-world");
|
|
19
19
|
*/
|
|
20
20
|
export const toCamelCase = (str) => camelCase(str);
|
|
21
|
+
/**
|
|
22
|
+
* Converts a string to camelCase while preserving a trailing _suffix if it exists.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* // Returns "helloWorld"
|
|
26
|
+
* toCamelCasePreserveTrailingUnderscoreSuffix("helloWorld");
|
|
27
|
+
*
|
|
28
|
+
* // Returns "helloWorld_directories"
|
|
29
|
+
* toCamelCasePreserveTrailingUnderscoreSuffix("hello-world_directories");
|
|
30
|
+
|
|
31
|
+
* // Returns "helloWorld_"
|
|
32
|
+
* toCamelCasePreserveTrailingUnderscoreSuffix("hello-world");
|
|
33
|
+
*/
|
|
34
|
+
export const toCamelCasePreserveTrailingUnderscoreSuffix = (str) => {
|
|
35
|
+
const suffixMatch = str.match(/(_[a-zA-Z]+)$/);
|
|
36
|
+
const suffix = suffixMatch ? suffixMatch[1] : '';
|
|
37
|
+
const baseString = suffix ? str.slice(0, -suffix.length) : str;
|
|
38
|
+
return camelCase(baseString) + suffix;
|
|
39
|
+
};
|
|
21
40
|
/**
|
|
22
41
|
* Converts a string to kebab-case.
|
|
23
42
|
* Source : https://github.com/angus-c/just/blob/master/packages/string-kebab-case
|
package/package.json
CHANGED