adminforth 1.0.32 → 1.0.34
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/dataConnectors/sqlite.ts +1 -0
- package/dist/dataConnectors/sqlite.js +1 -0
- package/dist/index.js +87 -74
- package/dist/modules/utils.js +11 -0
- package/dist/spa/spa/src/App.vue +0 -3
- package/dist/spa/spa/src/components/CustomDatePicker.vue +3 -3
- package/dist/spa/spa/src/components/CustomDateRangePicker.vue +3 -3
- package/dist/spa/spa/src/components/CustomRangePicker.vue +32 -19
- package/dist/spa/spa/src/components/Dropdown.vue +6 -1
- package/dist/spa/spa/src/components/ResourceForm.vue +125 -102
- package/dist/spa/spa/src/components/ValueRenderer.vue +11 -1
- package/dist/spa/spa/src/stores/core.ts +21 -19
- package/dist/spa/spa/src/views/CreateView.vue +16 -6
- package/dist/spa/spa/src/views/EditView.vue +15 -5
- package/dist/spa/spa/src/views/ListView.vue +31 -17
- package/dist/spa/spa/src/views/ResourceParent.vue +1 -1
- package/dist/spa/spa/src/views/ShowView.vue +21 -6
- package/dist/types/AdminForthConfig.js +1 -0
- package/index.ts +73 -149
- package/modules/utils.ts +16 -0
- package/package.json +1 -1
- package/spa/src/App.vue +0 -3
- package/spa/src/components/CustomDatePicker.vue +3 -3
- package/spa/src/components/CustomDateRangePicker.vue +3 -3
- package/spa/src/components/CustomRangePicker.vue +32 -19
- package/spa/src/components/Dropdown.vue +6 -1
- package/spa/src/components/ResourceForm.vue +125 -102
- package/spa/src/components/ValueRenderer.vue +11 -1
- package/spa/src/stores/core.ts +21 -19
- package/spa/src/views/CreateView.vue +16 -6
- package/spa/src/views/EditView.vue +15 -5
- package/spa/src/views/ListView.vue +31 -17
- package/spa/src/views/ResourceParent.vue +1 -1
- package/spa/src/views/ShowView.vue +21 -6
- package/types/AdminForthConfig.ts +159 -0
package/index.ts
CHANGED
|
@@ -8,116 +8,13 @@ import { guessLabelFromName } from './modules/utils.js';
|
|
|
8
8
|
import ExpressServer from './servers/express.js';
|
|
9
9
|
import {v1 as uuid} from 'uuid';
|
|
10
10
|
import fs from 'fs';
|
|
11
|
-
|
|
12
|
-
let package_json;
|
|
13
|
-
if (fs.existsSync('../package.json')) {
|
|
14
|
-
// in prod we are in dist folder
|
|
15
|
-
package_json = JSON.parse(fs.readFileSync('../package.json', 'utf8'));
|
|
16
|
-
} else {
|
|
17
|
-
package_json = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
|
|
18
|
-
}
|
|
19
|
-
|
|
11
|
+
import { ADMINFORTH_VERSION } from './modules/utils.js';
|
|
20
12
|
import { AdminForthFilterOperators, AdminForthTypes, AdminForthTypesValues } from './types.js';
|
|
13
|
+
import { AdminForthConfig } from './types/AdminForthConfig.js';
|
|
21
14
|
|
|
22
15
|
const AVAILABLE_SHOW_IN = ['list', 'edit', 'create', 'filter', 'show'];
|
|
23
16
|
const DEFAULT_ALLOWED_ACTIONS = {create: true, edit: true, show: true, delete: true};
|
|
24
17
|
|
|
25
|
-
type AdminForthConfigMenuItem = {
|
|
26
|
-
label: string,
|
|
27
|
-
icon?: string,
|
|
28
|
-
path?: string,
|
|
29
|
-
component?: string,
|
|
30
|
-
resourceId?: string,
|
|
31
|
-
homepage?: boolean,
|
|
32
|
-
children?: Array<AdminForthConfigMenuItem>,
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
type AdminForthResourceColumn = {
|
|
37
|
-
name: string,
|
|
38
|
-
label?: string,
|
|
39
|
-
type?: AdminForthTypesValues,
|
|
40
|
-
primaryKey?: boolean,
|
|
41
|
-
required?: boolean | { create: boolean, edit: boolean },
|
|
42
|
-
editingNote?: string | { create: string, edit: string },
|
|
43
|
-
showIn?: Array<string>,
|
|
44
|
-
fillOnCreate?: Function,
|
|
45
|
-
isUnique?: boolean,
|
|
46
|
-
virtual?: boolean,
|
|
47
|
-
allowMinMaxQuery?: boolean,
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
type AdminForthResource = {
|
|
51
|
-
resourceId: string,
|
|
52
|
-
label?: string,
|
|
53
|
-
table: string,
|
|
54
|
-
dataSource: string,
|
|
55
|
-
columns: Array<AdminForthResourceColumn>,
|
|
56
|
-
itemLabel?: Function,
|
|
57
|
-
hooks?: {
|
|
58
|
-
show?: Function,
|
|
59
|
-
create?: {
|
|
60
|
-
beforeSave?: Function,
|
|
61
|
-
afterSave?: Function,
|
|
62
|
-
},
|
|
63
|
-
edit?: {
|
|
64
|
-
beforeSave?: Function,
|
|
65
|
-
afterSave?: Function,
|
|
66
|
-
},
|
|
67
|
-
delete?: {
|
|
68
|
-
beforeSave?: Function,
|
|
69
|
-
afterSave?: Function,
|
|
70
|
-
},
|
|
71
|
-
},
|
|
72
|
-
options?: {
|
|
73
|
-
bulkActions?: Array<{
|
|
74
|
-
label: string,
|
|
75
|
-
state: string,
|
|
76
|
-
icon: string,
|
|
77
|
-
action: Function,
|
|
78
|
-
}>,
|
|
79
|
-
allowedActions?: AllowedActions,
|
|
80
|
-
|
|
81
|
-
},
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
type AdminForthDataSource = {
|
|
85
|
-
id: string,
|
|
86
|
-
url: string,
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
type AdminForthConfig = {
|
|
90
|
-
rootUser?: {
|
|
91
|
-
username: string,
|
|
92
|
-
password: string,
|
|
93
|
-
},
|
|
94
|
-
auth?: {
|
|
95
|
-
resourceId: string,
|
|
96
|
-
usernameField: string,
|
|
97
|
-
passwordHashField: string,
|
|
98
|
-
loginBackgroundImage?: string,
|
|
99
|
-
userFullName?: string,
|
|
100
|
-
},
|
|
101
|
-
resources: Array<any>,
|
|
102
|
-
menu: Array<AdminForthConfigMenuItem>,
|
|
103
|
-
databaseConnectors?: any,
|
|
104
|
-
dataSources: Array<any>,
|
|
105
|
-
customization?: {
|
|
106
|
-
customComponentsDir?: string,
|
|
107
|
-
vueUsesFile?: string,
|
|
108
|
-
},
|
|
109
|
-
baseUrl?: string,
|
|
110
|
-
brandName?: string,
|
|
111
|
-
datesFormat?: string,
|
|
112
|
-
deleteConfirmation?: boolean,
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
type AllowedActions = {
|
|
116
|
-
create: boolean,
|
|
117
|
-
edit: boolean,
|
|
118
|
-
show: boolean,
|
|
119
|
-
delete: boolean,
|
|
120
|
-
}
|
|
121
18
|
|
|
122
19
|
class AdminForth {
|
|
123
20
|
static Types = AdminForthTypes;
|
|
@@ -131,8 +28,6 @@ class AdminForth {
|
|
|
131
28
|
|
|
132
29
|
#defaultConfig = {
|
|
133
30
|
deleteConfirmation: true,
|
|
134
|
-
|
|
135
|
-
|
|
136
31
|
}
|
|
137
32
|
|
|
138
33
|
config: AdminForthConfig;
|
|
@@ -157,6 +52,7 @@ class AdminForth {
|
|
|
157
52
|
this.codeInjector = new CodeInjector(this);
|
|
158
53
|
this.connectors = {};
|
|
159
54
|
this.statuses = {}
|
|
55
|
+
console.log(`🚀 AdminForth v${ADMINFORTH_VERSION} starting up`)
|
|
160
56
|
}
|
|
161
57
|
|
|
162
58
|
validateConfig() {
|
|
@@ -403,7 +299,7 @@ class AdminForth {
|
|
|
403
299
|
if (!this.config.databaseConnectors[dbType]) {
|
|
404
300
|
throw new Error(`Database type ${dbType} is not supported, consider using databaseConnectors in AdminForth config`);
|
|
405
301
|
}
|
|
406
|
-
this.connectors[ds.id] = new this.config.databaseConnectors[dbType]({url: ds.url
|
|
302
|
+
this.connectors[ds.id] = new this.config.databaseConnectors[dbType]({url: ds.url});
|
|
407
303
|
});
|
|
408
304
|
|
|
409
305
|
await Promise.all(this.config.resources.map(async (res) => {
|
|
@@ -441,10 +337,6 @@ class AdminForth {
|
|
|
441
337
|
// console.log('⚙️⚙️⚙️ Database discovery done', JSON.stringify(this.config.resources, null, 2));
|
|
442
338
|
}
|
|
443
339
|
|
|
444
|
-
async init() {
|
|
445
|
-
console.log('AdminForth init');
|
|
446
|
-
}
|
|
447
|
-
|
|
448
340
|
async bundleNow({ hotReload=false, verbose=false }) {
|
|
449
341
|
this.codeInjector.bundleNow({ hotReload, verbose });
|
|
450
342
|
}
|
|
@@ -553,12 +445,12 @@ class AdminForth {
|
|
|
553
445
|
return { error: 'Unauthorized' };
|
|
554
446
|
}
|
|
555
447
|
username = user.data[0][this.config.auth.usernameField];
|
|
556
|
-
userFullName = user.data[0][this.config.auth.
|
|
448
|
+
userFullName = user.data[0][this.config.auth.userFullNameField];
|
|
557
449
|
}
|
|
558
450
|
|
|
559
451
|
const userData = {
|
|
560
452
|
[this.config.auth.usernameField]: username,
|
|
561
|
-
[this.config.auth.
|
|
453
|
+
[this.config.auth.userFullNameField]: userFullName
|
|
562
454
|
};
|
|
563
455
|
return {
|
|
564
456
|
user: userData,
|
|
@@ -575,7 +467,7 @@ class AdminForth {
|
|
|
575
467
|
usernameField: this.config.auth.usernameField,
|
|
576
468
|
},
|
|
577
469
|
adminUser,
|
|
578
|
-
version:
|
|
470
|
+
version: ADMINFORTH_VERSION,
|
|
579
471
|
};
|
|
580
472
|
},
|
|
581
473
|
});
|
|
@@ -601,8 +493,11 @@ class AdminForth {
|
|
|
601
493
|
server.endpoint({
|
|
602
494
|
method: 'POST',
|
|
603
495
|
path: '/get_resource_data',
|
|
604
|
-
handler: async ({ body }) => {
|
|
605
|
-
const { resourceId,
|
|
496
|
+
handler: async ({ body, adminUser }) => {
|
|
497
|
+
const { resourceId, source } = body;
|
|
498
|
+
if (['show', 'list'].includes(source) === false) {
|
|
499
|
+
return { error: 'Invalid source, should be list or show' };
|
|
500
|
+
}
|
|
606
501
|
if (!this.statuses.dbDiscover) {
|
|
607
502
|
return { error: 'Database discovery not started' };
|
|
608
503
|
}
|
|
@@ -613,6 +508,19 @@ class AdminForth {
|
|
|
613
508
|
if (!resource) {
|
|
614
509
|
return { error: `Resource ${resourceId} not found` };
|
|
615
510
|
}
|
|
511
|
+
if (resource.hooks?.[source]?.beforeDatasourceRequest) {
|
|
512
|
+
const resp = await resource.hooks?.[source]?.beforeDatasourceRequest({ resource, query: body, adminUser });
|
|
513
|
+
if (!resp || (!resp.ok && !resp.error)) {
|
|
514
|
+
throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
if (resp.error) {
|
|
518
|
+
return { error: resp.error };
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
const { limit, offset, filters, sort } = body;
|
|
522
|
+
|
|
523
|
+
|
|
616
524
|
const data = await this.connectors[resource.dataSource].getData({
|
|
617
525
|
resource,
|
|
618
526
|
limit,
|
|
@@ -620,6 +528,50 @@ class AdminForth {
|
|
|
620
528
|
filters,
|
|
621
529
|
sort,
|
|
622
530
|
});
|
|
531
|
+
// for foreign keys, add references
|
|
532
|
+
await Promise.all(
|
|
533
|
+
resource.columns.filter((col) => col.foreignResource).map(async (col) => {
|
|
534
|
+
const targetResource = this.config.resources.find((res) => res.resourceId == col.foreignResource.resourceId);
|
|
535
|
+
const targetConnector = this.connectors[targetResource.dataSource];
|
|
536
|
+
const targetResourcePkField = targetResource.columns.find((col) => col.primaryKey).name;
|
|
537
|
+
const targetData = await targetConnector.getData({
|
|
538
|
+
resource: targetResource,
|
|
539
|
+
limit: limit,
|
|
540
|
+
offset: 0,
|
|
541
|
+
filters: [
|
|
542
|
+
{
|
|
543
|
+
field: targetResourcePkField,
|
|
544
|
+
operator: AdminForthFilterOperators.IN,
|
|
545
|
+
value: data.data.map((item) => item[col.name]),
|
|
546
|
+
}
|
|
547
|
+
],
|
|
548
|
+
sort: [],
|
|
549
|
+
});
|
|
550
|
+
const targetDataMap = targetData.data.reduce((acc, item) => {
|
|
551
|
+
acc[item[targetResourcePkField]] = {
|
|
552
|
+
label: targetResource.itemLabel ? targetResource.itemLabel(item) : item[targetResourcePkField],
|
|
553
|
+
pk: item[targetResourcePkField],
|
|
554
|
+
}
|
|
555
|
+
return acc;
|
|
556
|
+
}, {});
|
|
557
|
+
data.data.forEach((item) => {
|
|
558
|
+
item[col.name] = targetDataMap[item[col.name]];
|
|
559
|
+
});
|
|
560
|
+
})
|
|
561
|
+
);
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
if (resource.hooks?.[source]?.afterDatasourceRequest) {
|
|
565
|
+
const resp = await resource.hooks?.[source]?.afterDatasourceRequest({ resource, response: data.data, adminUser });
|
|
566
|
+
if (!resp || (!resp.ok && !resp.error)) {
|
|
567
|
+
throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
if (resp.error) {
|
|
571
|
+
return { error: resp.error };
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
623
575
|
return {...data, options: resource?.options };
|
|
624
576
|
},
|
|
625
577
|
});
|
|
@@ -674,8 +626,8 @@ class AdminForth {
|
|
|
674
626
|
const response = {
|
|
675
627
|
items
|
|
676
628
|
};
|
|
677
|
-
if (columnConfig.foreignResource.hooks?.
|
|
678
|
-
const resp = await column.foreignResource.hooks?.
|
|
629
|
+
if (columnConfig.foreignResource.hooks?.afterDatasourceResponse) {
|
|
630
|
+
const resp = await column.foreignResource.hooks?.afterDatasourceResponse({ response, adminUser });
|
|
679
631
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
680
632
|
throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
|
|
681
633
|
}
|
|
@@ -684,6 +636,7 @@ class AdminForth {
|
|
|
684
636
|
return { error: resp.error };
|
|
685
637
|
}
|
|
686
638
|
}
|
|
639
|
+
|
|
687
640
|
return response;
|
|
688
641
|
},
|
|
689
642
|
});
|
|
@@ -717,36 +670,7 @@ class AdminForth {
|
|
|
717
670
|
return item;
|
|
718
671
|
},
|
|
719
672
|
});
|
|
720
|
-
server.endpoint({
|
|
721
|
-
method: 'POST',
|
|
722
|
-
path: '/get_record',
|
|
723
|
-
handler: async ({ body, adminUser }) => {
|
|
724
|
-
const { resourceId, primaryKey } = body;
|
|
725
|
-
const resource = this.config.resources.find((res) => res.resourceId == resourceId);
|
|
726
|
-
const primaryKeyColumn = resource.columns.find((col) => col.primaryKey);
|
|
727
|
-
const connector = this.connectors[resource.dataSource];
|
|
728
|
-
const record = await connector.getRecordByPrimaryKey(resource, primaryKey);
|
|
729
|
-
if (!record) {
|
|
730
|
-
return { error: `Record with ${primaryKeyColumn.name} ${primaryKey} not found` };
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
// execute hook if needed
|
|
734
|
-
if (resource.hooks?.show) {
|
|
735
|
-
const resp = await resource.hooks?.show({ resource, record, adminUser });
|
|
736
|
-
if (!resp || (!resp.ok && !resp.error)) {
|
|
737
|
-
throw new Error(`Hook must return object with {ok: true} or { error: 'Error' } `);
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
if (resp.error) {
|
|
741
|
-
return { error: resp.error };
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
673
|
|
|
745
|
-
const labler = resource.itemLabel || ((record) => `${resource.label} ${record[primaryKeyColumn.name]}`);
|
|
746
|
-
record._label = labler(record);
|
|
747
|
-
return record;
|
|
748
|
-
}
|
|
749
|
-
});
|
|
750
674
|
server.endpoint({
|
|
751
675
|
noAuth: true, // TODO
|
|
752
676
|
method: 'POST',
|
|
@@ -779,7 +703,7 @@ class AdminForth {
|
|
|
779
703
|
});
|
|
780
704
|
}
|
|
781
705
|
}
|
|
782
|
-
if (column.required?.create && body['record'][column.name] === undefined) {
|
|
706
|
+
if ((column.required as {create?: boolean, edit?: boolean}) ?.create && body['record'][column.name] === undefined) {
|
|
783
707
|
return { error: `Column '${column.name}' is required` };
|
|
784
708
|
}
|
|
785
709
|
|
package/modules/utils.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
import fs from 'fs';
|
|
1
4
|
|
|
2
5
|
|
|
3
6
|
export function guessLabelFromName(name) {
|
|
@@ -10,3 +13,16 @@ export function guessLabelFromName(name) {
|
|
|
10
13
|
return name.split(/(?=[A-Z])/).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(' ');
|
|
11
14
|
}
|
|
12
15
|
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
let package_json;
|
|
19
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
20
|
+
const __dirname = path.join(path.dirname(__filename), '..');
|
|
21
|
+
console.log('📦 __filename', __dirname);
|
|
22
|
+
console.log('📦 __dirname', __dirname);
|
|
23
|
+
|
|
24
|
+
export const ADMIN_FORTH_ABSOLUTE_PATH = __dirname;
|
|
25
|
+
|
|
26
|
+
package_json = JSON.parse(fs.readFileSync(path.join(ADMIN_FORTH_ABSOLUTE_PATH, 'package.json'), 'utf8'));
|
|
27
|
+
|
|
28
|
+
export const ADMINFORTH_VERSION = package_json.version;
|
package/package.json
CHANGED
package/spa/src/App.vue
CHANGED
|
@@ -42,9 +42,6 @@
|
|
|
42
42
|
</p>
|
|
43
43
|
</div>
|
|
44
44
|
<ul class="py-1" role="none">
|
|
45
|
-
<li>
|
|
46
|
-
<a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600 dark:hover:text-white" role="menuitem">Dashboard</a>
|
|
47
|
-
</li>
|
|
48
45
|
<li >
|
|
49
46
|
<span @click="toggleTheme" class=" cursor-pointer flex items-center gap-1 block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600 dark:hover:text-white" role="menuitem">
|
|
50
47
|
{{ theme === 'dark' ? 'Light' : 'Dark' }}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<label for="start-time" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">{{ label }}</label>
|
|
6
6
|
|
|
7
7
|
<div class="relative">
|
|
8
|
-
<div class="absolute inset-y-0 end-0 top-0 flex items-center pe-3.5">
|
|
8
|
+
<div class="absolute inset-y-0 end-0 top-0 flex items-center pe-3.5 pointer-events-none">
|
|
9
9
|
<IconCalendar class="w-4 h-4 text-gray-500 dark:text-gray-400"/>
|
|
10
10
|
</div>
|
|
11
11
|
|
|
@@ -97,7 +97,7 @@ const start = computed(() => {
|
|
|
97
97
|
})
|
|
98
98
|
|
|
99
99
|
function updateFromProps() {
|
|
100
|
-
if (props.valueStart
|
|
100
|
+
if (!props.valueStart) {
|
|
101
101
|
datepickerStartEl.value.value = '';
|
|
102
102
|
startTime.value = '';
|
|
103
103
|
}
|
|
@@ -157,5 +157,5 @@ onMounted(() => {
|
|
|
157
157
|
|
|
158
158
|
onBeforeUnmount(() => {
|
|
159
159
|
removeChangeDateListener();
|
|
160
|
-
})
|
|
160
|
+
});
|
|
161
161
|
</script>
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
<div class="mx-auto grid grid-cols-2 gap-4 mb-2" :class="{hidden: !showTimeInputs}">
|
|
27
27
|
<div>
|
|
28
28
|
<div class="relative">
|
|
29
|
-
<div class="absolute inset-y-0 end-0 top-0 flex items-center pe-3.5">
|
|
29
|
+
<div class="absolute inset-y-0 end-0 top-0 flex items-center pe-3.5 pointer-events-none">
|
|
30
30
|
<IconTime class="w-4 h-4 text-gray-500 dark:text-gray-400 bg-white dark:bg-gray-700"/>
|
|
31
31
|
</div>
|
|
32
32
|
|
|
@@ -132,11 +132,11 @@ const end = computed(() => {
|
|
|
132
132
|
})
|
|
133
133
|
|
|
134
134
|
function updateFromProps() {
|
|
135
|
-
if (props.valueStart
|
|
135
|
+
if (!props.valueStart) {
|
|
136
136
|
datepickerStartEl.value.value = '';
|
|
137
137
|
startTime.value = '';
|
|
138
138
|
}
|
|
139
|
-
if (props.valueEnd
|
|
139
|
+
if (!props.valueEnd) {
|
|
140
140
|
datepickerEndEl.value.value = '';
|
|
141
141
|
endTime.value = '';
|
|
142
142
|
}
|
|
@@ -71,33 +71,52 @@ const sliderValue = ref([start.value, end.value]);
|
|
|
71
71
|
|
|
72
72
|
const updateFromSlider =
|
|
73
73
|
debounce((value: [number, number]) => {
|
|
74
|
+
console.log('start end', value)
|
|
74
75
|
start.value = value[0];
|
|
75
76
|
end.value = value[1];
|
|
76
77
|
}, 500);
|
|
77
78
|
|
|
78
|
-
function updateFromProps() {
|
|
79
|
-
if (props.valueStart || props.valueEnd) {
|
|
80
|
-
setFromProps(props.valueStart, props.valueEnd)
|
|
81
|
-
} else {
|
|
82
|
-
clear();
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
79
|
onMounted(() => {
|
|
87
|
-
|
|
80
|
+
updateStartFromProps();
|
|
81
|
+
updateEndFromProps();
|
|
88
82
|
|
|
89
|
-
watch(() =>
|
|
90
|
-
|
|
83
|
+
watch(() => props.valueStart, (value) => {
|
|
84
|
+
updateStartFromProps();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
watch(() => props.valueEnd, (value) => {
|
|
88
|
+
updateEndFromProps();
|
|
91
89
|
});
|
|
92
90
|
})
|
|
93
91
|
|
|
92
|
+
function updateStartFromProps() {
|
|
93
|
+
if (props.valueStart || props.valueStart === 0) {
|
|
94
|
+
start.value = props.valueStart ? props.valueStart : minFormatted.value;
|
|
95
|
+
sliderValue.value = [start.value, end.value]
|
|
96
|
+
} else {
|
|
97
|
+
console.log(props.valueStart)
|
|
98
|
+
start.value = minFormatted.value;
|
|
99
|
+
sliderValue.value = [minFormatted.value, end.value];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function updateEndFromProps() {
|
|
104
|
+
if (props.valueEnd || props.valueStart === 0) {
|
|
105
|
+
end.value = props.valueEnd ? props.valueEnd : minFormatted.value;
|
|
106
|
+
sliderValue.value = [start.value, end.value]
|
|
107
|
+
} else {
|
|
108
|
+
end.value = maxFormatted.value;
|
|
109
|
+
sliderValue.value = [start.value, maxFormatted.value];
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
94
113
|
watch(start, () => {
|
|
95
|
-
|
|
114
|
+
console.log('⚡ emit', start.value)
|
|
96
115
|
emit('update:valueStart', start.value)
|
|
97
116
|
})
|
|
98
117
|
|
|
99
118
|
watch(end, () => {
|
|
100
|
-
|
|
119
|
+
console.log('⚡ emit', end.value)
|
|
101
120
|
emit('update:valueEnd', end.value);
|
|
102
121
|
})
|
|
103
122
|
|
|
@@ -106,12 +125,6 @@ const clear = () => {
|
|
|
106
125
|
end.value = maxFormatted.value;
|
|
107
126
|
sliderValue.value = [start.value, end.value]
|
|
108
127
|
}
|
|
109
|
-
|
|
110
|
-
function setFromProps(startValue: number, endValue: number) {
|
|
111
|
-
start.value = startValue ? startValue : minFormatted.value
|
|
112
|
-
end.value = endValue ? endValue : maxFormatted.value
|
|
113
|
-
sliderValue.value = [start.value, end.value]
|
|
114
|
-
}
|
|
115
128
|
</script>
|
|
116
129
|
|
|
117
130
|
<style lang="scss" scoped>
|
|
@@ -78,7 +78,12 @@ const selectedItems = ref([]);
|
|
|
78
78
|
function updateFromProps() {
|
|
79
79
|
if (props.modelValue !== undefined) {
|
|
80
80
|
if (props.single) {
|
|
81
|
-
|
|
81
|
+
const el = props.options.find(item => item.value === props.modelValue);
|
|
82
|
+
if (el) {
|
|
83
|
+
selectedItems.value = [el];
|
|
84
|
+
} else {
|
|
85
|
+
selectedItems.value = [];
|
|
86
|
+
}
|
|
82
87
|
} else {
|
|
83
88
|
selectedItems.value = props.options.filter(item => props.modelValue.includes(item.value));
|
|
84
89
|
}
|