@svadmin/lite 0.10.1 → 0.13.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/README.md +1 -19
- package/dist/compatibility.js +29 -29
- package/dist/components/LiteArrayItem.svelte +2 -2
- package/dist/components/LiteCanvasAnnotation.svelte +3 -1
- package/dist/components/LiteFileInput.svelte +40 -0
- package/dist/components/LiteFileInput.svelte.d.ts +11 -0
- package/dist/components/LiteFileUpload.svelte +53 -0
- package/dist/components/LiteFileUpload.svelte.d.ts +16 -0
- package/dist/components/LiteFilterBuilder.svelte +107 -153
- package/dist/components/LiteFilterBuilder.svelte.d.ts +0 -1
- package/dist/components/LiteForm.svelte +2 -2
- package/dist/components/LiteImportWizard.svelte +2 -1
- package/dist/components/LiteJsonSchemaForm.svelte +136 -70
- package/dist/components/LiteJsonSchemaForm.svelte.d.ts +12 -2
- package/dist/components/LiteMasterDetailView.svelte +2 -2
- package/dist/components/LiteMediaLibraryModal.svelte +5 -2
- package/dist/components/LiteSensitiveDataMask.svelte +2 -1
- package/dist/components/LiteShowField.svelte +6 -4
- package/dist/components/LiteSignaturePad.svelte +3 -1
- package/dist/components/advanced/LiteAutoSaveIndicator.svelte +2 -2
- package/dist/components/advanced/LiteToast.svelte +2 -2
- package/dist/components/advanced/LiteVirtualTable.svelte +6 -5
- package/dist/components/buttons/LiteCloneButton.svelte +3 -0
- package/dist/components/buttons/LiteCreateButton.svelte +3 -0
- package/dist/components/buttons/LiteDeleteButton.svelte +3 -0
- package/dist/components/buttons/LiteEditButton.svelte +3 -0
- package/dist/components/buttons/LiteExportButton.svelte +3 -0
- package/dist/components/buttons/LiteImportButton.svelte +5 -1
- package/dist/components/buttons/LiteListButton.svelte +3 -0
- package/dist/components/buttons/LiteRefreshButton.svelte +3 -0
- package/dist/components/buttons/LiteSaveButton.svelte +3 -0
- package/dist/components/buttons/LiteShowButton.svelte +3 -0
- package/dist/components/compatibility/LiteDirectoryUpload.svelte +4 -3
- package/dist/components/fields/LiteAvatarField.svelte +3 -3
- package/dist/components/fields/LiteCascader.svelte +4 -2
- package/dist/components/fields/LiteDateField.svelte +3 -0
- package/dist/components/fields/LiteDateRangeField.svelte +9 -4
- package/dist/components/fields/LiteFileField.svelte +2 -2
- package/dist/components/fields/LiteTreeSelect.svelte +4 -2
- package/dist/components/pages/LiteListPage.svelte +4 -2
- package/dist/filter-form.d.ts +3 -0
- package/dist/filter-form.js +34 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/lite.css +86 -0
- package/dist/server-adapter.d.ts +15 -15
- package/dist/server-adapter.js +62 -8
- package/package.json +7 -14
- package/dist/polyfill-entry.d.ts +0 -2
- package/dist/polyfill-entry.js +0 -3
- package/dist/polyfill.js +0 -20707
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
<script lang="ts">
|
|
11
11
|
import type { FieldDefinition } from '@svadmin/core';
|
|
12
|
+
import { useTranslation } from '@svadmin/core/i18n';
|
|
12
13
|
|
|
13
14
|
interface Props {
|
|
14
15
|
field?: FieldDefinition;
|
|
@@ -41,12 +42,14 @@
|
|
|
41
42
|
mode = 'show',
|
|
42
43
|
}: Props = $props();
|
|
43
44
|
|
|
45
|
+
const i18n = useTranslation();
|
|
46
|
+
|
|
44
47
|
const start = $derived.by(() => {
|
|
45
48
|
if (startDate !== undefined) return startDate;
|
|
46
49
|
if (Array.isArray(value)) return value[0];
|
|
47
50
|
if (value && typeof value === 'object') {
|
|
48
51
|
const obj = value as Record<string, unknown>;
|
|
49
|
-
return (obj
|
|
52
|
+
return (obj['start'] ?? obj['from']) as string | number | Date | null | undefined;
|
|
50
53
|
}
|
|
51
54
|
return undefined;
|
|
52
55
|
});
|
|
@@ -56,7 +59,7 @@
|
|
|
56
59
|
if (Array.isArray(value)) return value[1];
|
|
57
60
|
if (value && typeof value === 'object') {
|
|
58
61
|
const obj = value as Record<string, unknown>;
|
|
59
|
-
return (obj
|
|
62
|
+
return (obj['end'] ?? obj['to']) as string | number | Date | null | undefined;
|
|
60
63
|
}
|
|
61
64
|
return undefined;
|
|
62
65
|
});
|
|
@@ -118,23 +121,25 @@
|
|
|
118
121
|
<div class="lite-inline-sm" style="display: flex; align-items: center;">
|
|
119
122
|
<input
|
|
120
123
|
type="date"
|
|
124
|
+
lang={i18n.locale}
|
|
121
125
|
name={startKey}
|
|
122
126
|
id={startKey}
|
|
123
127
|
value={toIsoDateInput(start)}
|
|
124
128
|
class="lite-input {hasError ? 'lite-input-error' : ''}"
|
|
125
129
|
style="flex: 1; min-width: 120px;"
|
|
126
|
-
placeholder=
|
|
130
|
+
placeholder={i18n.t('common.startDate')}
|
|
127
131
|
{...field?.required ? { required: true } : {}}
|
|
128
132
|
/>
|
|
129
133
|
<span style="margin: 0 8px; color: #64748b;">{separator}</span>
|
|
130
134
|
<input
|
|
131
135
|
type="date"
|
|
136
|
+
lang={i18n.locale}
|
|
132
137
|
name={endKey}
|
|
133
138
|
id={endKey}
|
|
134
139
|
value={toIsoDateInput(end)}
|
|
135
140
|
class="lite-input {hasError ? 'lite-input-error' : ''}"
|
|
136
141
|
style="flex: 1; min-width: 120px;"
|
|
137
|
-
placeholder=
|
|
142
|
+
placeholder={i18n.t('common.endDate')}
|
|
138
143
|
{...field?.required ? { required: true } : {}}
|
|
139
144
|
/>
|
|
140
145
|
</div>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { FieldDefinition } from '@svadmin/core';
|
|
3
3
|
import { toSafeHref } from '../../security';
|
|
4
|
+
import LiteFileInput from '../LiteFileInput.svelte';
|
|
4
5
|
|
|
5
6
|
interface Props {
|
|
6
7
|
field: FieldDefinition;
|
|
@@ -42,8 +43,7 @@
|
|
|
42
43
|
<span style="font-size: 12px;">Current files: {files.length}</span>
|
|
43
44
|
</div>
|
|
44
45
|
{/if}
|
|
45
|
-
<
|
|
46
|
-
type="file"
|
|
46
|
+
<LiteFileInput
|
|
47
47
|
name={field.key}
|
|
48
48
|
id={field.key}
|
|
49
49
|
class="lite-input {hasError ? 'lite-input-error' : ''}"
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { definedOptions } from '@svadmin/core/options';
|
|
3
|
+
|
|
2
4
|
import type { FieldDefinition } from '@svadmin/core';
|
|
3
5
|
import { t } from '@svadmin/core/i18n';
|
|
4
6
|
|
|
@@ -49,12 +51,12 @@
|
|
|
49
51
|
function flattenTree(nodes: TreeSelectOption[], level = 0): FlatTreeOption[] {
|
|
50
52
|
const list: FlatTreeOption[] = [];
|
|
51
53
|
for (const node of nodes) {
|
|
52
|
-
list.push({
|
|
54
|
+
list.push(definedOptions({
|
|
53
55
|
value: node.value,
|
|
54
56
|
label: node.label,
|
|
55
57
|
level,
|
|
56
58
|
disabled: node.disabled,
|
|
57
|
-
});
|
|
59
|
+
}));
|
|
58
60
|
if (node.children && node.children.length > 0) {
|
|
59
61
|
list.push(...flattenTree(node.children, level + 1));
|
|
60
62
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { definedOptions } from '@svadmin/core/options';
|
|
3
|
+
|
|
2
4
|
import type { ResourceDefinition } from "@svadmin/core";
|
|
3
5
|
import { t } from "@svadmin/core/i18n";
|
|
4
6
|
import LiteTable from "../LiteTable.svelte";
|
|
@@ -134,9 +136,9 @@
|
|
|
134
136
|
<LiteTable
|
|
135
137
|
{records}
|
|
136
138
|
{resource}
|
|
137
|
-
{currentSort}
|
|
139
|
+
{...definedOptions({ "currentSort": currentSort })}
|
|
138
140
|
{currentOrder}
|
|
139
|
-
{currentSearch}
|
|
141
|
+
{...definedOptions({ "currentSearch": currentSearch })}
|
|
140
142
|
{basePath}
|
|
141
143
|
canShow={showView}
|
|
142
144
|
canEdit={showEdit}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** 使用已有拓扑读取当前表单值,不把用户字段名解释成对象路径。服务端仍须独立授权。 */
|
|
2
|
+
export function readFilterForm(filters, fields, data) {
|
|
3
|
+
const operators = new Set(['eq', 'ne', 'contains', 'ncontains', 'gt', 'gte', 'lt', 'lte', 'null', 'nnull']);
|
|
4
|
+
function read(filter, path) {
|
|
5
|
+
const get = (key) => data.get(`filters[${path}][${key}]`);
|
|
6
|
+
if (!('field' in filter)) {
|
|
7
|
+
const operator = get('operator');
|
|
8
|
+
if (operator !== 'and' && operator !== 'or')
|
|
9
|
+
throw new TypeError('Invalid filter group');
|
|
10
|
+
return { operator, value: filter.value.map((child, index) => read(child, `${path}.value.${index}`)) };
|
|
11
|
+
}
|
|
12
|
+
const field = fields.find(candidate => candidate.key === get('field') && candidate.filterable !== false);
|
|
13
|
+
const operator = get('operator');
|
|
14
|
+
if (!field || typeof operator !== 'string' || !operators.has(operator))
|
|
15
|
+
throw new TypeError('Invalid filter rule');
|
|
16
|
+
let value = get('value');
|
|
17
|
+
if (operator === 'null' || operator === 'nnull')
|
|
18
|
+
value = null;
|
|
19
|
+
else if (typeof value !== 'string')
|
|
20
|
+
throw new TypeError('Invalid filter value');
|
|
21
|
+
else if (['number', 'currency', 'percent'].includes(field.type)) {
|
|
22
|
+
if (!value.trim() || !Number.isFinite(Number(value)))
|
|
23
|
+
throw new TypeError('Invalid numeric filter');
|
|
24
|
+
value = Number(value);
|
|
25
|
+
}
|
|
26
|
+
else if (field.type === 'boolean') {
|
|
27
|
+
if (value !== 'true' && value !== 'false')
|
|
28
|
+
throw new TypeError('Invalid boolean filter');
|
|
29
|
+
value = value === 'true';
|
|
30
|
+
}
|
|
31
|
+
return { field: field.key, operator: operator, value };
|
|
32
|
+
}
|
|
33
|
+
return filters.map((filter, index) => read(filter, String(index)));
|
|
34
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ export { default as LiteLayout } from './components/LiteLayout.svelte';
|
|
|
8
8
|
export { default as LiteTable } from './components/LiteTable.svelte';
|
|
9
9
|
export { default as LitePagination } from './components/LitePagination.svelte';
|
|
10
10
|
export { default as LiteForm } from './components/LiteForm.svelte';
|
|
11
|
+
export { default as LiteFileInput } from './components/LiteFileInput.svelte';
|
|
12
|
+
export { default as LiteFileUpload } from './components/LiteFileUpload.svelte';
|
|
11
13
|
export { default as LiteLogin } from './components/LiteLogin.svelte';
|
|
12
14
|
export { default as LiteShow } from './components/LiteShow.svelte';
|
|
13
15
|
export { default as LiteSearch } from './components/LiteSearch.svelte';
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,8 @@ export { default as LiteLayout } from './components/LiteLayout.svelte';
|
|
|
12
12
|
export { default as LiteTable } from './components/LiteTable.svelte';
|
|
13
13
|
export { default as LitePagination } from './components/LitePagination.svelte';
|
|
14
14
|
export { default as LiteForm } from './components/LiteForm.svelte';
|
|
15
|
+
export { default as LiteFileInput } from './components/LiteFileInput.svelte';
|
|
16
|
+
export { default as LiteFileUpload } from './components/LiteFileUpload.svelte';
|
|
15
17
|
export { default as LiteLogin } from './components/LiteLogin.svelte';
|
|
16
18
|
export { default as LiteShow } from './components/LiteShow.svelte';
|
|
17
19
|
export { default as LiteSearch } from './components/LiteSearch.svelte';
|
package/dist/lite.css
CHANGED
|
@@ -471,6 +471,92 @@ a:hover {
|
|
|
471
471
|
box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.12);
|
|
472
472
|
}
|
|
473
473
|
|
|
474
|
+
/* File inputs keep the native form control but replace its browser-localized
|
|
475
|
+
* visible copy with application-controlled labels. */
|
|
476
|
+
.lite-file-picker {
|
|
477
|
+
position: relative;
|
|
478
|
+
display: inline-flex;
|
|
479
|
+
align-items: center;
|
|
480
|
+
min-width: 0;
|
|
481
|
+
min-height: 38px;
|
|
482
|
+
color: #64748b;
|
|
483
|
+
vertical-align: middle;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
.lite-file-picker.lite-input {
|
|
487
|
+
display: flex;
|
|
488
|
+
width: 100%;
|
|
489
|
+
padding: 0;
|
|
490
|
+
border: 0;
|
|
491
|
+
background: transparent;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
.lite-file-picker__native {
|
|
495
|
+
position: absolute;
|
|
496
|
+
z-index: 1;
|
|
497
|
+
top: 0;
|
|
498
|
+
right: 0;
|
|
499
|
+
bottom: 0;
|
|
500
|
+
left: 0;
|
|
501
|
+
width: 100%;
|
|
502
|
+
height: 100%;
|
|
503
|
+
margin: 0;
|
|
504
|
+
opacity: 0;
|
|
505
|
+
cursor: pointer;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
.lite-file-picker__visual {
|
|
509
|
+
display: flex;
|
|
510
|
+
align-items: center;
|
|
511
|
+
width: 100%;
|
|
512
|
+
min-width: 0;
|
|
513
|
+
min-height: 38px;
|
|
514
|
+
overflow: hidden;
|
|
515
|
+
border: 1px solid #cbd5e1;
|
|
516
|
+
border-radius: 6px;
|
|
517
|
+
padding: 6px 10px 6px 6px;
|
|
518
|
+
background: #fff;
|
|
519
|
+
pointer-events: none;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
.lite-file-picker__visual > * + * {
|
|
523
|
+
margin-left: 10px;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
.lite-file-picker__button {
|
|
527
|
+
flex: 0 0 auto;
|
|
528
|
+
display: inline-flex;
|
|
529
|
+
align-items: center;
|
|
530
|
+
min-height: 26px;
|
|
531
|
+
border: 1px solid #cbd5e1;
|
|
532
|
+
border-radius: 4px;
|
|
533
|
+
padding: 0 10px;
|
|
534
|
+
background: #f8fafc;
|
|
535
|
+
color: #334155;
|
|
536
|
+
font-size: 12px;
|
|
537
|
+
white-space: nowrap;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
.lite-file-picker__name {
|
|
541
|
+
min-width: 0;
|
|
542
|
+
overflow: hidden;
|
|
543
|
+
text-overflow: ellipsis;
|
|
544
|
+
white-space: nowrap;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
.lite-file-picker[data-disabled="true"] .lite-file-picker__visual {
|
|
548
|
+
opacity: 0.5;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
.lite-file-picker.lite-input-error .lite-file-picker__visual {
|
|
552
|
+
border-color: #ef4444;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
.lite-file-picker__native:focus + .lite-file-picker__visual {
|
|
556
|
+
border-color: #4f46e5;
|
|
557
|
+
box-shadow: 0 0 0 1px #fff, 0 0 0 3px rgba(79, 70, 229, 0.3);
|
|
558
|
+
}
|
|
559
|
+
|
|
474
560
|
.lite-error-text {
|
|
475
561
|
color: #ef4444;
|
|
476
562
|
font-size: 12px;
|
package/dist/server-adapter.d.ts
CHANGED
|
@@ -55,18 +55,18 @@ export declare function createCrudActions(dp: DataProvider, resource: ResourceDe
|
|
|
55
55
|
} | {
|
|
56
56
|
success: boolean;
|
|
57
57
|
error: string;
|
|
58
|
-
id?:
|
|
59
|
-
values?:
|
|
58
|
+
id?: never;
|
|
59
|
+
values?: never;
|
|
60
60
|
} | {
|
|
61
61
|
success: boolean;
|
|
62
62
|
id: unknown;
|
|
63
|
-
error?:
|
|
64
|
-
values?:
|
|
63
|
+
error?: never;
|
|
64
|
+
values?: never;
|
|
65
65
|
} | {
|
|
66
66
|
success: boolean;
|
|
67
67
|
error: string;
|
|
68
68
|
values: Record<string, unknown>;
|
|
69
|
-
id?:
|
|
69
|
+
id?: never;
|
|
70
70
|
}>;
|
|
71
71
|
update: ({ request }: RequestEvent) => Promise<{
|
|
72
72
|
success: false;
|
|
@@ -76,11 +76,11 @@ export declare function createCrudActions(dp: DataProvider, resource: ResourceDe
|
|
|
76
76
|
} | {
|
|
77
77
|
success: boolean;
|
|
78
78
|
error: string;
|
|
79
|
-
values?:
|
|
79
|
+
values?: never;
|
|
80
80
|
} | {
|
|
81
81
|
success: boolean;
|
|
82
|
-
error?:
|
|
83
|
-
values?:
|
|
82
|
+
error?: never;
|
|
83
|
+
values?: never;
|
|
84
84
|
} | {
|
|
85
85
|
success: boolean;
|
|
86
86
|
error: string;
|
|
@@ -91,14 +91,14 @@ export declare function createCrudActions(dp: DataProvider, resource: ResourceDe
|
|
|
91
91
|
error: string;
|
|
92
92
|
} | {
|
|
93
93
|
success: boolean;
|
|
94
|
-
error?:
|
|
94
|
+
error?: never;
|
|
95
95
|
}>;
|
|
96
96
|
batchDelete: ({ request }: RequestEvent) => Promise<{
|
|
97
97
|
success: boolean;
|
|
98
98
|
error: string;
|
|
99
99
|
} | {
|
|
100
100
|
success: boolean;
|
|
101
|
-
error?:
|
|
101
|
+
error?: never;
|
|
102
102
|
}>;
|
|
103
103
|
};
|
|
104
104
|
/**
|
|
@@ -122,35 +122,35 @@ export declare function createAuthActions(authProvider: AuthProvider): {
|
|
|
122
122
|
error: string;
|
|
123
123
|
} | {
|
|
124
124
|
success: boolean;
|
|
125
|
-
error?:
|
|
125
|
+
error?: never;
|
|
126
126
|
}>;
|
|
127
127
|
register: ({ request }: RequestEvent) => Promise<{
|
|
128
128
|
success: boolean;
|
|
129
129
|
error: string;
|
|
130
130
|
} | {
|
|
131
131
|
success: boolean;
|
|
132
|
-
error?:
|
|
132
|
+
error?: never;
|
|
133
133
|
}>;
|
|
134
134
|
forgot_password: ({ request }: RequestEvent) => Promise<{
|
|
135
135
|
success: boolean;
|
|
136
136
|
error: string;
|
|
137
137
|
} | {
|
|
138
138
|
success: boolean;
|
|
139
|
-
error?:
|
|
139
|
+
error?: never;
|
|
140
140
|
}>;
|
|
141
141
|
update_password: ({ request }: RequestEvent) => Promise<{
|
|
142
142
|
success: boolean;
|
|
143
143
|
error: string;
|
|
144
144
|
} | {
|
|
145
145
|
success: boolean;
|
|
146
|
-
error?:
|
|
146
|
+
error?: never;
|
|
147
147
|
}>;
|
|
148
148
|
update_profile: ({ request }: RequestEvent) => Promise<{
|
|
149
149
|
success: boolean;
|
|
150
150
|
error: string;
|
|
151
151
|
} | {
|
|
152
152
|
success: boolean;
|
|
153
|
-
error?:
|
|
153
|
+
error?: never;
|
|
154
154
|
}>;
|
|
155
155
|
};
|
|
156
156
|
/**
|
package/dist/server-adapter.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { definedOptions } from '@svadmin/core/options';
|
|
1
2
|
import { redirect, isRedirect } from '@sveltejs/kit';
|
|
2
3
|
import { resourceToTypeBoxSchema } from './schema-generator';
|
|
3
4
|
import { parseExplicitBoolean } from './value-normalization';
|
|
@@ -17,7 +18,7 @@ function listRequestState(url, resource) {
|
|
|
17
18
|
const order = sortableField
|
|
18
19
|
? requestedOrder === 'asc' || requestedOrder === 'desc' ? requestedOrder : 'asc'
|
|
19
20
|
: resource.defaultSort?.order ?? 'asc';
|
|
20
|
-
return { page, pageSize, sort, order, search: url.searchParams.get('q') ?? undefined };
|
|
21
|
+
return definedOptions({ page, pageSize, sort, order, search: url.searchParams.get('q') ?? undefined });
|
|
21
22
|
}
|
|
22
23
|
function listRequestFilterValues(resource, url) {
|
|
23
24
|
const values = {};
|
|
@@ -41,7 +42,7 @@ function listRequestFilters(resource, url) {
|
|
|
41
42
|
value: search,
|
|
42
43
|
}));
|
|
43
44
|
if (searchFilters.length === 1) {
|
|
44
|
-
filters.push(searchFilters
|
|
45
|
+
filters.push(...searchFilters);
|
|
45
46
|
}
|
|
46
47
|
else if (searchFilters.length > 1) {
|
|
47
48
|
filters.push({ operator: 'or', value: searchFilters });
|
|
@@ -57,7 +58,60 @@ function listRequestFilters(resource, url) {
|
|
|
57
58
|
});
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
|
-
|
|
61
|
+
const structured = parseStructuredFilters(resource, url);
|
|
62
|
+
return structured.length > 0 ? structured : filters;
|
|
63
|
+
}
|
|
64
|
+
function parseStructuredFilters(resource, url) {
|
|
65
|
+
const entries = [...url.searchParams.entries()]
|
|
66
|
+
.map(([key, value]) => {
|
|
67
|
+
const match = /^filters\[([0-9]+(?:\.value\.[0-9]+)*)\]\[(field|operator|value)\]$/.exec(key);
|
|
68
|
+
return match ? { path: match[1], property: match[2], value } : undefined;
|
|
69
|
+
})
|
|
70
|
+
.filter((entry) => entry !== undefined);
|
|
71
|
+
if (entries.length === 0)
|
|
72
|
+
return [];
|
|
73
|
+
const roots = [];
|
|
74
|
+
for (const entry of entries) {
|
|
75
|
+
const segments = [...entry.path.matchAll(/\d+/g)].map(match => Number(match[0]));
|
|
76
|
+
const rootIndex = segments.shift();
|
|
77
|
+
if (rootIndex === undefined || !Number.isSafeInteger(rootIndex) || rootIndex < 0)
|
|
78
|
+
continue;
|
|
79
|
+
let node = roots[rootIndex];
|
|
80
|
+
if (!node) {
|
|
81
|
+
node = {};
|
|
82
|
+
roots[rootIndex] = node;
|
|
83
|
+
}
|
|
84
|
+
for (const childIndex of segments) {
|
|
85
|
+
if (!Number.isSafeInteger(childIndex) || childIndex < 0)
|
|
86
|
+
break;
|
|
87
|
+
node.children ??= [];
|
|
88
|
+
node = node.children[childIndex] ??= {};
|
|
89
|
+
}
|
|
90
|
+
node[entry.property] = entry.value;
|
|
91
|
+
}
|
|
92
|
+
function compile(node) {
|
|
93
|
+
const operator = node.operator;
|
|
94
|
+
if (node.field && operator && operator !== 'and' && operator !== 'or') {
|
|
95
|
+
const field = resource.fields.find(candidate => candidate.key === node.field);
|
|
96
|
+
if (!field)
|
|
97
|
+
return undefined;
|
|
98
|
+
if (operator === 'null' || operator === 'nnull') {
|
|
99
|
+
return { field: node.field, operator: operator, value: null };
|
|
100
|
+
}
|
|
101
|
+
if (node.value === undefined || node.value === '')
|
|
102
|
+
return undefined;
|
|
103
|
+
const value = field.type === 'number' || field.type === 'currency' || field.type === 'percent'
|
|
104
|
+
? Number(node.value)
|
|
105
|
+
: field.type === 'boolean' ? node.value === 'true' : node.value;
|
|
106
|
+
return { field: node.field, operator: operator, value };
|
|
107
|
+
}
|
|
108
|
+
if ((operator === 'and' || operator === 'or') && node.children) {
|
|
109
|
+
const children = node.children.map(compile).filter((child) => child !== undefined);
|
|
110
|
+
return children.length > 0 ? { operator, value: children } : undefined;
|
|
111
|
+
}
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
114
|
+
return roots.map(compile).filter((filter) => filter !== undefined);
|
|
61
115
|
}
|
|
62
116
|
/**
|
|
63
117
|
* Creates a SvelteKit `load` function that fetches a resource list
|
|
@@ -73,7 +127,7 @@ export function createListLoader(dp, resource) {
|
|
|
73
127
|
sorters,
|
|
74
128
|
filters: listRequestFilters(resource, url),
|
|
75
129
|
});
|
|
76
|
-
return {
|
|
130
|
+
return definedOptions({
|
|
77
131
|
records: listResponse.data,
|
|
78
132
|
total: listResponse.total,
|
|
79
133
|
page,
|
|
@@ -88,7 +142,7 @@ export function createListLoader(dp, resource) {
|
|
|
88
142
|
currentSearch: search,
|
|
89
143
|
currentFilters: listRequestFilterValues(resource, url),
|
|
90
144
|
resource,
|
|
91
|
-
};
|
|
145
|
+
});
|
|
92
146
|
};
|
|
93
147
|
}
|
|
94
148
|
// ─── Detail Loader ────────────────────────────────────────────
|
|
@@ -260,7 +314,7 @@ export function createAuthActions(authProvider) {
|
|
|
260
314
|
}
|
|
261
315
|
function validatePasswordConfirmation(authParams) {
|
|
262
316
|
const { confirmPassword, ...providerParams } = authParams;
|
|
263
|
-
const password = authParams
|
|
317
|
+
const password = authParams['password'];
|
|
264
318
|
if (typeof password !== 'string'
|
|
265
319
|
|| password.length === 0
|
|
266
320
|
|| typeof confirmPassword !== 'string'
|
|
@@ -363,13 +417,13 @@ function pathWithinPrefix(pathname, prefix) {
|
|
|
363
417
|
}
|
|
364
418
|
function redirectOptions(options) {
|
|
365
419
|
const configured = typeof options === 'string' ? { litePrefix: options } : options;
|
|
366
|
-
return {
|
|
420
|
+
return definedOptions({
|
|
367
421
|
litePrefix: normalizeRoutePrefix(configured.litePrefix ?? '/lite'),
|
|
368
422
|
spaPrefix: normalizeRoutePrefix(configured.spaPrefix ?? '/'),
|
|
369
423
|
exclude: (configured.exclude ?? []).map(normalizeRoutePrefix),
|
|
370
424
|
mapPath: configured.mapPath,
|
|
371
425
|
status: configured.status ?? 302,
|
|
372
|
-
};
|
|
426
|
+
});
|
|
373
427
|
}
|
|
374
428
|
/**
|
|
375
429
|
* Computes a legacy redirect without importing or modifying the modern SPA.
|
package/package.json
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@svadmin/lite",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "SSR-first lightweight admin UI for @svadmin with optional progressive enhancement",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": [
|
|
7
7
|
"./dist/lite.css",
|
|
8
|
-
"./dist/enhance.js"
|
|
9
|
-
"./dist/polyfill.js"
|
|
8
|
+
"./dist/enhance.js"
|
|
10
9
|
],
|
|
11
10
|
"files": [
|
|
12
11
|
"dist",
|
|
@@ -35,10 +34,6 @@
|
|
|
35
34
|
"import": "./dist/enhance.js",
|
|
36
35
|
"default": "./dist/enhance.js"
|
|
37
36
|
},
|
|
38
|
-
"./polyfill.js": {
|
|
39
|
-
"import": "./dist/polyfill.js",
|
|
40
|
-
"default": "./dist/polyfill.js"
|
|
41
|
-
},
|
|
42
37
|
"./lite.css": {
|
|
43
38
|
"svelte": "./dist/lite.css",
|
|
44
39
|
"style": "./dist/lite.css",
|
|
@@ -54,17 +49,15 @@
|
|
|
54
49
|
},
|
|
55
50
|
"peerDependencies": {
|
|
56
51
|
"svelte": "^5.56.10",
|
|
57
|
-
"@svadmin/core": ">=0.34.2 <0.
|
|
52
|
+
"@svadmin/core": ">=0.34.2 <0.54.0",
|
|
58
53
|
"@sveltejs/kit": "^2.70.3"
|
|
59
54
|
},
|
|
60
55
|
"dependencies": {
|
|
61
56
|
"@lucide/svelte": "^1.35.0",
|
|
62
|
-
"@sinclair/typebox": "^0.34.52"
|
|
63
|
-
"core-js": "^3.50.0",
|
|
64
|
-
"whatwg-fetch": "^3.6.20"
|
|
57
|
+
"@sinclair/typebox": "^0.34.52"
|
|
65
58
|
},
|
|
66
59
|
"devDependencies": {
|
|
67
|
-
"@types/bun": "^1.4.
|
|
60
|
+
"@types/bun": "^1.4.2",
|
|
68
61
|
"@happy-dom/global-registrator": "^20.11.12",
|
|
69
62
|
"@sveltejs/vite-plugin-svelte": "^7.3.0",
|
|
70
63
|
"@testing-library/dom": "^10.4.1",
|
|
@@ -73,7 +66,7 @@
|
|
|
73
66
|
"vitest": "^4.1.11"
|
|
74
67
|
},
|
|
75
68
|
"scripts": {
|
|
76
|
-
"build": "node ../../node_modules/@sveltejs/package/svelte-package.js -i src -o dist &&
|
|
69
|
+
"build": "node ../../node_modules/@sveltejs/package/svelte-package.js -i src -o dist && bun ../../scripts/copy-package-assets.ts static/enhance.js dist/enhance.js",
|
|
77
70
|
"test": "bun run test:components && bun run test:server && bun run test:security",
|
|
78
71
|
"test:components": "vitest run --config ./vitest.config.ts",
|
|
79
72
|
"test:server": "bun test ./src/schema-generator.test.ts ./src/server-adapter.test.ts ./src/fragment-id.test.ts ./src/compatibility.test.ts ./src/ie11-ssr-contract.test.ts",
|
|
@@ -88,7 +81,7 @@
|
|
|
88
81
|
"author": "zuohuadong",
|
|
89
82
|
"repository": {
|
|
90
83
|
"type": "git",
|
|
91
|
-
"url": "https://github.com/vibeunion/svadmin.git",
|
|
84
|
+
"url": "git+https://github.com/vibeunion/svadmin.git",
|
|
92
85
|
"directory": "packages/lite"
|
|
93
86
|
}
|
|
94
87
|
}
|
package/dist/polyfill-entry.d.ts
DELETED
package/dist/polyfill-entry.js
DELETED