@adminforth/universal-search 1.2.0 → 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 CHANGED
@@ -7,5 +7,5 @@ custom/
7
7
  custom/UniversalSearchInput.vue
8
8
  custom/tsconfig.json
9
9
 
10
- sent 2,630 bytes received 58 bytes 5,376.00 bytes/sec
11
- total size is 2,406 speedup is 0.90
10
+ sent 2,519 bytes received 58 bytes 5,154.00 bytes/sec
11
+ total size is 2,295 speedup is 0.89
@@ -21,38 +21,41 @@
21
21
  </template>
22
22
  <script setup lang="ts">
23
23
  import { ref, watch } from 'vue';
24
- const adminforth: any = (window as any).adminforth || {};
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 debounceTimer: any = null;
29
+ let t: any = null;
29
30
 
30
- function applyInternal() {
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
- adminforth.__universalSearchTerm = term || undefined;
33
- adminforth.list.refresh && adminforth.list.refresh();
42
+ send(term || '');
34
43
  }
35
44
 
36
45
  function applyImmediate() {
37
- if (debounceTimer) {
38
- clearTimeout(debounceTimer);
39
- debounceTimer = null;
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 (debounceTimer) {
47
- clearTimeout(debounceTimer);
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
- // "node_modules/adminforth/dist/spa/src/*"
8
- "../../../spa/src/*"
7
+ "../node_modules/adminforth/dist/spa/src/*"
9
8
  ],
10
9
  "*": [
11
- // "node_modules/adminforth/dist/spa/node_modules/*"
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
- const adminforth: any = (window as any).adminforth || {};
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 debounceTimer: any = null;
29
+ let t: any = null;
29
30
 
30
- function applyInternal() {
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
- adminforth.__universalSearchTerm = term || undefined;
33
- adminforth.list.refresh && adminforth.list.refresh();
42
+ send(term || '');
34
43
  }
35
44
 
36
45
  function applyImmediate() {
37
- if (debounceTimer) {
38
- clearTimeout(debounceTimer);
39
- debounceTimer = null;
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 (debounceTimer) {
47
- clearTimeout(debounceTimer);
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
- // "node_modules/adminforth/dist/spa/src/*"
8
- "../../../spa/src/*"
7
+ "../node_modules/adminforth/dist/spa/src/*"
9
8
  ],
10
9
  "*": [
11
- // "node_modules/adminforth/dist/spa/node_modules/*"
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
@@ -85,81 +85,72 @@ export default class UniversalSearchPlugin extends AdminForthPlugin {
85
85
  if (!this.resourceConfig.hooks.list)
86
86
  this.resourceConfig.hooks.list = {};
87
87
  const originalBefore = this.resourceConfig.hooks.list.beforeDatasourceRequest;
88
+ const VIRTUAL_FIELD = '_universal_search';
88
89
  const transformFilters = (filters) => {
89
- return filters.flatMap(f => {
90
+ return (filters !== null && filters !== void 0 ? filters : []).flatMap(f => {
91
+ var _a, _b;
90
92
  if (!f)
91
93
  return [];
92
- if (f.operator === 'or' || f.operator === 'and') {
94
+ const op = String((_a = f.operator) !== null && _a !== void 0 ? _a : '').toLowerCase();
95
+ if (op === 'or' || op === 'and') {
93
96
  return [Object.assign(Object.assign({}, f), { subFilters: transformFilters(f.subFilters || []) })];
94
97
  }
95
- if (f.field === virtualFieldName) {
96
- const term = (f.value || '').toString().trim();
98
+ if (f.field === VIRTUAL_FIELD) {
99
+ const term = String((_b = f.value) !== null && _b !== void 0 ? _b : '').trim();
97
100
  if (!term)
98
101
  return [];
99
102
  const sub = [];
100
- columns.forEach(col => {
103
+ for (const col of columns) {
101
104
  const searchBy = (col.searchBy === 'labelOnly' ? 'keyOnly' : col.searchBy) || 'valueOnly';
102
- const addFilter = (field) => {
105
+ const add = (field) => {
103
106
  if (col.exact) {
104
- if (col.caseSensitive) {
107
+ if (col.caseSensitive)
105
108
  sub.push(Filters.LIKE(field, term));
106
- }
107
- else {
109
+ else
108
110
  sub.push(Filters.EQ(field, term));
109
- }
110
111
  }
111
112
  else {
112
- if (col.caseSensitive) {
113
- sub.push(Filters.LIKE(field, term));
114
- }
115
- else {
116
- sub.push(Filters.ILIKE ? Filters.ILIKE(field, term) : { field, operator: 'ilike', value: term });
117
- }
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));
118
120
  }
119
121
  };
120
122
  if (searchBy === 'valueOnly')
121
- addFilter(col.name);
123
+ add(col.name);
122
124
  else if (searchBy === 'keyOnly')
123
- addFilter(`${col.name}__key`);
124
- else if (searchBy === 'both') {
125
- addFilter(col.name);
126
- addFilter(`${col.name}__key`);
125
+ add(`${col.name}__key`);
126
+ else {
127
+ add(col.name);
128
+ add(`${col.name}__key`);
127
129
  }
128
- });
130
+ }
129
131
  if (!sub.length)
130
132
  return [];
131
- console.log('UniversalSearchPlugin: transformed filter', f, '=>', sub);
132
- return [Filters.OR(sub)];
133
+ return [Filters.OR(...sub)];
133
134
  }
134
135
  return [f];
135
136
  });
136
137
  };
137
- const transformer = (ctx) => __awaiter(this, void 0, void 0, function* () {
138
- var _a, _b, _c;
139
- const { query } = ctx;
140
- let incomingTerm = ((_c = (_b = (_a = query === null || query === void 0 ? void 0 : query.body) === null || _a === void 0 ? void 0 : _a.__universal_search_term) !== null && _b !== void 0 ? _b : query === null || query === void 0 ? void 0 : query.__universal_search_term) !== null && _c !== void 0 ? _c : '').toString().trim();
141
- if (!incomingTerm && Array.isArray(query === null || query === void 0 ? void 0 : query.filters)) {
142
- const vf = query.filters.find(f => (f === null || f === void 0 ? void 0 : f.field) === virtualFieldName && typeof f.value === 'string');
143
- if (vf)
144
- incomingTerm = vf.value.trim();
145
- }
146
- if (ephemeral) {
147
- if (incomingTerm) {
148
- query.__universal_search_term = incomingTerm;
149
- const alreadyHas = Array.isArray(query.filters) && query.filters.some(f => (f === null || f === void 0 ? void 0 : f.field) === virtualFieldName);
150
- if (!alreadyHas) {
151
- const tempFilter = { field: virtualFieldName, operator: 'eq', value: incomingTerm };
152
- query.filters = Array.isArray(query.filters) ? [...query.filters, tempFilter] : [tempFilter];
153
- }
154
- }
155
- else {
156
- if (Array.isArray(query.filters)) {
157
- query.filters = query.filters.filter(f => (f === null || f === void 0 ? void 0 : f.field) !== virtualFieldName);
158
- }
159
- }
160
- }
161
- if (Array.isArray(query === null || query === void 0 ? void 0 : query.filters)) {
162
- query.filters = transformFilters(query.filters);
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;
163
154
  }
164
155
  return { ok: true, error: '' };
165
156
  });
package/index.ts CHANGED
@@ -76,75 +76,74 @@ export default class UniversalSearchPlugin extends AdminForthPlugin {
76
76
  if (!this.resourceConfig.hooks.list) this.resourceConfig.hooks.list = {} as any;
77
77
  const originalBefore = this.resourceConfig.hooks.list.beforeDatasourceRequest;
78
78
 
79
- const transformFilters = (filters: any[]): any[] => {
80
- return filters.flatMap(f => {
81
- if (!f) return [];
82
- if (f.operator === 'or' || f.operator === 'and') {
83
- return [{ ...f, subFilters: transformFilters(f.subFilters || []) }];
84
- }
85
- if (f.field === virtualFieldName) {
86
- const term = (f.value || '').toString().trim();
87
- if (!term) return [];
88
- const sub: any[] = [];
89
- columns.forEach(col => {
90
- const searchBy = (col.searchBy === 'labelOnly' ? 'keyOnly' : col.searchBy) || 'valueOnly';
91
- const addFilter = (field: string) => {
92
- if (col.exact) {
93
- if (col.caseSensitive) {
94
- sub.push(Filters.LIKE(field, term));
95
- } else {
96
- sub.push(Filters.EQ(field, term));
97
- }
98
- } else {
99
- if (col.caseSensitive) {
100
- sub.push(Filters.LIKE(field, term));
101
- } else {
102
- sub.push((Filters as any).ILIKE ? (Filters as any).ILIKE(field, term) : { field, operator: 'ilike', value: term });
103
- }
104
- }
105
- };
106
- if (searchBy === 'valueOnly') addFilter(col.name);
107
- else if (searchBy === 'keyOnly') addFilter(`${col.name}__key`);
108
- else if (searchBy === 'both') { addFilter(col.name); addFilter(`${col.name}__key`); }
109
- });
110
- if (!sub.length) return [];
111
- console.log('UniversalSearchPlugin: transformed filter', f, '=>', sub);
112
- return [Filters.OR(sub)];
113
- }
114
- return [f];
115
- });
116
- };
117
-
118
- const transformer = async (ctx: any) => {
119
- const { query } = ctx;
120
-
121
- let incomingTerm = (query?.body?.__universal_search_term ?? query?.__universal_search_term ?? '').toString().trim();
122
- if (!incomingTerm && Array.isArray(query?.filters)) {
123
- const vf = (query.filters as any[]).find(f => f?.field === virtualFieldName && typeof f.value === 'string');
124
- if (vf) incomingTerm = vf.value.trim();
125
- }
126
-
127
- if (ephemeral) {
128
- if (incomingTerm) {
129
- query.__universal_search_term = incomingTerm;
130
- const alreadyHas = Array.isArray(query.filters) && (query.filters as any[]).some(f => f?.field === virtualFieldName);
131
- if (!alreadyHas) {
132
- const tempFilter = { field: virtualFieldName, operator: 'eq', value: incomingTerm };
133
- query.filters = Array.isArray(query.filters) ? [...query.filters, tempFilter] : [tempFilter];
134
- }
135
- } else {
136
- if (Array.isArray(query.filters)) {
137
- query.filters = (query.filters as any[]).filter(f => f?.field !== virtualFieldName);
79
+ const VIRTUAL_FIELD = '_universal_search';
80
+
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));
138
104
  }
139
- }
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`); }
140
109
  }
141
110
 
142
- if (Array.isArray(query?.filters)) {
143
- query.filters = transformFilters(query.filters);
144
- }
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
+ }
145
144
 
146
- return { ok: true, error: '' };
147
- };
145
+ return { ok: true, error: '' };
146
+ };
148
147
 
149
148
  if (!originalBefore) {
150
149
  this.resourceConfig.hooks.list.beforeDatasourceRequest = [transformer];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/universal-search",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Universal quick search input plugin for AdminForth (injected before action buttons)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",