@followupus/common 0.8.5 → 0.8.7

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/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # common
2
2
 
3
3
  ## add a changelog after some modifications
4
+
4
5
  ```sh
5
6
  pnpm changeset
6
7
  ```
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export * from './shared/index.js';
2
- export * from './utils/index.js';
1
+ export * from "./shared/index.js";
2
+ export * from "./utils/index.js";
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export * from './shared/index.js';
2
- export * from './utils/index.js';
1
+ export * from "./shared/index.js";
2
+ export * from "./utils/index.js";
@@ -1,4 +1,4 @@
1
- import { IBaseCustomColumn, IBaseGroup, IFilter, IFilterCondition, IPureBoard } from './types';
1
+ import { IBaseCustomColumn, IBaseGroup, IFilter, IFilterCondition, IPureBoard } from "./types";
2
2
  export declare const COLUMN_TYPES: {
3
3
  NUMBER: string;
4
4
  TEXT: string;
@@ -52,8 +52,10 @@ export declare const DATE_GROUPS: {
52
52
  THIS_MONTH: string;
53
53
  FUTURE: string;
54
54
  };
55
+ export declare const isLinkedColumns: (columnType?: string) => boolean;
56
+ export declare const getColumnTypeFromId: (columnId: string) => string | undefined;
55
57
  export declare const getColumnValueType: (columnType: string) => "string" | "number" | "object" | "stringArray" | "objectArray";
56
58
  export declare const getDateGroupKey: (dateStr: string) => string | null;
57
- export declare const getValidConditions: (filter: IFilter, headers?: IBaseCustomColumn[], currentUserId?: string) => IFilterCondition[];
59
+ export declare const getValidConditions: (filter: IFilter, headers?: IBaseCustomColumn[], currentUserId?: string, escapeHeaderCheck?: boolean) => IFilterCondition[];
58
60
  export declare const filterItemsByConditions: (groups: IBaseGroup[], filter: IFilter, headers?: IBaseCustomColumn[], currentUserId?: string) => IBaseGroup[];
59
61
  export declare const filterBoardTree: (board: IPureBoard, filter: IFilter, currentUserId?: string) => IPureBoard;
@@ -1,5 +1,5 @@
1
1
  import dayjs from "dayjs";
2
- import _ from 'lodash';
2
+ import _ from "lodash";
3
3
  export const COLUMN_TYPES = {
4
4
  NUMBER: "number",
5
5
  TEXT: "string",
@@ -75,6 +75,12 @@ export const COLUMN_OP_TYPES = {
75
75
  OP_TYPES.EMPTY,
76
76
  OP_TYPES.NOT_EMPTY,
77
77
  ],
78
+ [COLUMN_TYPES.TAGS]: [
79
+ OP_TYPES.IS,
80
+ OP_TYPES.IS_NOT,
81
+ OP_TYPES.EMPTY,
82
+ OP_TYPES.NOT_EMPTY,
83
+ ],
78
84
  [COLUMN_TYPES.PEOPLE]: [
79
85
  OP_TYPES.IS,
80
86
  OP_TYPES.IS_NOT,
@@ -110,6 +116,14 @@ export const DATE_GROUPS = {
110
116
  THIS_MONTH: "thisMonth",
111
117
  FUTURE: "future",
112
118
  };
119
+ export const isLinkedColumns = (columnType) => {
120
+ if (!columnType)
121
+ return false;
122
+ return [COLUMN_TYPES.LINKED_COLUMN, COLUMN_TYPES.REF_LINED_COLUMN].includes(columnType);
123
+ };
124
+ export const getColumnTypeFromId = (columnId) => {
125
+ return Object.values(COLUMN_TYPES).find(type => columnId.startsWith(type));
126
+ };
113
127
  export const getColumnValueType = (columnType) => {
114
128
  switch (columnType) {
115
129
  case COLUMN_TYPES.PEOPLE:
@@ -117,6 +131,7 @@ export const getColumnValueType = (columnType) => {
117
131
  case COLUMN_TYPES.TAGS:
118
132
  return "stringArray";
119
133
  case COLUMN_TYPES.TIMELINE:
134
+ case COLUMN_TYPES.TIME_TRACKING:
120
135
  return "object";
121
136
  case COLUMN_TYPES.NUMBER:
122
137
  case COLUMN_TYPES.HOURS:
@@ -162,14 +177,21 @@ export const getDateGroupKey = (dateStr) => {
162
177
  }
163
178
  return DATE_GROUPS.FUTURE;
164
179
  };
165
- export const getValidConditions = (filter, headers, currentUserId) => {
180
+ export const getValidConditions = (filter, headers, currentUserId, escapeHeaderCheck) => {
166
181
  const newFilter = _.cloneDeep(filter);
167
182
  if (!newFilter.criteria?.length || !headers?.length) {
168
183
  return [];
169
184
  }
170
185
  newFilter.criteria.forEach(c => {
171
186
  const validHeader = headers.find(h => h.columnId === c.columnId);
172
- if (validHeader?.type === COLUMN_TYPES.PEOPLE) {
187
+ let checkHeader = validHeader;
188
+ if (isLinkedColumns(validHeader?.type)) {
189
+ checkHeader = validHeader?.linked;
190
+ }
191
+ if (!checkHeader && !escapeHeaderCheck)
192
+ return;
193
+ if (checkHeader?.type === COLUMN_TYPES.PEOPLE ||
194
+ c.columnId?.startsWith(COLUMN_TYPES.PEOPLE)) {
173
195
  if (c.value?.find(val => val === THEMSELVES) && currentUserId) {
174
196
  const idx = c.value.findIndex(val => val === THEMSELVES);
175
197
  if (idx > -1)
@@ -180,23 +202,34 @@ export const getValidConditions = (filter, headers, currentUserId) => {
180
202
  // for dropdown, if set the option is in filter condition, and user delete the option. should ignore it or make the option can't be deleted
181
203
  return newFilter.criteria.filter(c => {
182
204
  const validHeader = headers.find(h => h.columnId === c.columnId);
183
- if (!validHeader)
205
+ if (!validHeader && !escapeHeaderCheck)
206
+ return false;
207
+ let checkHeader = validHeader;
208
+ if (isLinkedColumns(validHeader?.type)) {
209
+ checkHeader = validHeader?.linked;
210
+ }
211
+ if (!checkHeader && !escapeHeaderCheck)
212
+ return false;
213
+ const columnType = checkHeader?.type || getColumnTypeFromId(c.columnId);
214
+ if (!columnType)
184
215
  return false;
185
- const validOperate = COLUMN_OP_TYPES[validHeader.type].includes(c.op);
216
+ const validOperate = COLUMN_OP_TYPES[columnType]?.includes(c.op);
186
217
  if (!validOperate)
187
218
  return false;
188
219
  const isDropdown = [
189
220
  COLUMN_TYPES.DROPDOWN,
190
221
  COLUMN_TYPES.STATUS,
191
222
  COLUMN_TYPES.PRIORITY,
192
- ].includes(validHeader.type);
223
+ COLUMN_TYPES.TAGS,
224
+ ].includes(columnType);
193
225
  switch (c.op) {
194
226
  case OP_TYPES.IS:
195
227
  case OP_TYPES.IS_NOT:
196
228
  return (c.blank ||
197
229
  (!!c.value?.filter(v => !!v || v === 0)?.length &&
198
230
  (!isDropdown ||
199
- c.value.some(v => validHeader.dropdowns?.find(d => d.key === v)))));
231
+ escapeHeaderCheck ||
232
+ c.value.some(v => checkHeader?.dropdowns?.find(d => d.key === v)))));
200
233
  case OP_TYPES.EMPTY:
201
234
  case OP_TYPES.NOT_EMPTY:
202
235
  return true;
@@ -264,16 +297,19 @@ const isContains = (itemVal, valueType, condition) => {
264
297
  const checkVal = condition.value?.length
265
298
  ? condition.value[0]
266
299
  : "";
300
+ const ignoreCaseCheck = (val, contains) => {
301
+ return !!val?.toLowerCase()?.includes(contains?.toLowerCase());
302
+ };
267
303
  switch (valueType) {
268
304
  case "number":
269
305
  return itemVal || itemVal === 0
270
- ? itemVal.toString().includes(checkVal)
306
+ ? itemVal?.toString()?.includes(checkVal)
271
307
  : false;
272
308
  case "string":
273
- return !!itemVal && itemVal.includes(checkVal);
309
+ return !!itemVal && ignoreCaseCheck(itemVal, checkVal);
274
310
  case "stringArray":
275
311
  return itemVal?.length
276
- ? itemVal.some(val => val.includes(checkVal))
312
+ ? itemVal.some(val => ignoreCaseCheck(val, checkVal))
277
313
  : false;
278
314
  default:
279
315
  break;
@@ -345,70 +381,92 @@ export const filterItemsByConditions = (groups, filter, headers, currentUserId)
345
381
  }
346
382
  groups.forEach(g => {
347
383
  g.items = g.items?.filter(item => {
348
- let match = false;
384
+ let isItemMatched = false;
349
385
  for (const condition of validConditions) {
350
386
  const header = headers?.find(h => h.columnId === condition.columnId);
351
- const valueType = getColumnValueType(header?.type ?? "");
352
- const itemVal = item.data?.[condition.columnId]?.value;
353
- const isDate = header?.type === COLUMN_TYPES.DATE;
354
- switch (condition.op) {
355
- case OP_TYPES.IS:
356
- match = isDate
357
- ? isDateInConditionValues(itemVal, condition)
358
- : isInConditionValues(itemVal, valueType, condition);
359
- break;
360
- case OP_TYPES.IS_NOT:
361
- match = isDate
362
- ? !isDateInConditionValues(itemVal, condition)
363
- : !isInConditionValues(itemVal, valueType, condition);
364
- break;
365
- case OP_TYPES.EMPTY:
366
- match = isEmpty(itemVal, valueType);
367
- break;
368
- case OP_TYPES.NOT_EMPTY:
369
- match = !isEmpty(itemVal, valueType);
370
- break;
371
- case OP_TYPES.CONTAINS:
372
- match = isContains(itemVal, valueType, condition);
373
- break;
374
- case OP_TYPES.NOT_CONTAINS:
375
- match = !isContains(itemVal, valueType, condition);
376
- break;
377
- case OP_TYPES.EQUAL:
378
- match = isEquals(itemVal, valueType, condition);
379
- break;
380
- case OP_TYPES.NOT_EQUAL:
381
- match = !isEquals(itemVal, valueType, condition);
382
- break;
383
- case OP_TYPES.GREATER:
384
- match =
385
- typeof itemVal === "number"
386
- ? isGreater(itemVal, condition)
387
- : false;
388
- break;
389
- case OP_TYPES.GREATER_EQUAL:
390
- match =
391
- typeof itemVal === "number"
392
- ? isGreaterEqual(itemVal, condition)
393
- : false;
394
- break;
395
- case OP_TYPES.LESS_EQUAL:
396
- match =
397
- typeof itemVal === "number"
398
- ? isLessEqual(itemVal, condition)
399
- : false;
400
- break;
401
- case OP_TYPES.LESS:
402
- match =
403
- typeof itemVal === "number" ? isLess(itemVal, condition) : false;
404
- break;
405
- default:
406
- break;
387
+ const isLinkedColumn = isLinkedColumns(header?.type);
388
+ let checkHeader = header;
389
+ if (isLinkedColumn) {
390
+ checkHeader = header?.linked;
391
+ }
392
+ const valueType = getColumnValueType(checkHeader?.type ?? "");
393
+ const checkConditionFn = (itemVal) => {
394
+ let match = false;
395
+ const isDate = checkHeader?.type === COLUMN_TYPES.DATE;
396
+ switch (condition.op) {
397
+ case OP_TYPES.IS:
398
+ match = isDate
399
+ ? isDateInConditionValues(itemVal, condition)
400
+ : isInConditionValues(itemVal, valueType, condition);
401
+ break;
402
+ case OP_TYPES.IS_NOT:
403
+ match = isDate
404
+ ? !isDateInConditionValues(itemVal, condition)
405
+ : !isInConditionValues(itemVal, valueType, condition);
406
+ break;
407
+ case OP_TYPES.EMPTY:
408
+ match = isEmpty(itemVal, valueType);
409
+ break;
410
+ case OP_TYPES.NOT_EMPTY:
411
+ match = !isEmpty(itemVal, valueType);
412
+ break;
413
+ case OP_TYPES.CONTAINS:
414
+ match = isContains(itemVal, valueType, condition);
415
+ break;
416
+ case OP_TYPES.NOT_CONTAINS:
417
+ match = !isContains(itemVal, valueType, condition);
418
+ break;
419
+ case OP_TYPES.EQUAL:
420
+ match = isEquals(itemVal, valueType, condition);
421
+ break;
422
+ case OP_TYPES.NOT_EQUAL:
423
+ match = !isEquals(itemVal, valueType, condition);
424
+ break;
425
+ case OP_TYPES.GREATER:
426
+ match =
427
+ typeof itemVal === "number"
428
+ ? isGreater(itemVal, condition)
429
+ : false;
430
+ break;
431
+ case OP_TYPES.GREATER_EQUAL:
432
+ match =
433
+ typeof itemVal === "number"
434
+ ? isGreaterEqual(itemVal, condition)
435
+ : false;
436
+ break;
437
+ case OP_TYPES.LESS_EQUAL:
438
+ match =
439
+ typeof itemVal === "number"
440
+ ? isLessEqual(itemVal, condition)
441
+ : false;
442
+ break;
443
+ case OP_TYPES.LESS:
444
+ match =
445
+ typeof itemVal === "number"
446
+ ? isLess(itemVal, condition)
447
+ : false;
448
+ break;
449
+ default:
450
+ break;
451
+ }
452
+ return match;
453
+ };
454
+ const itemValue = isLinkedColumn
455
+ ? item.data?.[condition.columnId]
456
+ : item.data?.[condition.columnId]?.value;
457
+ if (isLinkedColumn) {
458
+ isItemMatched = !!itemValue?.some((item) => {
459
+ const val = item.value;
460
+ return checkConditionFn(val);
461
+ });
462
+ }
463
+ else {
464
+ isItemMatched = checkConditionFn(itemValue);
407
465
  }
408
- if (!match)
466
+ if (!isItemMatched)
409
467
  return false;
410
468
  }
411
- return match;
469
+ return isItemMatched;
412
470
  });
413
471
  });
414
472
  return groups;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@followupus/common",
3
- "version": "0.8.5",
3
+ "version": "0.8.7",
4
4
  "description": "followup common utils npm package with TypeScript and VSCode",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",