@adminforth/universal-search 1.1.2 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build.log +2 -2
- package/custom/UniversalSearchInput.vue +20 -17
- package/custom/tsconfig.json +2 -5
- package/dist/custom/UniversalSearchInput.vue +20 -17
- package/dist/custom/tsconfig.json +2 -5
- package/dist/index.js +51 -37
- package/index.ts +75 -51
- package/package.json +1 -1
package/build.log
CHANGED
|
@@ -21,38 +21,41 @@
|
|
|
21
21
|
</template>
|
|
22
22
|
<script setup lang="ts">
|
|
23
23
|
import { ref, watch } from 'vue';
|
|
24
|
-
|
|
24
|
+
import adminforth from '@/adminforth';
|
|
25
|
+
import { AdminForthFilterOperators } from '@/types/Common';
|
|
25
26
|
|
|
26
27
|
const props = defineProps<{ meta?: any; resource?: any; adminUser?: any }>();
|
|
27
28
|
const localValue = ref('');
|
|
28
|
-
let
|
|
29
|
+
let t: any = null;
|
|
29
30
|
|
|
30
|
-
function
|
|
31
|
+
function send(term?: string) {
|
|
32
|
+
adminforth?.list?.updateFilter?.({
|
|
33
|
+
field: '_universal_search',
|
|
34
|
+
operator: AdminForthFilterOperators.EQ,
|
|
35
|
+
value: term || '',
|
|
36
|
+
});
|
|
37
|
+
adminforth?.list?.refresh?.();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function apply() {
|
|
31
41
|
const term = localValue.value.trim();
|
|
32
|
-
|
|
33
|
-
adminforth.list.refresh && adminforth.list.refresh();
|
|
42
|
+
send(term || '');
|
|
34
43
|
}
|
|
35
44
|
|
|
36
45
|
function applyImmediate() {
|
|
37
|
-
if (
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
applyInternal();
|
|
46
|
+
if (t) clearTimeout(t);
|
|
47
|
+
t = null;
|
|
48
|
+
apply();
|
|
42
49
|
}
|
|
43
50
|
|
|
44
51
|
watch(localValue, () => {
|
|
45
52
|
const delay = props.meta?.debounceMs ?? 500;
|
|
46
|
-
if (
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
debounceTimer = setTimeout(() => {
|
|
50
|
-
applyInternal();
|
|
51
|
-
}, delay);
|
|
53
|
+
if (t) clearTimeout(t);
|
|
54
|
+
t = setTimeout(apply, delay);
|
|
52
55
|
});
|
|
53
56
|
|
|
54
57
|
function clear() {
|
|
55
58
|
localValue.value = '';
|
|
56
59
|
applyImmediate();
|
|
57
60
|
}
|
|
58
|
-
</script>
|
|
61
|
+
</script>
|
package/custom/tsconfig.json
CHANGED
|
@@ -4,15 +4,12 @@
|
|
|
4
4
|
"esModuleInterop": true,
|
|
5
5
|
"paths": {
|
|
6
6
|
"@/*": [
|
|
7
|
-
|
|
8
|
-
"../../../spa/src/*"
|
|
7
|
+
"../node_modules/adminforth/dist/spa/src/*"
|
|
9
8
|
],
|
|
10
9
|
"*": [
|
|
11
|
-
|
|
12
|
-
"../../../spa/node_modules/*"
|
|
10
|
+
"../node_modules/adminforth/dist/spa/node_modules/*"
|
|
13
11
|
],
|
|
14
12
|
"@@/*": [
|
|
15
|
-
// "node_modules/adminforth/dist/spa/src/*"
|
|
16
13
|
"."
|
|
17
14
|
]
|
|
18
15
|
}
|
|
@@ -21,38 +21,41 @@
|
|
|
21
21
|
</template>
|
|
22
22
|
<script setup lang="ts">
|
|
23
23
|
import { ref, watch } from 'vue';
|
|
24
|
-
|
|
24
|
+
import adminforth from '@/adminforth';
|
|
25
|
+
import { AdminForthFilterOperators } from '@/types/Common';
|
|
25
26
|
|
|
26
27
|
const props = defineProps<{ meta?: any; resource?: any; adminUser?: any }>();
|
|
27
28
|
const localValue = ref('');
|
|
28
|
-
let
|
|
29
|
+
let t: any = null;
|
|
29
30
|
|
|
30
|
-
function
|
|
31
|
+
function send(term?: string) {
|
|
32
|
+
adminforth?.list?.updateFilter?.({
|
|
33
|
+
field: '_universal_search',
|
|
34
|
+
operator: AdminForthFilterOperators.EQ,
|
|
35
|
+
value: term || '',
|
|
36
|
+
});
|
|
37
|
+
adminforth?.list?.refresh?.();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function apply() {
|
|
31
41
|
const term = localValue.value.trim();
|
|
32
|
-
|
|
33
|
-
adminforth.list.refresh && adminforth.list.refresh();
|
|
42
|
+
send(term || '');
|
|
34
43
|
}
|
|
35
44
|
|
|
36
45
|
function applyImmediate() {
|
|
37
|
-
if (
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
applyInternal();
|
|
46
|
+
if (t) clearTimeout(t);
|
|
47
|
+
t = null;
|
|
48
|
+
apply();
|
|
42
49
|
}
|
|
43
50
|
|
|
44
51
|
watch(localValue, () => {
|
|
45
52
|
const delay = props.meta?.debounceMs ?? 500;
|
|
46
|
-
if (
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
debounceTimer = setTimeout(() => {
|
|
50
|
-
applyInternal();
|
|
51
|
-
}, delay);
|
|
53
|
+
if (t) clearTimeout(t);
|
|
54
|
+
t = setTimeout(apply, delay);
|
|
52
55
|
});
|
|
53
56
|
|
|
54
57
|
function clear() {
|
|
55
58
|
localValue.value = '';
|
|
56
59
|
applyImmediate();
|
|
57
60
|
}
|
|
58
|
-
</script>
|
|
61
|
+
</script>
|
|
@@ -4,15 +4,12 @@
|
|
|
4
4
|
"esModuleInterop": true,
|
|
5
5
|
"paths": {
|
|
6
6
|
"@/*": [
|
|
7
|
-
|
|
8
|
-
"../../../spa/src/*"
|
|
7
|
+
"../node_modules/adminforth/dist/spa/src/*"
|
|
9
8
|
],
|
|
10
9
|
"*": [
|
|
11
|
-
|
|
12
|
-
"../../../spa/node_modules/*"
|
|
10
|
+
"../node_modules/adminforth/dist/spa/node_modules/*"
|
|
13
11
|
],
|
|
14
12
|
"@@/*": [
|
|
15
|
-
// "node_modules/adminforth/dist/spa/src/*"
|
|
16
13
|
"."
|
|
17
14
|
]
|
|
18
15
|
}
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import { AdminForthPlugin, Filters } from 'adminforth';
|
|
10
|
+
import { AdminForthPlugin, AdminForthDataTypes, Filters } from 'adminforth';
|
|
11
11
|
export default class UniversalSearchPlugin extends AdminForthPlugin {
|
|
12
12
|
constructor(options) {
|
|
13
13
|
super(options, import.meta.url);
|
|
@@ -45,6 +45,15 @@ export default class UniversalSearchPlugin extends AdminForthPlugin {
|
|
|
45
45
|
if (!Array.isArray(this.resourceConfig.columns))
|
|
46
46
|
this.resourceConfig.columns = [];
|
|
47
47
|
const exists = this.resourceConfig.columns.some(c => c.name === virtualFieldName);
|
|
48
|
+
if (!exists) {
|
|
49
|
+
this.resourceConfig.columns.push({
|
|
50
|
+
name: virtualFieldName,
|
|
51
|
+
virtual: true,
|
|
52
|
+
type: AdminForthDataTypes.STRING,
|
|
53
|
+
label: 'Universal Search',
|
|
54
|
+
showIn: { all: false },
|
|
55
|
+
});
|
|
56
|
+
}
|
|
48
57
|
const injection = {
|
|
49
58
|
file: this.componentPath('UniversalSearchInput.vue'),
|
|
50
59
|
meta: {
|
|
@@ -76,67 +85,72 @@ export default class UniversalSearchPlugin extends AdminForthPlugin {
|
|
|
76
85
|
if (!this.resourceConfig.hooks.list)
|
|
77
86
|
this.resourceConfig.hooks.list = {};
|
|
78
87
|
const originalBefore = this.resourceConfig.hooks.list.beforeDatasourceRequest;
|
|
88
|
+
const VIRTUAL_FIELD = '_universal_search';
|
|
79
89
|
const transformFilters = (filters) => {
|
|
80
|
-
return filters.flatMap(f => {
|
|
90
|
+
return (filters !== null && filters !== void 0 ? filters : []).flatMap(f => {
|
|
91
|
+
var _a, _b;
|
|
81
92
|
if (!f)
|
|
82
93
|
return [];
|
|
83
|
-
|
|
94
|
+
const op = String((_a = f.operator) !== null && _a !== void 0 ? _a : '').toLowerCase();
|
|
95
|
+
if (op === 'or' || op === 'and') {
|
|
84
96
|
return [Object.assign(Object.assign({}, f), { subFilters: transformFilters(f.subFilters || []) })];
|
|
85
97
|
}
|
|
86
|
-
if (f.field ===
|
|
87
|
-
const term = (f.value
|
|
98
|
+
if (f.field === VIRTUAL_FIELD) {
|
|
99
|
+
const term = String((_b = f.value) !== null && _b !== void 0 ? _b : '').trim();
|
|
88
100
|
if (!term)
|
|
89
101
|
return [];
|
|
90
102
|
const sub = [];
|
|
91
|
-
|
|
103
|
+
for (const col of columns) {
|
|
92
104
|
const searchBy = (col.searchBy === 'labelOnly' ? 'keyOnly' : col.searchBy) || 'valueOnly';
|
|
93
|
-
const
|
|
105
|
+
const add = (field) => {
|
|
94
106
|
if (col.exact) {
|
|
95
|
-
if (col.caseSensitive)
|
|
107
|
+
if (col.caseSensitive)
|
|
96
108
|
sub.push(Filters.LIKE(field, term));
|
|
97
|
-
|
|
98
|
-
else {
|
|
109
|
+
else
|
|
99
110
|
sub.push(Filters.EQ(field, term));
|
|
100
|
-
}
|
|
101
111
|
}
|
|
102
112
|
else {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
else
|
|
107
|
-
sub.push(Filters.ILIKE
|
|
108
|
-
|
|
113
|
+
const likeVal = `${term}`;
|
|
114
|
+
if (col.caseSensitive)
|
|
115
|
+
sub.push(Filters.LIKE(field, likeVal));
|
|
116
|
+
else if (Filters.ILIKE)
|
|
117
|
+
sub.push(Filters.ILIKE(field, likeVal));
|
|
118
|
+
else
|
|
119
|
+
sub.push(Filters.LIKE(field, likeVal));
|
|
109
120
|
}
|
|
110
121
|
};
|
|
111
122
|
if (searchBy === 'valueOnly')
|
|
112
|
-
|
|
123
|
+
add(col.name);
|
|
113
124
|
else if (searchBy === 'keyOnly')
|
|
114
|
-
|
|
115
|
-
else
|
|
116
|
-
|
|
117
|
-
|
|
125
|
+
add(`${col.name}__key`);
|
|
126
|
+
else {
|
|
127
|
+
add(col.name);
|
|
128
|
+
add(`${col.name}__key`);
|
|
118
129
|
}
|
|
119
|
-
}
|
|
130
|
+
}
|
|
120
131
|
if (!sub.length)
|
|
121
132
|
return [];
|
|
122
|
-
|
|
123
|
-
return [Filters.OR(sub)];
|
|
133
|
+
return [Filters.OR(...sub)];
|
|
124
134
|
}
|
|
125
135
|
return [f];
|
|
126
136
|
});
|
|
127
137
|
};
|
|
128
|
-
const transformer = (
|
|
129
|
-
var
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
const transformer = (_a) => __awaiter(this, [_a], void 0, function* ({ query }) {
|
|
139
|
+
var _b, _c, _d, _e, _f;
|
|
140
|
+
const term = String(((_e = (_d = (_c = (_b = query === null || query === void 0 ? void 0 : query.body) === null || _b === void 0 ? void 0 : _b.__universal_search_term) !== null && _c !== void 0 ? _c : query === null || query === void 0 ? void 0 : query.__universal_search_term) !== null && _d !== void 0 ? _d : global.__universal_search_term) !== null && _e !== void 0 ? _e : '')).trim();
|
|
141
|
+
const incoming = Array.isArray(query === null || query === void 0 ? void 0 : query.filters)
|
|
142
|
+
? query.filters
|
|
143
|
+
: Array.isArray((_f = query === null || query === void 0 ? void 0 : query.body) === null || _f === void 0 ? void 0 : _f.filters)
|
|
144
|
+
? query.body.filters
|
|
145
|
+
: [];
|
|
146
|
+
const withVirtual = term
|
|
147
|
+
? [...incoming, { field: VIRTUAL_FIELD, operator: 'eq', value: term }]
|
|
148
|
+
: incoming;
|
|
149
|
+
const transformed = transformFilters(withVirtual);
|
|
150
|
+
query.filters = transformed;
|
|
151
|
+
query.body = Object.assign(Object.assign({}, (query.body || {})), { filters: transformed });
|
|
152
|
+
if (query.body.__universal_search_term !== undefined) {
|
|
153
|
+
delete query.body.__universal_search_term;
|
|
140
154
|
}
|
|
141
155
|
return { ok: true, error: '' };
|
|
142
156
|
});
|
package/index.ts
CHANGED
|
@@ -40,6 +40,15 @@ export default class UniversalSearchPlugin extends AdminForthPlugin {
|
|
|
40
40
|
|
|
41
41
|
if (!Array.isArray(this.resourceConfig.columns)) this.resourceConfig.columns = [] as any;
|
|
42
42
|
const exists = (this.resourceConfig.columns as any[]).some(c => c.name === virtualFieldName);
|
|
43
|
+
if (!exists) {
|
|
44
|
+
(this.resourceConfig.columns as any[]).push({
|
|
45
|
+
name: virtualFieldName,
|
|
46
|
+
virtual: true,
|
|
47
|
+
type: AdminForthDataTypes.STRING,
|
|
48
|
+
label: 'Universal Search',
|
|
49
|
+
showIn: { all: false },
|
|
50
|
+
});
|
|
51
|
+
}
|
|
43
52
|
|
|
44
53
|
const injection = {
|
|
45
54
|
file: this.componentPath('UniversalSearchInput.vue'),
|
|
@@ -67,59 +76,74 @@ export default class UniversalSearchPlugin extends AdminForthPlugin {
|
|
|
67
76
|
if (!this.resourceConfig.hooks.list) this.resourceConfig.hooks.list = {} as any;
|
|
68
77
|
const originalBefore = this.resourceConfig.hooks.list.beforeDatasourceRequest;
|
|
69
78
|
|
|
70
|
-
|
|
71
|
-
return filters.flatMap(f => {
|
|
72
|
-
if (!f) return [];
|
|
73
|
-
if (f.operator === 'or' || f.operator === 'and') {
|
|
74
|
-
return [{ ...f, subFilters: transformFilters(f.subFilters || []) }];
|
|
75
|
-
}
|
|
76
|
-
if (f.field === virtualFieldName) {
|
|
77
|
-
const term = (f.value || '').toString().trim();
|
|
78
|
-
if (!term) return [];
|
|
79
|
-
const sub: any[] = [];
|
|
80
|
-
columns.forEach(col => {
|
|
81
|
-
const searchBy = (col.searchBy === 'labelOnly' ? 'keyOnly' : col.searchBy) || 'valueOnly';
|
|
82
|
-
const addFilter = (field: string) => {
|
|
83
|
-
if (col.exact) {
|
|
84
|
-
if (col.caseSensitive) {
|
|
85
|
-
sub.push(Filters.LIKE(field, term));
|
|
86
|
-
} else {
|
|
87
|
-
sub.push(Filters.EQ(field, term));
|
|
88
|
-
}
|
|
89
|
-
} else {
|
|
90
|
-
if (col.caseSensitive) {
|
|
91
|
-
sub.push(Filters.LIKE(field, term));
|
|
92
|
-
} else {
|
|
93
|
-
sub.push((Filters as any).ILIKE ? (Filters as any).ILIKE(field, term) : { field, operator: 'ilike', value: term });
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
if (searchBy === 'valueOnly') addFilter(col.name);
|
|
98
|
-
else if (searchBy === 'keyOnly') addFilter(`${col.name}__key`);
|
|
99
|
-
else if (searchBy === 'both') { addFilter(col.name); addFilter(`${col.name}__key`); }
|
|
100
|
-
});
|
|
101
|
-
if (!sub.length) return [];
|
|
102
|
-
console.log('UniversalSearchPlugin: transformed filter', f, '=>', sub);
|
|
103
|
-
return [Filters.OR(sub)];
|
|
104
|
-
}
|
|
105
|
-
return [f];
|
|
106
|
-
});
|
|
107
|
-
};
|
|
79
|
+
const VIRTUAL_FIELD = '_universal_search';
|
|
108
80
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
if (
|
|
119
|
-
|
|
81
|
+
const transformFilters = (filters: any[]): any[] => {
|
|
82
|
+
return (filters ?? []).flatMap(f => {
|
|
83
|
+
if (!f) return [];
|
|
84
|
+
const op = String(f.operator ?? '').toLowerCase();
|
|
85
|
+
if (op === 'or' || op === 'and') {
|
|
86
|
+
return [{ ...f, subFilters: transformFilters(f.subFilters || []) }];
|
|
87
|
+
}
|
|
88
|
+
if (f.field === VIRTUAL_FIELD) {
|
|
89
|
+
const term = String(f.value ?? '').trim();
|
|
90
|
+
if (!term) return [];
|
|
91
|
+
const sub: any[] = [];
|
|
92
|
+
|
|
93
|
+
for (const col of columns) {
|
|
94
|
+
const searchBy = (col.searchBy === 'labelOnly' ? 'keyOnly' : col.searchBy) || 'valueOnly';
|
|
95
|
+
const add = (field: string) => {
|
|
96
|
+
if (col.exact) {
|
|
97
|
+
if (col.caseSensitive) sub.push(Filters.LIKE(field, term));
|
|
98
|
+
else sub.push(Filters.EQ(field, term));
|
|
99
|
+
} else {
|
|
100
|
+
const likeVal = `${term}`;
|
|
101
|
+
if (col.caseSensitive) sub.push(Filters.LIKE(field, likeVal));
|
|
102
|
+
else if ((Filters as any).ILIKE) sub.push((Filters as any).ILIKE(field, likeVal));
|
|
103
|
+
else sub.push(Filters.LIKE(field, likeVal));
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
if (searchBy === 'valueOnly') add(col.name);
|
|
107
|
+
else if (searchBy === 'keyOnly') add(`${col.name}__key`);
|
|
108
|
+
else { add(col.name); add(`${col.name}__key`); }
|
|
120
109
|
}
|
|
121
|
-
|
|
122
|
-
|
|
110
|
+
|
|
111
|
+
if (!sub.length) return [];
|
|
112
|
+
return [Filters.OR(...sub)];
|
|
113
|
+
}
|
|
114
|
+
return [f];
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const transformer = async ({ query }: { query: any }) => {
|
|
119
|
+
const term = String(
|
|
120
|
+
(query?.body?.__universal_search_term ??
|
|
121
|
+
query?.__universal_search_term ??
|
|
122
|
+
(global as any).__universal_search_term ??
|
|
123
|
+
'')
|
|
124
|
+
).trim();
|
|
125
|
+
|
|
126
|
+
const incoming = Array.isArray(query?.filters)
|
|
127
|
+
? query.filters
|
|
128
|
+
: Array.isArray(query?.body?.filters)
|
|
129
|
+
? query.body.filters
|
|
130
|
+
: [];
|
|
131
|
+
|
|
132
|
+
const withVirtual = term
|
|
133
|
+
? [...incoming, { field: VIRTUAL_FIELD, operator: 'eq', value: term }]
|
|
134
|
+
: incoming;
|
|
135
|
+
|
|
136
|
+
const transformed = transformFilters(withVirtual);
|
|
137
|
+
|
|
138
|
+
query.filters = transformed;
|
|
139
|
+
query.body = { ...(query.body || {}), filters: transformed };
|
|
140
|
+
|
|
141
|
+
if (query.body.__universal_search_term !== undefined) {
|
|
142
|
+
delete query.body.__universal_search_term;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return { ok: true, error: '' };
|
|
146
|
+
};
|
|
123
147
|
|
|
124
148
|
if (!originalBefore) {
|
|
125
149
|
this.resourceConfig.hooks.list.beforeDatasourceRequest = [transformer];
|