adminforth 1.0.41 → 1.0.43
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/mongo.ts +0 -21
- package/dataConnectors/postgres.ts +0 -8
- package/dataConnectors/sqlite.ts +1 -10
- package/dist/dataConnectors/mongo.js +0 -17
- package/dist/dataConnectors/postgres.js +0 -8
- package/dist/dataConnectors/sqlite.js +1 -8
- package/dist/index.js +22 -1
- package/dist/spa/spa/src/components/CustomRangePicker.vue +19 -27
- package/index.ts +26 -1
- package/package.json +1 -1
- package/spa/src/components/CustomRangePicker.vue +19 -27
package/dataConnectors/mongo.ts
CHANGED
|
@@ -123,27 +123,6 @@ class MongoConnector {
|
|
|
123
123
|
async getData({ resource, limit, offset, sort, filters }) {
|
|
124
124
|
// const columns = resource.dataSourceColumns.filter(c=> !c.virtual).map((col) => col.name).join(', ');
|
|
125
125
|
const tableName = resource.table;
|
|
126
|
-
|
|
127
|
-
for (const filter of filters) {
|
|
128
|
-
if (!this.OperatorsMap[filter.operator]) {
|
|
129
|
-
throw new Error(`Operator ${filter.operator} is not allowed`);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (!resource.dataSourceColumns.some((col) => col.name === filter.field)) {
|
|
133
|
-
throw new Error(`Field ${filter.field} is not in resource ${resource.resourceId}. Available fields: ${resource.dataSourceColumns.map((col) => col.name).join(', ')}`);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (filter.operator === AdminForthFilterOperators.IN || filter.operator === AdminForthFilterOperators.NIN) {
|
|
137
|
-
if (!Array.isArray(filter.value)) {
|
|
138
|
-
throw new Error(`Value for operator ${filter.operator} should be an array`);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
if (filter.operator === AdminForthFilterOperators.IN && filter.value.length === 0) {
|
|
143
|
-
// nonsense
|
|
144
|
-
return { data: [], total: 0 };
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
126
|
|
|
148
127
|
const collection = this.db.db().collection(tableName);
|
|
149
128
|
const query = {};
|
|
@@ -180,14 +180,6 @@ class PostgresConnector {
|
|
|
180
180
|
const columns = resource.dataSourceColumns.filter(c=> !c.virtual).map((col) => `"${col.name}"`).join(', ');
|
|
181
181
|
const tableName = resource.table;
|
|
182
182
|
|
|
183
|
-
for (const filter of filters) {
|
|
184
|
-
if (!this.OperatorsMap[filter.operator]) {
|
|
185
|
-
throw new Error(`Operator ${filter.operator} is not allowed`);
|
|
186
|
-
}
|
|
187
|
-
if (!resource.dataSourceColumns.some((col) => col.name == filter.field)) {
|
|
188
|
-
throw new Error(`Field ${filter.field} is not in resource ${resource.resourceId}. Available fields: ${resource.dataSourceColumns.map((col) => col.name).join(', ')}`);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
183
|
let totalCounter = 1;
|
|
192
184
|
const where = filters.length ? `WHERE ${filters.map((f, i) => {
|
|
193
185
|
let placeholder = '$'+(totalCounter);
|
package/dataConnectors/sqlite.ts
CHANGED
|
@@ -138,18 +138,9 @@ class SQLiteConnector {
|
|
|
138
138
|
|
|
139
139
|
|
|
140
140
|
getData({ resource, limit, offset, sort, filters }) {
|
|
141
|
+
console.log('SQLITE getData', { resource, limit, offset, sort, filters });
|
|
141
142
|
const columns = resource.dataSourceColumns.map((col) => col.name).join(', ');
|
|
142
143
|
const tableName = resource.table;
|
|
143
|
-
|
|
144
|
-
for (const filter of filters) {
|
|
145
|
-
if (!this.OperatorsMap[filter.operator]) {
|
|
146
|
-
throw new Error(`Operator ${filter.operator} is not allowed`);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (!resource.dataSourceColumns.some((col) => col.name == filter.field)) {
|
|
150
|
-
throw new Error(`Field "${filter.field}" is not in resource ${resource.resourceId}, available fields: ${resource.dataSourceColumns.map((col) => '"'+col.name+'"').join(', ')}`);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
144
|
|
|
154
145
|
const where = filters.length ? `WHERE ${filters.map((f, i) => {
|
|
155
146
|
let placeholder = '?';
|
|
@@ -130,23 +130,6 @@ class MongoConnector {
|
|
|
130
130
|
return __awaiter(this, arguments, void 0, function* ({ resource, limit, offset, sort, filters }) {
|
|
131
131
|
// const columns = resource.dataSourceColumns.filter(c=> !c.virtual).map((col) => col.name).join(', ');
|
|
132
132
|
const tableName = resource.table;
|
|
133
|
-
for (const filter of filters) {
|
|
134
|
-
if (!this.OperatorsMap[filter.operator]) {
|
|
135
|
-
throw new Error(`Operator ${filter.operator} is not allowed`);
|
|
136
|
-
}
|
|
137
|
-
if (!resource.dataSourceColumns.some((col) => col.name === filter.field)) {
|
|
138
|
-
throw new Error(`Field ${filter.field} is not in resource ${resource.resourceId}. Available fields: ${resource.dataSourceColumns.map((col) => col.name).join(', ')}`);
|
|
139
|
-
}
|
|
140
|
-
if (filter.operator === AdminForthFilterOperators.IN || filter.operator === AdminForthFilterOperators.NIN) {
|
|
141
|
-
if (!Array.isArray(filter.value)) {
|
|
142
|
-
throw new Error(`Value for operator ${filter.operator} should be an array`);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
if (filter.operator === AdminForthFilterOperators.IN && filter.value.length === 0) {
|
|
146
|
-
// nonsense
|
|
147
|
-
return { data: [], total: 0 };
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
133
|
const collection = this.db.db().collection(tableName);
|
|
151
134
|
const query = {};
|
|
152
135
|
for (const filter of filters) {
|
|
@@ -182,14 +182,6 @@ class PostgresConnector {
|
|
|
182
182
|
return __awaiter(this, arguments, void 0, function* ({ resource, limit, offset, sort, filters }) {
|
|
183
183
|
const columns = resource.dataSourceColumns.filter(c => !c.virtual).map((col) => `"${col.name}"`).join(', ');
|
|
184
184
|
const tableName = resource.table;
|
|
185
|
-
for (const filter of filters) {
|
|
186
|
-
if (!this.OperatorsMap[filter.operator]) {
|
|
187
|
-
throw new Error(`Operator ${filter.operator} is not allowed`);
|
|
188
|
-
}
|
|
189
|
-
if (!resource.dataSourceColumns.some((col) => col.name == filter.field)) {
|
|
190
|
-
throw new Error(`Field ${filter.field} is not in resource ${resource.resourceId}. Available fields: ${resource.dataSourceColumns.map((col) => col.name).join(', ')}`);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
185
|
let totalCounter = 1;
|
|
194
186
|
const where = filters.length ? `WHERE ${filters.map((f, i) => {
|
|
195
187
|
let placeholder = '$' + (totalCounter);
|
|
@@ -148,16 +148,9 @@ class SQLiteConnector {
|
|
|
148
148
|
return value;
|
|
149
149
|
}
|
|
150
150
|
getData({ resource, limit, offset, sort, filters }) {
|
|
151
|
+
console.log('SQLITE getData', { resource, limit, offset, sort, filters });
|
|
151
152
|
const columns = resource.dataSourceColumns.map((col) => col.name).join(', ');
|
|
152
153
|
const tableName = resource.table;
|
|
153
|
-
for (const filter of filters) {
|
|
154
|
-
if (!this.OperatorsMap[filter.operator]) {
|
|
155
|
-
throw new Error(`Operator ${filter.operator} is not allowed`);
|
|
156
|
-
}
|
|
157
|
-
if (!resource.dataSourceColumns.some((col) => col.name == filter.field)) {
|
|
158
|
-
throw new Error(`Field "${filter.field}" is not in resource ${resource.resourceId}, available fields: ${resource.dataSourceColumns.map((col) => '"' + col.name + '"').join(', ')}`);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
154
|
const where = filters.length ? `WHERE ${filters.map((f, i) => {
|
|
162
155
|
let placeholder = '?';
|
|
163
156
|
let field = f.field;
|
package/dist/index.js
CHANGED
|
@@ -471,6 +471,23 @@ class AdminForth {
|
|
|
471
471
|
}
|
|
472
472
|
}
|
|
473
473
|
const { limit, offset, filters, sort } = body;
|
|
474
|
+
for (const filter of (filters || [])) {
|
|
475
|
+
if (AdminForthFilterOperators[filter.operator] === undefined) {
|
|
476
|
+
throw new Error(`Operator '${filter.operator}' is not allowed`);
|
|
477
|
+
}
|
|
478
|
+
if (!resource.columns.some((col) => col.name === filter.field)) {
|
|
479
|
+
throw new Error(`Field '${filter.field}' is not in resource '${resource.resourceId}'. Available fields: ${resource.columns.map((col) => col.name).join(', ')}`);
|
|
480
|
+
}
|
|
481
|
+
if (filter.operator === AdminForthFilterOperators.IN || filter.operator === AdminForthFilterOperators.NIN) {
|
|
482
|
+
if (!Array.isArray(filter.value)) {
|
|
483
|
+
throw new Error(`Value for operator '${filter.operator}'' should be an array`);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
if (filter.operator === AdminForthFilterOperators.IN && filter.value.length === 0) {
|
|
487
|
+
// nonsense
|
|
488
|
+
return { data: [], total: 0 };
|
|
489
|
+
}
|
|
490
|
+
}
|
|
474
491
|
const data = yield this.connectors[resource.dataSource].getData({
|
|
475
492
|
resource,
|
|
476
493
|
limit,
|
|
@@ -483,6 +500,10 @@ class AdminForth {
|
|
|
483
500
|
const targetResource = this.config.resources.find((res) => res.resourceId == col.foreignResource.resourceId);
|
|
484
501
|
const targetConnector = this.connectors[targetResource.dataSource];
|
|
485
502
|
const targetResourcePkField = targetResource.columns.find((col) => col.primaryKey).name;
|
|
503
|
+
const pksUnique = [...new Set(data.data.map((item) => item[col.name]))];
|
|
504
|
+
if (pksUnique.length === 0) {
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
486
507
|
const targetData = yield targetConnector.getData({
|
|
487
508
|
resource: targetResource,
|
|
488
509
|
limit: limit,
|
|
@@ -491,7 +512,7 @@ class AdminForth {
|
|
|
491
512
|
{
|
|
492
513
|
field: targetResourcePkField,
|
|
493
514
|
operator: AdminForthFilterOperators.IN,
|
|
494
|
-
value:
|
|
515
|
+
value: pksUnique,
|
|
495
516
|
}
|
|
496
517
|
],
|
|
497
518
|
sort: [],
|
|
@@ -42,10 +42,10 @@ import debounce from 'debounce'
|
|
|
42
42
|
|
|
43
43
|
const props = defineProps({
|
|
44
44
|
valueStart: {
|
|
45
|
-
default:
|
|
45
|
+
default: '',
|
|
46
46
|
},
|
|
47
47
|
valueEnd: {
|
|
48
|
-
default:
|
|
48
|
+
default: '',
|
|
49
49
|
},
|
|
50
50
|
min: {
|
|
51
51
|
default: 0,
|
|
@@ -61,19 +61,18 @@ const minFormatted = computed(() => Math.floor(props.min));
|
|
|
61
61
|
const maxFormatted = computed(() => Math.ceil(props.max));
|
|
62
62
|
|
|
63
63
|
const isChanged = computed(() => {
|
|
64
|
-
return start.value !== minFormatted.value || end.value !== maxFormatted.value;
|
|
64
|
+
return start.value && start.value !== minFormatted.value || end.value && end.value !== maxFormatted.value;
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
-
const start = ref(
|
|
68
|
-
const end = ref(
|
|
67
|
+
const start = ref(props.valueStart);
|
|
68
|
+
const end = ref(props.valueEnd);
|
|
69
69
|
|
|
70
|
-
const sliderValue = ref([
|
|
70
|
+
const sliderValue = ref([minFormatted.value, maxFormatted.value]);
|
|
71
71
|
|
|
72
72
|
const updateFromSlider =
|
|
73
73
|
debounce((value: [number, number]) => {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
end.value = value[1];
|
|
74
|
+
start.value = value[0] === minFormatted.value ? '': value[0];
|
|
75
|
+
end.value = value[1] === maxFormatted.value ? '': value[1];
|
|
77
76
|
}, 500);
|
|
78
77
|
|
|
79
78
|
onMounted(() => {
|
|
@@ -90,24 +89,13 @@ onMounted(() => {
|
|
|
90
89
|
})
|
|
91
90
|
|
|
92
91
|
function updateStartFromProps() {
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
}
|
|
92
|
+
start.value = props.valueStart;
|
|
93
|
+
setSliderValues(start.value, end.value)
|
|
101
94
|
}
|
|
102
95
|
|
|
103
96
|
function updateEndFromProps() {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
sliderValue.value = [start.value, end.value]
|
|
107
|
-
} else {
|
|
108
|
-
end.value = maxFormatted.value;
|
|
109
|
-
sliderValue.value = [start.value, maxFormatted.value];
|
|
110
|
-
}
|
|
97
|
+
end.value = props.valueEnd;
|
|
98
|
+
setSliderValues(start.value, end.value)
|
|
111
99
|
}
|
|
112
100
|
|
|
113
101
|
watch(start, () => {
|
|
@@ -121,9 +109,13 @@ watch(end, () => {
|
|
|
121
109
|
})
|
|
122
110
|
|
|
123
111
|
const clear = () => {
|
|
124
|
-
start.value =
|
|
125
|
-
end.value =
|
|
126
|
-
|
|
112
|
+
start.value = ''
|
|
113
|
+
end.value = ''
|
|
114
|
+
setSliderValues('', '')
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function setSliderValues(start, end) {
|
|
118
|
+
sliderValue.value = [start || minFormatted.value, end || maxFormatted.value];
|
|
127
119
|
}
|
|
128
120
|
</script>
|
|
129
121
|
|
package/index.ts
CHANGED
|
@@ -523,6 +523,7 @@ class AdminForth {
|
|
|
523
523
|
if (!resource) {
|
|
524
524
|
return { error: `Resource ${resourceId} not found` };
|
|
525
525
|
}
|
|
526
|
+
|
|
526
527
|
if (resource.hooks?.[source]?.beforeDatasourceRequest) {
|
|
527
528
|
const resp = await resource.hooks?.[source]?.beforeDatasourceRequest({ resource, query: body, adminUser });
|
|
528
529
|
if (!resp || (!resp.ok && !resp.error)) {
|
|
@@ -535,6 +536,26 @@ class AdminForth {
|
|
|
535
536
|
}
|
|
536
537
|
const { limit, offset, filters, sort } = body;
|
|
537
538
|
|
|
539
|
+
for (const filter of (filters || [])) {
|
|
540
|
+
if (AdminForthFilterOperators[filter.operator] === undefined) {
|
|
541
|
+
throw new Error(`Operator '${filter.operator}' is not allowed`);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
if (!resource.columns.some((col) => col.name === filter.field)) {
|
|
545
|
+
throw new Error(`Field '${filter.field}' is not in resource '${resource.resourceId}'. Available fields: ${resource.columns.map((col) => col.name).join(', ')}`);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
if (filter.operator === AdminForthFilterOperators.IN || filter.operator === AdminForthFilterOperators.NIN) {
|
|
549
|
+
if (!Array.isArray(filter.value)) {
|
|
550
|
+
throw new Error(`Value for operator '${filter.operator}'' should be an array`);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
if (filter.operator === AdminForthFilterOperators.IN && filter.value.length === 0) {
|
|
555
|
+
// nonsense
|
|
556
|
+
return { data: [], total: 0 };
|
|
557
|
+
}
|
|
558
|
+
}
|
|
538
559
|
|
|
539
560
|
const data = await this.connectors[resource.dataSource].getData({
|
|
540
561
|
resource,
|
|
@@ -549,6 +570,10 @@ class AdminForth {
|
|
|
549
570
|
const targetResource = this.config.resources.find((res) => res.resourceId == col.foreignResource.resourceId);
|
|
550
571
|
const targetConnector = this.connectors[targetResource.dataSource];
|
|
551
572
|
const targetResourcePkField = targetResource.columns.find((col) => col.primaryKey).name;
|
|
573
|
+
const pksUnique = [...new Set(data.data.map((item) => item[col.name]))];
|
|
574
|
+
if (pksUnique.length === 0) {
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
552
577
|
const targetData = await targetConnector.getData({
|
|
553
578
|
resource: targetResource,
|
|
554
579
|
limit: limit,
|
|
@@ -557,7 +582,7 @@ class AdminForth {
|
|
|
557
582
|
{
|
|
558
583
|
field: targetResourcePkField,
|
|
559
584
|
operator: AdminForthFilterOperators.IN,
|
|
560
|
-
value:
|
|
585
|
+
value: pksUnique,
|
|
561
586
|
}
|
|
562
587
|
],
|
|
563
588
|
sort: [],
|
package/package.json
CHANGED
|
@@ -42,10 +42,10 @@ import debounce from 'debounce'
|
|
|
42
42
|
|
|
43
43
|
const props = defineProps({
|
|
44
44
|
valueStart: {
|
|
45
|
-
default:
|
|
45
|
+
default: '',
|
|
46
46
|
},
|
|
47
47
|
valueEnd: {
|
|
48
|
-
default:
|
|
48
|
+
default: '',
|
|
49
49
|
},
|
|
50
50
|
min: {
|
|
51
51
|
default: 0,
|
|
@@ -61,19 +61,18 @@ const minFormatted = computed(() => Math.floor(props.min));
|
|
|
61
61
|
const maxFormatted = computed(() => Math.ceil(props.max));
|
|
62
62
|
|
|
63
63
|
const isChanged = computed(() => {
|
|
64
|
-
return start.value !== minFormatted.value || end.value !== maxFormatted.value;
|
|
64
|
+
return start.value && start.value !== minFormatted.value || end.value && end.value !== maxFormatted.value;
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
-
const start = ref(
|
|
68
|
-
const end = ref(
|
|
67
|
+
const start = ref(props.valueStart);
|
|
68
|
+
const end = ref(props.valueEnd);
|
|
69
69
|
|
|
70
|
-
const sliderValue = ref([
|
|
70
|
+
const sliderValue = ref([minFormatted.value, maxFormatted.value]);
|
|
71
71
|
|
|
72
72
|
const updateFromSlider =
|
|
73
73
|
debounce((value: [number, number]) => {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
end.value = value[1];
|
|
74
|
+
start.value = value[0] === minFormatted.value ? '': value[0];
|
|
75
|
+
end.value = value[1] === maxFormatted.value ? '': value[1];
|
|
77
76
|
}, 500);
|
|
78
77
|
|
|
79
78
|
onMounted(() => {
|
|
@@ -90,24 +89,13 @@ onMounted(() => {
|
|
|
90
89
|
})
|
|
91
90
|
|
|
92
91
|
function updateStartFromProps() {
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
}
|
|
92
|
+
start.value = props.valueStart;
|
|
93
|
+
setSliderValues(start.value, end.value)
|
|
101
94
|
}
|
|
102
95
|
|
|
103
96
|
function updateEndFromProps() {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
sliderValue.value = [start.value, end.value]
|
|
107
|
-
} else {
|
|
108
|
-
end.value = maxFormatted.value;
|
|
109
|
-
sliderValue.value = [start.value, maxFormatted.value];
|
|
110
|
-
}
|
|
97
|
+
end.value = props.valueEnd;
|
|
98
|
+
setSliderValues(start.value, end.value)
|
|
111
99
|
}
|
|
112
100
|
|
|
113
101
|
watch(start, () => {
|
|
@@ -121,9 +109,13 @@ watch(end, () => {
|
|
|
121
109
|
})
|
|
122
110
|
|
|
123
111
|
const clear = () => {
|
|
124
|
-
start.value =
|
|
125
|
-
end.value =
|
|
126
|
-
|
|
112
|
+
start.value = ''
|
|
113
|
+
end.value = ''
|
|
114
|
+
setSliderValues('', '')
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function setSliderValues(start, end) {
|
|
118
|
+
sliderValue.value = [start || minFormatted.value, end || maxFormatted.value];
|
|
127
119
|
}
|
|
128
120
|
</script>
|
|
129
121
|
|