quasar-ui-danx 0.0.10 → 0.0.12

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 (89) hide show
  1. package/package.json +8 -2
  2. package/src/components/ActionTable/ActionTable.vue +143 -0
  3. package/src/components/ActionTable/BatchActionMenu.vue +60 -0
  4. package/src/components/ActionTable/EmptyTableState.vue +33 -0
  5. package/src/components/ActionTable/Filters/CollapsableFiltersSidebar.vue +36 -0
  6. package/src/components/ActionTable/Filters/FilterGroupItem.vue +28 -0
  7. package/src/components/ActionTable/Filters/FilterGroupList.vue +76 -0
  8. package/src/components/ActionTable/Filters/FilterListToggle.vue +50 -0
  9. package/src/components/ActionTable/Filters/FilterableField.vue +143 -0
  10. package/src/components/ActionTable/Filters/index.ts +5 -0
  11. package/src/components/ActionTable/Form/Fields/BooleanField.vue +37 -0
  12. package/src/components/ActionTable/Form/Fields/ConfirmPasswordField.vue +46 -0
  13. package/src/components/ActionTable/Form/Fields/DateField.vue +59 -0
  14. package/src/components/ActionTable/Form/Fields/DateRangeField.vue +110 -0
  15. package/src/components/ActionTable/Form/Fields/DateTimeField.vue +50 -0
  16. package/src/components/ActionTable/Form/Fields/DateTimePicker.vue +59 -0
  17. package/src/components/ActionTable/Form/Fields/EditableDiv.vue +39 -0
  18. package/src/components/ActionTable/Form/Fields/FieldLabel.vue +32 -0
  19. package/src/components/ActionTable/Form/Fields/FileUploadButton.vue +78 -0
  20. package/src/components/ActionTable/Form/Fields/InlineDateTimeField.vue +44 -0
  21. package/src/components/ActionTable/Form/Fields/IntegerField.vue +26 -0
  22. package/src/components/ActionTable/Form/Fields/LabelValueBlock.vue +22 -0
  23. package/src/components/ActionTable/Form/Fields/LabeledInput.vue +63 -0
  24. package/src/components/ActionTable/Form/Fields/MultiFileField.vue +91 -0
  25. package/src/components/ActionTable/Form/Fields/MultiKeywordField.vue +57 -0
  26. package/src/components/ActionTable/Form/Fields/NewPasswordField.vue +39 -0
  27. package/src/components/ActionTable/Form/Fields/NumberField.vue +94 -0
  28. package/src/components/ActionTable/Form/Fields/NumberRangeField.vue +140 -0
  29. package/src/components/ActionTable/Form/Fields/SelectDrawer.vue +136 -0
  30. package/src/components/ActionTable/Form/Fields/SelectField.vue +318 -0
  31. package/src/components/ActionTable/Form/Fields/SelectWithChildrenField.vue +81 -0
  32. package/src/components/ActionTable/Form/Fields/SingleFileField.vue +78 -0
  33. package/src/components/ActionTable/Form/Fields/TextField.vue +82 -0
  34. package/src/components/ActionTable/Form/Fields/WysiwygField.vue +46 -0
  35. package/src/components/ActionTable/Form/Fields/index.ts +23 -0
  36. package/src/components/ActionTable/Form/RenderedForm.vue +76 -0
  37. package/src/components/ActionTable/Form/index.ts +2 -0
  38. package/src/components/ActionTable/RenderComponentColumn.vue +22 -0
  39. package/src/components/ActionTable/TableSummaryRow.vue +95 -0
  40. package/src/components/ActionTable/index.ts +10 -0
  41. package/src/components/ActionTable/listActions.ts +362 -0
  42. package/src/components/ActionTable/listHelpers.ts +74 -0
  43. package/src/components/ActionTable/tableColumns.ts +72 -0
  44. package/src/components/DragAndDrop/HandleDraggable.vue +29 -29
  45. package/src/components/DragAndDrop/ListItemDraggable.vue +10 -10
  46. package/src/components/DragAndDrop/index.ts +0 -1
  47. package/src/components/DragAndDrop/listDragAndDrop.ts +1 -1
  48. package/src/components/Utility/CollapsableSidebar.vue +119 -0
  49. package/src/components/Utility/ContentDrawer.vue +70 -0
  50. package/src/components/Utility/Dialogs/ConfirmDialog.vue +132 -0
  51. package/src/components/Utility/Dialogs/FullScreenDialog.vue +46 -0
  52. package/src/components/Utility/Dialogs/FullscreenCarouselDialog.vue +105 -0
  53. package/src/components/Utility/Dialogs/InfoDialog.vue +92 -0
  54. package/src/components/Utility/Dialogs/InputDialog.vue +35 -0
  55. package/src/components/Utility/ImagePreview.vue +192 -0
  56. package/src/components/Utility/Popover/PopoverMenu.vue +64 -0
  57. package/src/components/Utility/Transitions/ListTransition.vue +50 -0
  58. package/src/components/Utility/Transitions/SlideTransition.vue +63 -0
  59. package/src/components/Utility/Transitions/StaggeredListTransition.vue +97 -0
  60. package/src/components/Utility/index.ts +11 -0
  61. package/src/components/index.ts +3 -0
  62. package/src/helpers/FileUpload.ts +295 -0
  63. package/src/helpers/FlashMessages.ts +79 -0
  64. package/src/helpers/array.ts +37 -0
  65. package/src/helpers/compatibility.ts +64 -0
  66. package/src/helpers/date.ts +5 -0
  67. package/src/helpers/download.ts +200 -0
  68. package/src/helpers/downloadPdf.ts +92 -0
  69. package/src/helpers/files.ts +52 -0
  70. package/src/helpers/formats.ts +183 -0
  71. package/src/helpers/http.ts +62 -0
  72. package/src/helpers/index.ts +12 -1
  73. package/src/helpers/multiFileUpload.ts +68 -0
  74. package/src/helpers/singleFileUpload.ts +54 -0
  75. package/src/helpers/storage.ts +8 -0
  76. package/src/index.esm.js +3 -4
  77. package/src/svg/FilterIcon.svg +7 -0
  78. package/src/svg/ImageIcon.svg +30 -0
  79. package/src/svg/PdfIcon.svg +21 -0
  80. package/src/svg/PercentIcon.svg +13 -0
  81. package/src/svg/TrashIcon.svg +15 -0
  82. package/src/svg/XIcon.svg +18 -0
  83. package/src/svg/index.ts +8 -0
  84. package/src/vendor/tinymce-config.ts +1 -0
  85. package/src/vue-plugin.js +7 -4
  86. package/tsconfig.json +14 -13
  87. package/src/components/DragAndDrop/Icons/index.ts +0 -2
  88. /package/src/{components/DragAndDrop/Icons → svg}/DragHandleDotsIcon.svg +0 -0
  89. /package/src/{components/DragAndDrop/Icons → svg}/DragHandleIcon.svg +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quasar-ui-danx",
3
- "version": "0.0.10",
3
+ "version": "0.0.12",
4
4
  "author": "Dan <dan@flytedesk.com>",
5
5
  "description": "DanX Vue / Quasar component library",
6
6
  "license": "MIT",
@@ -62,6 +62,12 @@
62
62
  "last 4 iOS versions"
63
63
  ],
64
64
  "dependencies": {
65
- "@vueuse/core": "^10.7.2"
65
+ "@heroicons/vue": "v1",
66
+ "@tinymce/tinymce-vue": "^5.1.1",
67
+ "@vueuse/core": "^10.7.2",
68
+ "exifreader": "^4.21.1",
69
+ "gsap": "^3.12.5",
70
+ "luxon": "^3.4.4",
71
+ "tailwindcss": "^3.4.1"
66
72
  }
67
73
  }
@@ -0,0 +1,143 @@
1
+ <template>
2
+ <q-table
3
+ ref="actionTable"
4
+ :selected="selectedRows"
5
+ :pagination="quasarPagination"
6
+ :columns="columns"
7
+ :loading="isLoadingList"
8
+ :rows="pagedItems?.data || []"
9
+ selection="multiple"
10
+ :rows-per-page-options="rowsPerPageOptions"
11
+ class="sticky-column sticky-header w-full !border-0"
12
+ color="blue-base"
13
+ @update:selected="$emit('update:selected-rows', $event)"
14
+ @update:pagination="() => {}"
15
+ @request="$emit('update:quasar-pagination', $event.pagination)"
16
+ >
17
+ <template #no-data>
18
+ <slot name="empty">
19
+ <EmptyTableState :text="`There are no ${label.toLowerCase()} matching the applied filter`" />
20
+ </slot>
21
+ </template>
22
+ <template #top-row>
23
+ <TableSummaryRow
24
+ :label="label"
25
+ :item-count="summary?.count || 0"
26
+ :selected-count="selectedRows.length"
27
+ :loading="isLoadingSummary"
28
+ :summary="summary"
29
+ :columns="columns"
30
+ @clear="$emit('update:selected-rows', [])"
31
+ />
32
+ </template>
33
+ <template #header-cell="rowProps">
34
+ <q-th
35
+ :key="rowProps.key"
36
+ :props="rowProps"
37
+ :data-drop-zone="`resize-column-` + rowProps.col.name"
38
+ >
39
+ {{ rowProps.col.label }}
40
+ <HandleDraggable
41
+ v-if="rowProps.col.resizeable"
42
+ :drop-zone="`resize-column-` + rowProps.col.name"
43
+ class="resize-handle"
44
+ @resize="rowProps.col.onResize"
45
+ >
46
+ <RowResizeIcon class="w-4 text-neutral-base" />
47
+ </HandleDraggable>
48
+ </q-th>
49
+ </template>
50
+ <template #body-cell="rowProps">
51
+ <q-td :key="rowProps.key" :props="rowProps">
52
+ <template v-if="rowProps.col.component">
53
+ <RenderComponentColumn
54
+ :row-props="rowProps"
55
+ @action="$emit('action', $event)"
56
+ />
57
+ </template>
58
+ <template v-else-if="rowProps.col.fieldList">
59
+ <div v-for="field in rowProps.col.fieldList" :key="field">
60
+ {{ rowProps.row[field] }}
61
+ </div>
62
+ </template>
63
+ <template v-else-if="rowProps.col.filterOnClick">
64
+ <a @click="$emit('filter', rowProps.col.filterOnClick(rowProps.row))">
65
+ {{ rowProps.value }}
66
+ </a>
67
+ </template>
68
+ <template v-else>
69
+ <slot v-bind="{name: rowProps.col.name, row: rowProps.row, value: rowProps.value}">
70
+ {{ rowProps.value }}
71
+ </slot>
72
+ </template>
73
+ </q-td>
74
+ </template>
75
+ </q-table>
76
+ </template>
77
+
78
+ <script setup>
79
+ import {
80
+ EmptyTableState,
81
+ HandleDraggable,
82
+ registerStickyScrolling,
83
+ RenderComponentColumn,
84
+ TableSummaryRow
85
+ } from '@ui/components';
86
+ import { DragHandleIcon as RowResizeIcon } from '@ui/svg';
87
+ import { ref } from 'vue';
88
+
89
+ defineEmits(['action', 'filter', 'update:quasar-pagination', 'update:selected-rows']);
90
+ defineProps({
91
+ label: {
92
+ type: String,
93
+ required: true
94
+ },
95
+ selectedRows: {
96
+ type: Array,
97
+ required: true
98
+ },
99
+ quasarPagination: {
100
+ type: Object,
101
+ required: true
102
+ },
103
+ isLoadingList: Boolean,
104
+ pagedItems: {
105
+ type: Object,
106
+ default: null
107
+ },
108
+ isLoadingSummary: Boolean,
109
+ summary: {
110
+ type: Object,
111
+ default: null
112
+ },
113
+ columns: {
114
+ type: Array,
115
+ required: true
116
+ },
117
+ rowsPerPageOptions: {
118
+ type: Array,
119
+ default: () => [10, 25, 50, 100]
120
+ }
121
+ });
122
+ const actionTable = ref(null);
123
+ registerStickyScrolling(actionTable);
124
+ </script>
125
+
126
+ <style lang="scss" scoped>
127
+ [data-drop-zone] {
128
+ .resize-handle {
129
+ position: absolute;
130
+ top: 0;
131
+ right: -.45em;
132
+ width: .9em;
133
+ opacity: 0;
134
+ transition: all .3s;
135
+ }
136
+
137
+ &:hover {
138
+ .resize-handle {
139
+ opacity: 1;
140
+ }
141
+ }
142
+ }
143
+ </style>
@@ -0,0 +1,60 @@
1
+ <template>
2
+ <div>
3
+ <PopoverMenu
4
+ class="bg-neutral-plus-6 px-4 h-full flex"
5
+ :items="items"
6
+ :disabled="selectedRows.length === 0"
7
+ @action="onAction"
8
+ />
9
+ <q-tooltip v-if="selectedRows.length === 0">
10
+ Batch actions require a selection
11
+ </q-tooltip>
12
+ <slot>
13
+ <Component
14
+ :is="activeComponent.is"
15
+ v-if="activeComponent"
16
+ v-bind="activeComponent.props"
17
+ :is-saving="isSaving"
18
+ @close="activeAction = false"
19
+ @confirm="onConfirmAction"
20
+ />
21
+ </slot>
22
+ </div>
23
+ </template>
24
+ <script setup>
25
+ import PopoverMenu from '@ui/components/Utility/Popover/PopoverMenu';
26
+ import { computed, ref } from 'vue';
27
+
28
+ const emit = defineEmits(['action']);
29
+ const props = defineProps({
30
+ items: {
31
+ type: Array,
32
+ required: true
33
+ },
34
+ selectedRows: {
35
+ type: Array,
36
+ required: true
37
+ },
38
+ applyBatchAction: {
39
+ type: Function,
40
+ required: true
41
+ },
42
+ isSaving: Boolean
43
+ });
44
+
45
+
46
+ const activeAction = ref(null);
47
+ const activeComponent = computed(() => (props.items.find(i => i.action === activeAction.value)?.component || (() => null))(props.selectedRows));
48
+
49
+ function onAction(action) {
50
+ activeAction.value = action;
51
+ emit('action', action);
52
+ }
53
+ async function onConfirmAction(input) {
54
+ const result = await props.applyBatchAction(input || activeComponent.value.input());
55
+
56
+ if (result?.success) {
57
+ activeAction.value = null;
58
+ }
59
+ }
60
+ </script>
@@ -0,0 +1,33 @@
1
+ <template>
2
+ <div class="flex items-center justify-center text-sm py-14 w-full">
3
+ <div v-if="loading">
4
+ <slot name="loading">{{ loadingText }}
5
+ <q-spinner-ball class="w-4 ml-2" />
6
+ </slot>
7
+ </div>
8
+ <div v-if="saving">
9
+ <slot name="saving">{{ savingText }}
10
+ <q-spinner-ball class="w-4 ml-2" />
11
+ </slot>
12
+ </div>
13
+ <slot>{{ text }}</slot>
14
+ </div>
15
+ </template>
16
+ <script setup>
17
+ defineProps({
18
+ loading: Boolean,
19
+ saving: Boolean,
20
+ text: {
21
+ type: String,
22
+ default: 'No records found'
23
+ },
24
+ loadingText: {
25
+ type: String,
26
+ default: 'Loading...'
27
+ },
28
+ savingText: {
29
+ type: String,
30
+ default: 'Saving...'
31
+ }
32
+ });
33
+ </script>
@@ -0,0 +1,36 @@
1
+ <template>
2
+ <CollapsableSidebar
3
+ :collapse="!showFilters"
4
+ disabled
5
+ min-width="0"
6
+ max-width="18rem"
7
+ name="admin-ads"
8
+ @update:collapse="$emit('update:show-filters', !$event)"
9
+ >
10
+ <FilterGroupList
11
+ :filter="filter"
12
+ :filter-groups="filterGroups"
13
+ @update:filter="$emit('update:filter', $event)"
14
+ />
15
+ </CollapsableSidebar>
16
+ </template>
17
+ <script setup>
18
+ import { CollapsableSidebar, FilterGroupList } from '@ui/components';
19
+
20
+ defineEmits(['update:filter', 'update:show-filters']);
21
+ defineProps({
22
+ name: {
23
+ type: String,
24
+ required: true
25
+ },
26
+ showFilters: Boolean,
27
+ filter: {
28
+ type: Object,
29
+ default: null
30
+ },
31
+ filterGroups: {
32
+ type: Array,
33
+ default: () => []
34
+ }
35
+ });
36
+ </script>
@@ -0,0 +1,28 @@
1
+ <template>
2
+ <q-expansion-item>
3
+ <template #header>
4
+ <div class="flex items-center flex-nowrap flex-grow">
5
+ <div class="whitespace-nowrap flex-grow text-left text-sm font-bold">{{ name }}</div>
6
+ <q-badge
7
+ :label="count"
8
+ rounded
9
+ class="ml-2 transition-all"
10
+ :class="{'bg-gray-base': !count, 'bg-blue-base': count}"
11
+ />
12
+ </div>
13
+ </template>
14
+ <slot />
15
+ </q-expansion-item>
16
+ </template>
17
+ <script setup>
18
+ defineProps({
19
+ name: {
20
+ type: String,
21
+ required: true
22
+ },
23
+ count: {
24
+ type: Number,
25
+ required: true
26
+ }
27
+ });
28
+ </script>
@@ -0,0 +1,76 @@
1
+ <template>
2
+ <q-list>
3
+ <div class="px-4 py-2 max-w-full">
4
+ <template
5
+ v-for="(group, index) in filterGroups"
6
+ :key="'group-' + group.name"
7
+ >
8
+ <template v-if="group.flat">
9
+ <FilterableField
10
+ v-for="field in group.fields"
11
+ :key="'field-' + field.name"
12
+ :model-value="field.calcValue ? field.calcValue(filter) : filter[field.name]"
13
+ :field="field"
14
+ :loading="loading"
15
+ class="mb-4"
16
+ @update:model-value="updateFilter(field, $event)"
17
+ />
18
+ </template>
19
+
20
+ <FilterGroupItem
21
+ v-else
22
+ :name="group.name"
23
+ :count="activeCountByGroup[group.name]"
24
+ >
25
+ <FilterableField
26
+ v-for="field in group.fields"
27
+ :key="'field-' + field.name"
28
+ :model-value="field.calcValue ? field.calcValue(filter) : filter[field.name]"
29
+ :field="field"
30
+ :loading="loading"
31
+ class="mb-4"
32
+ @update:model-value="updateFilter(field, $event)"
33
+ />
34
+ </FilterGroupItem>
35
+
36
+ <q-separator
37
+ v-if="index < (filterGroups.length - 1)"
38
+ class="my-2"
39
+ />
40
+ </template>
41
+ </div>
42
+ </q-list>
43
+ </template>
44
+ <script setup>
45
+ import { computed } from 'vue';
46
+ import FilterableField from './FilterableField';
47
+ import FilterGroupItem from './FilterGroupItem';
48
+
49
+ const emit = defineEmits(['update:filter']);
50
+ const props = defineProps({
51
+ filterGroups: {
52
+ type: Array,
53
+ required: true
54
+ },
55
+ filter: {
56
+ type: Object,
57
+ required: true
58
+ },
59
+ loading: Boolean
60
+ });
61
+
62
+ const activeCountByGroup = computed(() => {
63
+ const activeCountByGroup = {};
64
+ for (const group of props.filterGroups) {
65
+ activeCountByGroup[group.name] = group.fields.filter(field => props.filter[field.name] !== undefined).length;
66
+ }
67
+ return activeCountByGroup;
68
+ });
69
+ function updateFilter(field, value) {
70
+ let fieldFilter = { [field.name]: value };
71
+ if (field.filterBy) {
72
+ fieldFilter = field.filterBy(value);
73
+ }
74
+ emit('update:filter', { ...props.filter, ...fieldFilter });
75
+ }
76
+ </script>
@@ -0,0 +1,50 @@
1
+ <template>
2
+ <div class="flex items-center" :class="{'w-72': showFilters}">
3
+ <div class="flex-grow">
4
+ <q-btn
5
+ class="btn-blue-highlight"
6
+ :class="{'highlighted': showFilters}"
7
+ @click="$emit('update:show-filters', !showFilters)"
8
+ >
9
+ <FilterIcon class="w-5 mr-2" />
10
+ <q-badge
11
+ :label="'' + activeCount"
12
+ rounded
13
+ :color="activeCount > 0 ? 'blue-base' : 'gray-base'"
14
+ />
15
+ </q-btn>
16
+ </div>
17
+ <a
18
+ v-if="activeCount > 0"
19
+ class="text-blue-base hover:text-blue-plus-1 text-sm ml-4"
20
+ @click="$emit('update:filter', {})"
21
+ >Clear All</a>
22
+ </div>
23
+ </template>
24
+ <script setup>
25
+ import { FilterIcon } from '@ui/svg';
26
+ import { computed } from 'vue';
27
+
28
+ defineEmits(['update:show-filters', 'update:filter']);
29
+ const props = defineProps({
30
+ filter: {
31
+ type: Object,
32
+ required: true
33
+ },
34
+ filterGroups: {
35
+ type: Array,
36
+ required: true
37
+ },
38
+ showFilters: Boolean
39
+ });
40
+
41
+ const filterNameDictionary = computed(() => {
42
+ return props.filterGroups.reduce((acc, fg) => {
43
+ fg.fields.forEach(f => {
44
+ acc[f.name] = true;
45
+ });
46
+ return acc;
47
+ }, {});
48
+ });
49
+ const activeCount = computed(() => Object.keys(props.filter).filter(key => props.filter[key] !== undefined && filterNameDictionary.value[key]).length);
50
+ </script>
@@ -0,0 +1,143 @@
1
+ <template>
2
+ <div>
3
+ <template v-if="field.type === 'multi-select'">
4
+ <SelectField
5
+ v-if="field.options?.length > 0 || loading"
6
+ :model-value="modelValue"
7
+ :options="field.options"
8
+ multiple
9
+ :loading="loading"
10
+ :chip-limit="1"
11
+ filterable
12
+ :placeholder="field.placeholder"
13
+ :label="field.label"
14
+ @update:model-value="onUpdate"
15
+ />
16
+ <div
17
+ v-else
18
+ class="mt-2"
19
+ >
20
+ <div class="text-xs font-bold">{{ field.label }}</div>
21
+ <div class="text-sm ml-3 py-2">No Available Options</div>
22
+ </div>
23
+ </template>
24
+
25
+ <SelectField
26
+ v-else-if="field.type === 'single-select'"
27
+ :model-value="modelValue"
28
+ :options="field.options"
29
+ :placeholder="field.placeholder"
30
+ :loading="loading"
31
+ :label="field.label"
32
+ @update:model-value="onUpdate"
33
+ />
34
+ <DateField
35
+ v-else-if="field.type === 'date'"
36
+ :model-value="modelValue"
37
+ :label="field.label"
38
+ class="mt-2"
39
+ @update:model-value="onUpdate"
40
+ />
41
+ <DateRangeField
42
+ v-else-if="field.type === 'date-range'"
43
+ :model-value="modelValue"
44
+ :label="field.label"
45
+ :inline="field.inline"
46
+ with-time
47
+ class="mt-2 reactive"
48
+ @update:model-value="onUpdate"
49
+ />
50
+ <NumberRangeField
51
+ v-else-if="field.type === 'number-range'"
52
+ :model-value="modelValue"
53
+ :label="field.label"
54
+ class="mt-2"
55
+ :debounce="1000"
56
+ @update:model-value="onUpdate"
57
+ />
58
+ <NumberRangeField
59
+ v-else-if="field.type === 'currency-range'"
60
+ :model-value="modelValue"
61
+ :label="field.label"
62
+ class="mt-2"
63
+ :debounce="1000"
64
+ currency
65
+ @update:model-value="onUpdate"
66
+ />
67
+ <NumberRangeField
68
+ v-else-if="field.type === 'percent-range'"
69
+ :model-value="modelValue"
70
+ :label="field.label"
71
+ class="mt-2"
72
+ :debounce="1000"
73
+ percent
74
+ @update:model-value="onUpdate"
75
+ />
76
+ <BooleanField
77
+ v-else-if="field.type === 'boolean'"
78
+ :field="field"
79
+ :model-value="modelValue"
80
+ class="mt-2"
81
+ label-class="text-xs font-bold"
82
+ @update:model-value="onUpdate"
83
+ />
84
+ <MultiKeywordField
85
+ v-else-if="field.type === 'multi-keywords'"
86
+ :model-value="modelValue"
87
+ :field="field"
88
+ @update:model-value="onUpdate"
89
+ />
90
+ <SelectWithChildrenField
91
+ v-else-if="field.type === 'select-with-children'"
92
+ :model-value="modelValue"
93
+ :options="field.options"
94
+ :loading="loading"
95
+ :label="field.label"
96
+ :placeholder="field.placeholder"
97
+ @update:model-value="onUpdate"
98
+ />
99
+ <template v-else>
100
+ Field &quot;{{ field.name }}&quot;: Unknown filter type {{ field.type }}
101
+ </template>
102
+ </div>
103
+ </template>
104
+ <script setup>
105
+ import {
106
+ BooleanField,
107
+ DateField,
108
+ DateRangeField,
109
+ MultiKeywordField,
110
+ NumberRangeField,
111
+ SelectField,
112
+ SelectWithChildrenField
113
+ } from '@ui/components';
114
+
115
+ const emit = defineEmits(['update:model-value']);
116
+ const props = defineProps({
117
+ field: {
118
+ type: Object,
119
+ required: true
120
+ },
121
+ modelValue: {
122
+ type: [String, Array, Number, Object, Boolean],
123
+ default: undefined
124
+ },
125
+ loading: Boolean
126
+ });
127
+
128
+ function onUpdate(val) {
129
+ let newVal = val || undefined;
130
+
131
+ switch (props.field.type) {
132
+ case 'multi-select':
133
+ newVal = val.length > 0 ? val : undefined;
134
+ break;
135
+ case 'single-select':
136
+ case 'boolean':
137
+ newVal = val === null ? undefined : val;
138
+ break;
139
+ }
140
+
141
+ emit('update:model-value', newVal);
142
+ }
143
+ </script>
@@ -0,0 +1,5 @@
1
+ export {
2
+ default as CollapsableFiltersSidebar
3
+ } from "./CollapsableFiltersSidebar.vue";
4
+ export { default as FilterGroupList } from "./FilterGroupList.vue";
5
+ export { default as FilterListToggle } from "./FilterListToggle.vue";
@@ -0,0 +1,37 @@
1
+ <template>
2
+ <q-toggle
3
+ :data-testid="'boolean-field-' + field.id"
4
+ :model-value="modelValue"
5
+ :toggle-indeterminate="toggleIndeterminate"
6
+ :indeterminate-value="undefined"
7
+ @update:model-value="$emit('update:model-value', $event)"
8
+ >
9
+ <FieldLabel
10
+ :field="field"
11
+ :show-name="showName"
12
+ :class="labelClass"
13
+ />
14
+ </q-toggle>
15
+ </template>
16
+
17
+ <script setup>
18
+ import FieldLabel from './FieldLabel';
19
+
20
+ defineEmits(['update:model-value']);
21
+ defineProps({
22
+ modelValue: {
23
+ type: [Boolean],
24
+ default: undefined
25
+ },
26
+ field: {
27
+ type: Object,
28
+ required: true
29
+ },
30
+ labelClass: {
31
+ type: String,
32
+ default: 'text-sm'
33
+ },
34
+ showName: Boolean,
35
+ toggleIndeterminate: Boolean
36
+ });
37
+ </script>
@@ -0,0 +1,46 @@
1
+ <template>
2
+ <LabeledInput
3
+ type="password"
4
+ v-bind="props"
5
+ :rules="rules"
6
+ @update:model-value="$emit('update:model-value', $event)"
7
+ />
8
+ </template>
9
+
10
+ <script setup>
11
+ import LabeledInput from './LabeledInput';
12
+
13
+ defineEmits(['update:model-value']);
14
+ const props = defineProps({
15
+ name: {
16
+ type: String,
17
+ default: 'password_confirmation'
18
+ },
19
+ label: {
20
+ type: String,
21
+ default: 'Confirm Password'
22
+ },
23
+ placeholder: {
24
+ type: String,
25
+ default: 'Confirm Password'
26
+ },
27
+ modelValue: {
28
+ type: [String, Number],
29
+ required: true
30
+ },
31
+ error: {
32
+ type: String,
33
+ default: null
34
+ },
35
+ password: {
36
+ type: String,
37
+ default: ''
38
+ },
39
+ disabled: Boolean
40
+ });
41
+
42
+ const rules = [
43
+ (val) =>
44
+ val === props.password || 'The password and confirmation do not match'
45
+ ];
46
+ </script>