quasar-ui-danx 0.0.10 → 0.0.12

Sign up to get free protection for your applications and to get access to all the features.
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>