@dataloop-ai/components 0.17.94 → 0.17.95

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dataloop-ai/components",
3
- "version": "0.17.94",
3
+ "version": "0.17.95",
4
4
  "exports": {
5
5
  ".": "./index.ts",
6
6
  "./models": "./models.ts",
@@ -103,6 +103,10 @@ export default defineComponent({
103
103
  type: Object as PropType<Partial<DateInterval> | null>,
104
104
  default: null
105
105
  },
106
+ singleSelection: {
107
+ type: Boolean,
108
+ default: false
109
+ },
106
110
  normalizeCalendars: Boolean,
107
111
  disabled: Boolean
108
112
  },
@@ -245,7 +249,11 @@ export default defineComponent({
245
249
 
246
250
  this.dateInterval = { from: date, to: date }
247
251
 
248
- this.isSelectionMode = true
252
+ if (this.singleSelection) {
253
+ this.isSelectionMode = true
254
+ } else {
255
+ this.updateModelValue(this.dateInterval)
256
+ }
249
257
  },
250
258
 
251
259
  handleMouseenter(date: Date) {
@@ -343,7 +343,9 @@ export default defineComponent({
343
343
  const handleInputModel = (value: string) => {
344
344
  inputModel.value = value
345
345
  const json = toJSON(removeBrackets(value))
346
- emit('update:modelValue', json)
346
+ if (!isEqual(json, props.modelValue)) {
347
+ emit('update:modelValue', json)
348
+ }
347
349
  const stringified = JSON.stringify(json)
348
350
  const newQuery = replaceWithAliases(stringified, props.aliases)
349
351
  activeQuery.value.query = newQuery
@@ -356,10 +358,23 @@ export default defineComponent({
356
358
 
357
359
  const debouncedInputModel = debounce(handleInputModel, 300)
358
360
 
361
+ const isValidJSON = (item: string | Object): boolean => {
362
+ let value = typeof item !== 'string' ? JSON.stringify(item) : item
363
+ try {
364
+ value = JSON.parse(value)
365
+ } catch (e) {
366
+ return false
367
+ }
368
+
369
+ return typeof value === 'object' && value !== null
370
+ }
371
+
359
372
  const toJSON = (value: string) => {
360
- return parseSmartQuery(
373
+ const json = parseSmartQuery(
361
374
  replaceWithJsDates(value) ?? inputModel.value
362
375
  )
376
+
377
+ return isValidJSON(json) ? json : inputModel.value
363
378
  }
364
379
 
365
380
  const setFocused = (value: boolean) => {
@@ -383,7 +398,9 @@ export default defineComponent({
383
398
  return
384
399
  }
385
400
  const stringQuery = stringifySmartQuery(val)
386
- debouncedInputModel(stringQuery)
401
+ if (stringQuery !== inputModel.value.trim()) {
402
+ debouncedInputModel(stringQuery)
403
+ }
387
404
  }
388
405
  })
389
406
 
@@ -117,7 +117,10 @@
117
117
  :offset="[0, 3]"
118
118
  >
119
119
  <div class="dl-smart-search-input__date-picker-wrapper">
120
- <dl-date-picker @change="handleDateSelectionUpdate" />
120
+ <dl-date-picker
121
+ :single-selection="false"
122
+ @change="handleDateSelectionUpdate"
123
+ />
121
124
  </div>
122
125
  </dl-menu>
123
126
  </div>
@@ -2,19 +2,10 @@ export * from './highlightSyntax'
2
2
  export * from './utils'
3
3
 
4
4
  import { DateInterval } from '../../../DlDateTime/types'
5
-
6
- const startDatePattern = new RegExp(
7
- /\(from\s?\d{2}\/\d{2}\/\d{4}\s?\)|\(from\s?dd\/mm\/yyyy\s?\)/,
8
- 'gi'
9
- )
10
- const endDatePattern = new RegExp(
11
- /\(to\s?\d{2}\/\d{2}\/\d{4}\s?\)|\(to\s?dd\/mm\/yyyy\s?\)/,
12
- 'gi'
13
- )
14
- const dateIntervalPattern = new RegExp(
15
- /\((from\s?\(\d{2}\/\d{2}\/\d{4}\)\s?to\s?\(\d{2}\/\d{2}\/\d{4}\))\)|\((from\s?\(dd\/mm\/yyyy\)\s?to\s?\(dd\/mm\/yyyy\))\)/,
16
- 'gi'
17
- )
5
+ import {
6
+ datePattern,
7
+ datePatternNoBrackets
8
+ } from '../../../../../hooks/use-suggestions'
18
9
 
19
10
  export const isEndOfString = (str: string, pattern: RegExp): boolean => {
20
11
  const trimmed = str.trim()
@@ -23,40 +14,21 @@ export const isEndOfString = (str: string, pattern: RegExp): boolean => {
23
14
  if (!matches || !matches.length) return false
24
15
 
25
16
  const lastMatch = matches[matches.length - 1]
17
+
26
18
  return trimmed.lastIndexOf(lastMatch) + lastMatch.length === trimmed.length
27
19
  }
28
20
 
29
21
  export const isEndingWithDateIntervalPattern = (str: string) => {
30
- return (
31
- isEndOfString(str, dateIntervalPattern) ||
32
- isEndOfString(str, startDatePattern) ||
33
- isEndOfString(str, endDatePattern)
34
- )
22
+ return isEndOfString(str, datePattern)
35
23
  }
36
24
 
37
- export const replaceDateInterval = (
38
- str: string,
39
- dateInterval: DateInterval
40
- ) => {
41
- const dateFrom = new Date(dateInterval.from)
42
- const dateTo = new Date(dateInterval.to)
43
- const values = str.match(/\((.*?)\)/g)
44
- let newStr = ''
45
- if (!values) return str
46
-
47
- if (values.length > 1) {
48
- newStr = `(From (${formatDate(dateFrom)}) To (${formatDate(dateTo)}))`
49
- return replaceLastOccurrence(str, newStr, dateIntervalPattern)
50
- } else if (values[0].includes('From')) {
51
- newStr = `(From ${formatDate(dateFrom)})`
52
- return replaceLastOccurrence(str, newStr, startDatePattern)
53
- } else if (values[0].includes('To')) {
54
- newStr = `(To ${formatDate(dateTo)})`
55
- return replaceLastOccurrence(str, newStr, endDatePattern)
56
- }
25
+ export const replaceDateInterval = (str: string, date: DateInterval) => {
26
+ const newStr = `${formatDate(date.from)}`
27
+ return replaceLastOccurrence(str, newStr, datePatternNoBrackets)
57
28
  }
58
29
 
59
30
  const formatDate = (date: Date): string => {
31
+ if (!date) return
60
32
  return `${addZero(date.getDate())}/${addZero(
61
33
  date.getMonth() + 1
62
34
  )}/${date.getFullYear()}`
@@ -2,9 +2,7 @@ import { ColorSchema, SyntaxColorSchema, Filters } from '../types'
2
2
  import {
3
3
  operators,
4
4
  Alias,
5
- startDatePattern,
6
- endDatePattern,
7
- dateIntervalPattern
5
+ datePattern
8
6
  } from '../../../../../hooks/use-suggestions'
9
7
 
10
8
  export function getTabItems(filters: Filters) {
@@ -25,37 +23,22 @@ export function getTabItems(filters: Filters) {
25
23
  }
26
24
 
27
25
  export function replaceWithJsDates(str: string) {
28
- const intervals = str.match(dateIntervalPattern)
29
- const starts = str.match(startDatePattern)
30
- const ends = str.match(endDatePattern)
26
+ const dates = str.match(datePattern)
31
27
 
32
- intervals?.forEach((interval) => {
33
- str = str.replaceAll(interval, formatToDateObj(interval))
34
- })
35
- starts?.forEach((start) => {
36
- str = str.replaceAll(start, formatToDateObj(start))
37
- })
38
- ends?.forEach((end) => {
39
- str = str.replaceAll(end, formatToDateObj(end))
28
+ dates?.forEach((date) => {
29
+ str = str.replaceAll(date, formatToNumericDate(date))
40
30
  })
31
+
41
32
  return str
42
33
  }
43
34
 
44
- function formatToDateObj(str: string) {
45
- const [day, month, year] = str.split(' ')[1].split('/')
46
- const date = new Date(parseInt(year), parseInt(month), parseInt(day))
47
- if (!isValidDate(date)) return str
48
- const [toDay, toMonth, toYear] = str.split(' ')[3]?.split('/') || []
49
- const toDate = new Date(
50
- parseInt(toYear),
51
- parseInt(toMonth),
52
- parseInt(toDay)
53
- )
54
- if (!isValidDate(toDate)) return date.toISOString()
55
- return JSON.stringify({
56
- from: date.toISOString(),
57
- to: toDate.toISOString()
58
- })
35
+ function formatToNumericDate(str: string) {
36
+ const dateInfo = str.split('/')
37
+ const day = parseInt(dateInfo[0])
38
+ const month = parseInt(dateInfo[1])
39
+ const year = parseInt(dateInfo[2])
40
+ const newDate = new Date(year, month, day)
41
+ return newDate.getTime().toString()
59
42
  }
60
43
 
61
44
  function isValidDate(d: Date) {
@@ -71,24 +71,50 @@ type Expression = {
71
71
  }
72
72
 
73
73
  const space = ' '
74
- const dateStartSuggestionString = '(From dd/mm/yyyy)'
75
- const dateEndSuggestionString = '(To dd/mm/yyyy)'
76
- const dateIntervalSuggestionString = '(From (dd/mm/yyyy) To (dd/mm/yyyy))'
74
+ const dateSuggestionPattern = '(dd/mm/yyyy)'
77
75
 
78
76
  let localSuggestions: Suggestion[] = []
79
77
 
80
- export const startDatePattern = new RegExp(
81
- /(from\s?\d{2}\/\d{2}\/\d{4}\s?|from\s?dd\/mm\/yyyy\s?)/,
82
- 'gi'
83
- )
84
- export const endDatePattern = new RegExp(
85
- /(to\s?\d{2}\/\d{2}\/\d{4}\s?|to\s?dd\/mm\/yyyy\s?)/,
86
- 'gi'
87
- )
88
- export const dateIntervalPattern = new RegExp(
89
- /(from\s?\d{2}\/\d{2}\/\d{4}\s?to\s?\d{2}\/\d{2}\/\d{4})|(from\s?dd\/mm\/yyyy\s?to\s?dd\/mm\/yyyy)/,
78
+ export const datePattern = new RegExp(
79
+ /(\(\d{2}\/\d{2}\/\d{4}\)\s?|\s?\(dd\/mm\/yyyy\)\s?)/,
90
80
  'gi'
91
81
  )
82
+ export const datePatternNoBrackets =
83
+ /(\d{2}\/\d{2}\/\d{4}\s?|\s?dd\/mm\/yyyy\s?)/
84
+
85
+ const mergeWords = (words: string[]) => {
86
+ const result: string[] = []
87
+ let merging = false
88
+ let mergeIndex = -1
89
+
90
+ for (let i = 0; i < words.length; ++i) {
91
+ const currentItem = words[i]
92
+
93
+ if (currentItem === 'IN' || currentItem === 'NOT-IN') {
94
+ merging = true
95
+ mergeIndex = i + 1
96
+ result.push(currentItem)
97
+ continue
98
+ } else if (
99
+ Object.values(Logical).includes(currentItem as any) ||
100
+ Object.values(operators).includes(currentItem as any)
101
+ ) {
102
+ merging = false
103
+ }
104
+
105
+ if (merging) {
106
+ if (!result[mergeIndex]) {
107
+ result[mergeIndex] = ''
108
+ }
109
+ result[mergeIndex] += ' ' + currentItem
110
+ continue
111
+ }
112
+
113
+ result.push(currentItem)
114
+ }
115
+
116
+ return result
117
+ }
92
118
 
93
119
  export const useSuggestions = (
94
120
  schema: Schema,
@@ -123,7 +149,8 @@ export const useSuggestions = (
123
149
  localSuggestions = sortedSuggestions
124
150
 
125
151
  const words = splitByQuotes(input, space)
126
- const expressions = mapWordsToExpressions(words)
152
+ const mergedWords = mergeWords(words)
153
+ const expressions = mapWordsToExpressions(mergedWords)
127
154
 
128
155
  for (const { field, operator, value, keyword } of expressions) {
129
156
  let matchedField: Suggestion | null = null
@@ -191,11 +218,7 @@ export const useSuggestions = (
191
218
  dataType === 'date' ||
192
219
  dataType === 'time'
193
220
  ) {
194
- localSuggestions = [
195
- dateIntervalSuggestionString,
196
- dateStartSuggestionString,
197
- dateEndSuggestionString
198
- ]
221
+ localSuggestions = [dateSuggestionPattern]
199
222
 
200
223
  if (!value) continue
201
224
 
@@ -356,11 +379,7 @@ const validateBracketValues = (value: string) => {
356
379
  }
357
380
 
358
381
  const isValidDateIntervalPattern = (str: string) => {
359
- return (
360
- !!str.match(dateIntervalPattern) ||
361
- !!str.match(startDatePattern) ||
362
- !!str.match(endDatePattern)
363
- )
382
+ return !!str.match(datePatternNoBrackets)
364
383
  }
365
384
 
366
385
  const isValidNumber = (str: string) => {
@@ -509,11 +528,7 @@ const getValueSuggestions = (dataType: string | string[], operator: string) => {
509
528
  case 'date':
510
529
  case 'time':
511
530
  case 'datetime':
512
- suggestion.push(
513
- dateIntervalSuggestionString,
514
- dateStartSuggestionString,
515
- dateEndSuggestionString
516
- )
531
+ suggestion.push(dateSuggestionPattern)
517
532
  default:
518
533
  // do nothing
519
534
  break