@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 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
@@ -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
- 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') {
84
96
  return [Object.assign(Object.assign({}, f), { subFilters: transformFilters(f.subFilters || []) })];
85
97
  }
86
- if (f.field === virtualFieldName) {
87
- 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();
88
100
  if (!term)
89
101
  return [];
90
102
  const sub = [];
91
- columns.forEach(col => {
103
+ for (const col of columns) {
92
104
  const searchBy = (col.searchBy === 'labelOnly' ? 'keyOnly' : col.searchBy) || 'valueOnly';
93
- const addFilter = (field) => {
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
- if (col.caseSensitive) {
104
- sub.push(Filters.LIKE(field, term));
105
- }
106
- else {
107
- sub.push(Filters.ILIKE ? Filters.ILIKE(field, term) : { field, operator: 'ilike', value: term });
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
- addFilter(col.name);
123
+ add(col.name);
113
124
  else if (searchBy === 'keyOnly')
114
- addFilter(`${col.name}__key`);
115
- else if (searchBy === 'both') {
116
- addFilter(col.name);
117
- addFilter(`${col.name}__key`);
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
- console.log('UniversalSearchPlugin: transformed filter', f, '=>', sub);
123
- return [Filters.OR(sub)];
133
+ return [Filters.OR(...sub)];
124
134
  }
125
135
  return [f];
126
136
  });
127
137
  };
128
- const transformer = (ctx) => __awaiter(this, void 0, void 0, function* () {
129
- var _a;
130
- const { query } = ctx;
131
- if (ephemeral) {
132
- const term = (((_a = query === null || query === void 0 ? void 0 : query.body) === null || _a === void 0 ? void 0 : _a.__universal_search_term) || (query === null || query === void 0 ? void 0 : query.__universal_search_term) || '').toString().trim();
133
- if (term) {
134
- const tempFilter = { field: virtualFieldName, operator: 'eq', value: term };
135
- query.filters = Array.isArray(query.filters) ? [...query.filters, tempFilter] : [tempFilter];
136
- }
137
- }
138
- if (Array.isArray(query === null || query === void 0 ? void 0 : query.filters)) {
139
- 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;
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
- const transformFilters = (filters: any[]): any[] => {
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
- const transformer = async (ctx: any) => {
110
- const { query } = ctx;
111
- if (ephemeral) {
112
- const term = (query?.body?.__universal_search_term || query?.__universal_search_term || '').toString().trim();
113
- if (term) {
114
- const tempFilter = { field: virtualFieldName, operator: 'eq', value: term };
115
- query.filters = Array.isArray(query.filters) ? [...query.filters, tempFilter] : [tempFilter];
116
- }
117
- }
118
- if (Array.isArray(query?.filters)) {
119
- query.filters = transformFilters(query.filters);
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
- return { ok: true, error: '' };
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];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/universal-search",
3
- "version": "1.1.2",
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",