shared-ritm 1.2.64 → 1.2.66

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.
Files changed (58) hide show
  1. package/README.md +103 -103
  2. package/dist/index.css +1 -1
  3. package/dist/shared-ritm.es.js +3937 -3934
  4. package/dist/shared-ritm.umd.js +7 -7
  5. package/dist/types/api/services/SearchService.d.ts +7 -0
  6. package/dist/types/api/settings/ApiService.d.ts +1 -0
  7. package/dist/types/api/types/Api_Search.d.ts +43 -0
  8. package/dist/types/api/types/Api_Users.d.ts +43 -0
  9. package/dist/types/index.d.ts +4 -2
  10. package/package.json +63 -63
  11. package/src/api/services/ControlsService.ts +64 -64
  12. package/src/api/services/GanttService.ts +17 -17
  13. package/src/api/services/InstrumentsService.ts +22 -22
  14. package/src/api/services/MetricsService.ts +109 -109
  15. package/src/api/services/ProjectsService.ts +67 -67
  16. package/src/api/services/RepairsService.ts +100 -100
  17. package/src/api/services/SearchService.ts +15 -0
  18. package/src/api/services/VideoService.ts +14 -14
  19. package/src/api/settings/ApiService.ts +1 -0
  20. package/src/api/types/Api_Controls.ts +72 -72
  21. package/src/api/types/Api_Files.ts +1 -1
  22. package/src/api/types/Api_Instruments.ts +133 -133
  23. package/src/api/types/Api_Projects.ts +55 -55
  24. package/src/api/types/Api_Repairs.ts +93 -93
  25. package/src/api/types/Api_Search.ts +48 -0
  26. package/src/api/types/Api_Tasks.ts +155 -155
  27. package/src/common/app-checkbox/AppCheckbox.vue +26 -26
  28. package/src/common/app-dialogs/AppConfirmDialog.vue +99 -99
  29. package/src/common/app-dropdown/AppDropdown.vue +31 -31
  30. package/src/common/app-input/AppInput.vue +148 -148
  31. package/src/common/app-select/AppSelect.vue +157 -157
  32. package/src/common/app-sheet/AppSheet.vue +120 -120
  33. package/src/common/app-sidebar/components/SidebarMenuItem.vue +148 -148
  34. package/src/common/app-table/AppTable.vue +250 -250
  35. package/src/common/app-table/AppTableLayout.vue +111 -111
  36. package/src/common/app-table/components/ModalSelect.vue +264 -264
  37. package/src/common/app-table/components/TableModal.vue +329 -329
  38. package/src/common/app-table/components/TablePagination.vue +152 -152
  39. package/src/common/app-table/components/TableSearch.vue +76 -76
  40. package/src/common/app-table/controllers/useBaseTable.ts +42 -42
  41. package/src/common/app-table/controllers/useColumnSelector.ts +38 -38
  42. package/src/common/app-table/controllers/useTableModel.ts +93 -93
  43. package/src/common/app-toggle/AppToggle.vue +23 -23
  44. package/src/common/app-wrapper/AppWrapper.vue +28 -28
  45. package/src/icons/components/table-filter-icon.vue +30 -30
  46. package/src/icons/dialogs/RemoveIcon.vue +12 -12
  47. package/src/icons/dialogs/SafetyIcon.vue +12 -12
  48. package/src/icons/task/attention-icon.vue +13 -13
  49. package/src/icons/task/clock-icon.vue +10 -10
  50. package/src/icons/task/delete-icon.vue +10 -10
  51. package/src/icons/task/fire-icon.vue +16 -16
  52. package/src/index.ts +4 -1
  53. package/src/main.ts +28 -28
  54. package/src/shared/styles/general.css +125 -125
  55. package/src/styles/variables.sass +12 -12
  56. package/src/utils/confirm.ts +12 -12
  57. package/src/utils/helpers.ts +39 -39
  58. package/src/utils/notification.ts +9 -9
@@ -1,264 +1,264 @@
1
- <template>
2
- <label class="field-label">
3
- {{ label }}
4
- <span v-if="rules?.length && isShowRequired" class="required">*</span>
5
- </label>
6
-
7
- <q-select
8
- ref="select"
9
- v-model="selected"
10
- :options="filteredOptions"
11
- :disable="isDisabled"
12
- :multiple="multiple"
13
- :popup-content-class="'custom-select-menu'"
14
- :hide-selected="!showChip"
15
- :placeholder="placeholder"
16
- :loading="loading"
17
- :option-value="optionValue || 'value'"
18
- :option-label="optionLabel || 'label'"
19
- emit-value
20
- filled
21
- map-options
22
- stack-label
23
- use-input
24
- use-chips
25
- input-debounce="100"
26
- autocomplete=""
27
- :rules="rules"
28
- @virtual-scroll="onScroll"
29
- @filter="filterFn"
30
- >
31
- <template v-if="multiple || showChip" #selected-item="scope">
32
- <q-chip
33
- v-if="scope.opt"
34
- removable
35
- :tabindex="scope.tabindex"
36
- :style="{ backgroundColor: chipColor }"
37
- icon-remove="close"
38
- text-color="secondary"
39
- @remove="scope.removeAtIndex(scope.index)"
40
- >
41
- {{ scope.opt[optionLabel || 'label'] }}
42
- </q-chip>
43
- </template>
44
-
45
- <template #append>
46
- <q-icon
47
- v-if="!isDisabled && selected && selected.length"
48
- name="close"
49
- class="cursor-pointer clear-input"
50
- @click.stop="handleClear"
51
- />
52
- </template>
53
-
54
- <template #no-option>
55
- <div class="q-pa-sm">
56
- <q-item>
57
- <q-item-section class="wrapper-empty-text">
58
- {{ emptyText }}
59
- <button
60
- v-if="allowCreate && internalSearch && internalSearch.trim()"
61
- class="add-new-items"
62
- @click="handleCreateFromSearch"
63
- >
64
- Добавить
65
- </button>
66
- </q-item-section>
67
- </q-item>
68
- </div>
69
- </template>
70
-
71
- <template #option="scope">
72
- <q-item v-if="scope.opt.__loading" class="q-py-md q-ml-md">
73
- <q-spinner-dots size="24px" color="primary" />
74
- </q-item>
75
- <q-item v-else v-bind="scope.itemProps">
76
- <q-item-section>{{ scope.opt[optionLabel || 'label'] }}</q-item-section>
77
- </q-item>
78
- </template>
79
- </q-select>
80
- </template>
81
-
82
- <script setup lang="ts">
83
- import { computed, defineEmits, defineProps, ref, Ref } from 'vue'
84
- type Option = Record<string, any>
85
-
86
- interface AppQSelectProps {
87
- modelValue: any
88
- options: Option[]
89
- placeholder: string | undefined
90
- emptyText: string
91
- optionLabel?: string
92
- optionValue?: string
93
- label?: string
94
- multiple?: boolean
95
- loading?: boolean
96
- isShowRequired?: boolean
97
- isDisabled?: boolean
98
- allowCreate?: boolean
99
- isSearch?: boolean
100
- showChip?: boolean
101
- chipColor?: string
102
- height?: string
103
- borderColor?: string
104
- borderRadius?: string
105
- menuWidth?: string
106
- rules?: ((val: any) => boolean | string)[]
107
- }
108
-
109
- const props = defineProps<AppQSelectProps>()
110
- const emit = defineEmits(['update:modelValue', 'update:scroll', 'update:search', 'clear', 'create'])
111
-
112
- const select = ref({})
113
- const lcText: Ref<string> = ref('')
114
- const internalSearch = ref('')
115
-
116
- const selected = computed({
117
- get() {
118
- return props.modelValue
119
- },
120
- set(value) {
121
- emit('update:modelValue', value)
122
- },
123
- })
124
-
125
- function handleClear() {
126
- selected.value = props.multiple ? [] : null
127
- lcText.value = ''
128
- emit('update:modelValue', selected.value)
129
- emit('clear')
130
- }
131
-
132
- const filteredOptions = computed(() => {
133
- const labelKey = props.optionLabel || 'label'
134
-
135
- const baseOptions = props.options.filter(x => {
136
- const label = x[labelKey]
137
- return typeof label === 'string' && label.toLowerCase().includes(lcText.value)
138
- })
139
-
140
- if (props.loading) {
141
- return [
142
- ...baseOptions,
143
- {
144
- __loading: true,
145
- label: '__loading__',
146
- value: '__loading__',
147
- },
148
- ]
149
- }
150
-
151
- return baseOptions
152
- })
153
-
154
- function handleCreateFromSearch() {
155
- const labelKey = props.optionLabel || 'label'
156
- const valueKey = props.optionValue || 'value'
157
-
158
- const trimmed = internalSearch.value?.trim()
159
- if (!trimmed) return
160
-
161
- const newOption = {
162
- [labelKey]: trimmed,
163
- [valueKey]: trimmed,
164
- }
165
- emit('create', newOption)
166
- handleClear()
167
- }
168
-
169
- function filterFn(val: string, update: (cb: () => void) => void) {
170
- debouncedFilter(val, update)
171
- }
172
-
173
- const debouncedFilter = debounce((val: string, update: (cb: () => void) => void) => {
174
- internalSearch.value = val
175
- emit('update:search', val)
176
- update(() => {
177
- lcText.value = val.toLowerCase()
178
- })
179
- }, 500)
180
-
181
- function onScroll({ to, ref: qSelectRef }) {
182
- const totalOptions = qSelectRef.options.length
183
- if (to >= totalOptions - 1 && !lcText.value) {
184
- emit('update:scroll')
185
- }
186
- }
187
-
188
- function debounce<T>(fn: T, ms) {
189
- let timeoutId
190
- return function (...args) {
191
- clearTimeout(timeoutId)
192
- return new Promise(resolve => {
193
- timeoutId = setTimeout(() => {
194
- resolve(fn(...args))
195
- }, ms)
196
- })
197
- }
198
- }
199
- </script>
200
-
201
- <style lang="scss" scoped>
202
- .wrapper-empty-text {
203
- display: flex;
204
- align-items: center;
205
- justify-content: space-between;
206
- flex-direction: row;
207
- .add-new-items {
208
- background: #3f8cff;
209
- color: #fff;
210
- outline: none;
211
- border: none;
212
- border-radius: 4px;
213
- padding: 5px 10px;
214
- cursor: pointer;
215
- }
216
- }
217
- .field-label {
218
- font-size: 14px;
219
- font-weight: 700;
220
- color: #7d8592;
221
- }
222
- .required {
223
- color: #f65160;
224
- font-weight: bold;
225
- }
226
-
227
- ::v-deep(.q-placeholder) {
228
- color: #7d8592;
229
- }
230
- ::v-deep(.q-field__control) {
231
- border-radius: 8px;
232
- border: 1px solid #d8e0f0;
233
- background: #fff;
234
- box-shadow: 0px 1px 2px 0px rgba(184, 200, 224, 0.22);
235
- }
236
- ::v-deep(.q-field--filled.q-field--highlighted .q-field__control:before),
237
- ::v-deep(.q-field--filled .q-field__control:before) {
238
- background: #fff !important;
239
- border: none;
240
- }
241
- ::v-deep(.q-field--with-bottom) {
242
- padding-bottom: 0;
243
- }
244
- ::v-deep(.q-field__bottom) {
245
- padding: 0;
246
- }
247
- .clear-input {
248
- color: #d8e0f0;
249
- }
250
- ::v-deep(.q-chip) {
251
- border-radius: 4px;
252
- background: #e9eff9;
253
- color: #1d425d;
254
- font-family: NunitoSansFont, sans-serif;
255
- font-size: 14px;
256
- height: 30px;
257
- line-height: 30px;
258
- padding: 0 15px;
259
- .q-chip__icon {
260
- color: #3f8cff;
261
- margin-left: 5px;
262
- }
263
- }
264
- </style>
1
+ <template>
2
+ <label class="field-label">
3
+ {{ label }}
4
+ <span v-if="rules?.length && isShowRequired" class="required">*</span>
5
+ </label>
6
+
7
+ <q-select
8
+ ref="select"
9
+ v-model="selected"
10
+ :options="filteredOptions"
11
+ :disable="isDisabled"
12
+ :multiple="multiple"
13
+ :popup-content-class="'custom-select-menu'"
14
+ :hide-selected="!showChip"
15
+ :placeholder="placeholder"
16
+ :loading="loading"
17
+ :option-value="optionValue || 'value'"
18
+ :option-label="optionLabel || 'label'"
19
+ emit-value
20
+ filled
21
+ map-options
22
+ stack-label
23
+ use-input
24
+ use-chips
25
+ input-debounce="100"
26
+ autocomplete=""
27
+ :rules="rules"
28
+ @virtual-scroll="onScroll"
29
+ @filter="filterFn"
30
+ >
31
+ <template v-if="multiple || showChip" #selected-item="scope">
32
+ <q-chip
33
+ v-if="scope.opt"
34
+ removable
35
+ :tabindex="scope.tabindex"
36
+ :style="{ backgroundColor: chipColor }"
37
+ icon-remove="close"
38
+ text-color="secondary"
39
+ @remove="scope.removeAtIndex(scope.index)"
40
+ >
41
+ {{ scope.opt[optionLabel || 'label'] }}
42
+ </q-chip>
43
+ </template>
44
+
45
+ <template #append>
46
+ <q-icon
47
+ v-if="!isDisabled && selected && selected.length"
48
+ name="close"
49
+ class="cursor-pointer clear-input"
50
+ @click.stop="handleClear"
51
+ />
52
+ </template>
53
+
54
+ <template #no-option>
55
+ <div class="q-pa-sm">
56
+ <q-item>
57
+ <q-item-section class="wrapper-empty-text">
58
+ {{ emptyText }}
59
+ <button
60
+ v-if="allowCreate && internalSearch && internalSearch.trim()"
61
+ class="add-new-items"
62
+ @click="handleCreateFromSearch"
63
+ >
64
+ Добавить
65
+ </button>
66
+ </q-item-section>
67
+ </q-item>
68
+ </div>
69
+ </template>
70
+
71
+ <template #option="scope">
72
+ <q-item v-if="scope.opt.__loading" class="q-py-md q-ml-md">
73
+ <q-spinner-dots size="24px" color="primary" />
74
+ </q-item>
75
+ <q-item v-else v-bind="scope.itemProps">
76
+ <q-item-section>{{ scope.opt[optionLabel || 'label'] }}</q-item-section>
77
+ </q-item>
78
+ </template>
79
+ </q-select>
80
+ </template>
81
+
82
+ <script setup lang="ts">
83
+ import { computed, defineEmits, defineProps, ref, Ref } from 'vue'
84
+ type Option = Record<string, any>
85
+
86
+ interface AppQSelectProps {
87
+ modelValue: any
88
+ options: Option[]
89
+ placeholder: string | undefined
90
+ emptyText: string
91
+ optionLabel?: string
92
+ optionValue?: string
93
+ label?: string
94
+ multiple?: boolean
95
+ loading?: boolean
96
+ isShowRequired?: boolean
97
+ isDisabled?: boolean
98
+ allowCreate?: boolean
99
+ isSearch?: boolean
100
+ showChip?: boolean
101
+ chipColor?: string
102
+ height?: string
103
+ borderColor?: string
104
+ borderRadius?: string
105
+ menuWidth?: string
106
+ rules?: ((val: any) => boolean | string)[]
107
+ }
108
+
109
+ const props = defineProps<AppQSelectProps>()
110
+ const emit = defineEmits(['update:modelValue', 'update:scroll', 'update:search', 'clear', 'create'])
111
+
112
+ const select = ref({})
113
+ const lcText: Ref<string> = ref('')
114
+ const internalSearch = ref('')
115
+
116
+ const selected = computed({
117
+ get() {
118
+ return props.modelValue
119
+ },
120
+ set(value) {
121
+ emit('update:modelValue', value)
122
+ },
123
+ })
124
+
125
+ function handleClear() {
126
+ selected.value = props.multiple ? [] : null
127
+ lcText.value = ''
128
+ emit('update:modelValue', selected.value)
129
+ emit('clear')
130
+ }
131
+
132
+ const filteredOptions = computed(() => {
133
+ const labelKey = props.optionLabel || 'label'
134
+
135
+ const baseOptions = props.options.filter(x => {
136
+ const label = x[labelKey]
137
+ return typeof label === 'string' && label.toLowerCase().includes(lcText.value)
138
+ })
139
+
140
+ if (props.loading) {
141
+ return [
142
+ ...baseOptions,
143
+ {
144
+ __loading: true,
145
+ label: '__loading__',
146
+ value: '__loading__',
147
+ },
148
+ ]
149
+ }
150
+
151
+ return baseOptions
152
+ })
153
+
154
+ function handleCreateFromSearch() {
155
+ const labelKey = props.optionLabel || 'label'
156
+ const valueKey = props.optionValue || 'value'
157
+
158
+ const trimmed = internalSearch.value?.trim()
159
+ if (!trimmed) return
160
+
161
+ const newOption = {
162
+ [labelKey]: trimmed,
163
+ [valueKey]: trimmed,
164
+ }
165
+ emit('create', newOption)
166
+ handleClear()
167
+ }
168
+
169
+ function filterFn(val: string, update: (cb: () => void) => void) {
170
+ debouncedFilter(val, update)
171
+ }
172
+
173
+ const debouncedFilter = debounce((val: string, update: (cb: () => void) => void) => {
174
+ internalSearch.value = val
175
+ emit('update:search', val)
176
+ update(() => {
177
+ lcText.value = val.toLowerCase()
178
+ })
179
+ }, 500)
180
+
181
+ function onScroll({ to, ref: qSelectRef }) {
182
+ const totalOptions = qSelectRef.options.length
183
+ if (to >= totalOptions - 1 && !lcText.value) {
184
+ emit('update:scroll')
185
+ }
186
+ }
187
+
188
+ function debounce<T>(fn: T, ms) {
189
+ let timeoutId
190
+ return function (...args) {
191
+ clearTimeout(timeoutId)
192
+ return new Promise(resolve => {
193
+ timeoutId = setTimeout(() => {
194
+ resolve(fn(...args))
195
+ }, ms)
196
+ })
197
+ }
198
+ }
199
+ </script>
200
+
201
+ <style lang="scss" scoped>
202
+ .wrapper-empty-text {
203
+ display: flex;
204
+ align-items: center;
205
+ justify-content: space-between;
206
+ flex-direction: row;
207
+ .add-new-items {
208
+ background: #3f8cff;
209
+ color: #fff;
210
+ outline: none;
211
+ border: none;
212
+ border-radius: 4px;
213
+ padding: 5px 10px;
214
+ cursor: pointer;
215
+ }
216
+ }
217
+ .field-label {
218
+ font-size: 14px;
219
+ font-weight: 700;
220
+ color: #7d8592;
221
+ }
222
+ .required {
223
+ color: #f65160;
224
+ font-weight: bold;
225
+ }
226
+
227
+ ::v-deep(.q-placeholder) {
228
+ color: #7d8592;
229
+ }
230
+ ::v-deep(.q-field__control) {
231
+ border-radius: 8px;
232
+ border: 1px solid #d8e0f0;
233
+ background: #fff;
234
+ box-shadow: 0px 1px 2px 0px rgba(184, 200, 224, 0.22);
235
+ }
236
+ ::v-deep(.q-field--filled.q-field--highlighted .q-field__control:before),
237
+ ::v-deep(.q-field--filled .q-field__control:before) {
238
+ background: #fff !important;
239
+ border: none;
240
+ }
241
+ ::v-deep(.q-field--with-bottom) {
242
+ padding-bottom: 0;
243
+ }
244
+ ::v-deep(.q-field__bottom) {
245
+ padding: 0;
246
+ }
247
+ .clear-input {
248
+ color: #d8e0f0;
249
+ }
250
+ ::v-deep(.q-chip) {
251
+ border-radius: 4px;
252
+ background: #e9eff9;
253
+ color: #1d425d;
254
+ font-family: NunitoSansFont, sans-serif;
255
+ font-size: 14px;
256
+ height: 30px;
257
+ line-height: 30px;
258
+ padding: 0 15px;
259
+ .q-chip__icon {
260
+ color: #3f8cff;
261
+ margin-left: 5px;
262
+ }
263
+ }
264
+ </style>