@jskit-ai/http-web 0.1.92 → 0.1.93
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 +6 -6
- package/patterns/crud-screen-set/PATTERN.md +11 -1
- package/src/client/bulkActions.js +13 -40
- package/src/client/components/CrudAddEditScreen.vue +1 -9
- package/src/client/components/CrudListBulkActionSurface.vue +2 -5
- package/src/client/components/CrudListFilterControls.vue +175 -0
- package/src/client/components/CrudListFilterSurface.vue +5 -248
- package/src/client/components/CrudListScreen.vue +1 -28
- package/src/client/components/CrudViewScreen.vue +1 -9
- package/src/client/composables/crud/crudJsonApiTransportSupport.js +20 -42
- package/src/client/composables/crud/crudLookupFieldLabelSupport.js +2 -13
- package/src/client/composables/crud/crudLookupFieldRuntime.js +2 -27
- package/src/client/composables/crud/crudSchemaFormHelpers.js +1 -7
- package/src/client/composables/internal/crudListFilterLookupSupport.js +2 -1
- package/src/client/composables/internal/useOperationScope.js +5 -7
- package/src/client/composables/records/useAddEdit.js +12 -11
- package/src/client/composables/records/useCrudAddEdit.js +74 -22
- package/src/client/composables/records/useCrudList.js +0 -6
- package/src/client/composables/records/useCrudView.js +0 -6
- package/src/client/composables/records/useList.js +2 -8
- package/src/client/composables/records/useView.js +3 -8
- package/src/client/composables/runtime/addEditUiRuntime.js +12 -60
- package/src/client/composables/runtime/listUiRuntime.js +11 -36
- package/src/client/composables/runtime/useFieldErrorBag.js +3 -3
- package/src/client/composables/runtime/viewUiRuntime.js +14 -62
- package/src/client/composables/support/errorMessageHelpers.js +6 -48
- package/src/client/composables/support/resourceLoadStateHelpers.js +67 -156
- package/src/client/composables/support/routeTemplateHelpers.js +57 -0
- package/src/client/composables/useAccess.js +12 -17
- package/src/client/composables/useCommand.js +0 -1
- package/src/client/composables/useCrudDeleteAction.js +7 -5
- package/src/client/composables/useCrudListBulkActions.js +9 -21
- package/src/client/composables/useCrudListFilterLookups.js +1 -3
- package/src/client/composables/useCrudListParentTitle.js +0 -2
- package/src/client/composables/useCrudListRowActions.js +8 -24
- package/src/client/composables/useCrudListScreen.js +4 -5
- package/src/client/composables/useCrudViewScreen.js +2 -3
- package/src/client/composables/useRealtimeQueryInvalidation.js +3 -10
- package/src/client/composables/useScopeRuntime.js +2 -5
- package/src/client/rowActions.js +13 -40
- package/src/client/support/crudListActionSupport.js +54 -0
- package/test/crudAddEditActions.test.js +59 -19
- package/test/crudListFilterSurface.test.js +7 -4
- package/test/listUiRuntime.test.js +3 -1
- package/test/requestTransportOptions.test.js +24 -0
- package/test/resourceLoadStateHelpers.test.js +32 -0
- package/test/useAccess.test.js +62 -0
- package/test/useCrudDeleteAction.test.js +57 -2
- package/test/useCrudListScreen.test.js +45 -0
- package/test/useListRouteInitialization.test.js +5 -44
- package/src/client/composables/runtime/operationAdapters.js +0 -34
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jskit-ai/http-web",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.93",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "node --test --test-concurrency=1"
|
|
@@ -44,14 +44,14 @@
|
|
|
44
44
|
"./client/support/contractGuards": "./src/client/support/contractGuards.js"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@jskit-ai/resource-crud-core": "0.1.
|
|
47
|
+
"@jskit-ai/resource-crud-core": "0.1.188",
|
|
48
48
|
"@mdi/js": "^7.4.47"
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
|
-
"@jskit-ai/http-runtime": "0.1.
|
|
52
|
-
"@jskit-ai/kernel": "0.1.
|
|
53
|
-
"@jskit-ai/realtime": "0.1.
|
|
54
|
-
"@jskit-ai/shell-web": "0.1.
|
|
51
|
+
"@jskit-ai/http-runtime": "0.1.244",
|
|
52
|
+
"@jskit-ai/kernel": "0.1.246",
|
|
53
|
+
"@jskit-ai/realtime": "0.1.245",
|
|
54
|
+
"@jskit-ai/shell-web": "0.1.252",
|
|
55
55
|
"@tanstack/vue-query": "^5.90.5",
|
|
56
56
|
"vue": "^3.5.13",
|
|
57
57
|
"vue-router": "^5.0.4",
|
|
@@ -76,9 +76,19 @@ id (or a distinct new-record marker) so form cache entries stay separate.
|
|
|
76
76
|
The New/Edit examples supply it; list/view screen wrappers derive their
|
|
77
77
|
standard keys from `resourceNamespace`.
|
|
78
78
|
|
|
79
|
+
Each form fact has one input. `resource`, `input`, `buildPayload`,
|
|
80
|
+
`mapPayloadToModel` and `createModel` are top-level `useCrudAddEditScreen()`
|
|
81
|
+
options; `addEditOptions` carries only request and route options for
|
|
82
|
+
`useAddEdit()` (such as `apiSuffix`, `queryKeyFactory`, `readEnabled`,
|
|
83
|
+
`writeMethod`, URL templates, permissions, `client`, `transport` and
|
|
84
|
+
`onSaveSuccess`) and rejects anything else. The save-error message is
|
|
85
|
+
`addEditOptions.fallbackSaveError` when given, otherwise the resource's
|
|
86
|
+
`messages.saveError`; the request error and its toast use the same string.
|
|
87
|
+
|
|
79
88
|
Save navigation is configured in the top-level `saveSuccess` object. The default
|
|
80
89
|
prefers a configured record-view URL, then the list. A create-and-list variation
|
|
81
|
-
sets `navigateToView: false` and `listUrlTemplate` to its list
|
|
90
|
+
sets `navigateToView: false` and `saveSuccess.listUrlTemplate` to its list
|
|
91
|
+
route; `addEditOptions.listUrlTemplate` does not drive save navigation. Set both
|
|
82
92
|
`navigateToView` and `navigateToList` to `false` to stay on the form. A custom
|
|
83
93
|
`addEditOptions.onSaveSuccess` replaces default invalidation and navigation;
|
|
84
94
|
it is unnecessary for ordinary list navigation. The generic CRUD guide explains
|
|
@@ -1,47 +1,20 @@
|
|
|
1
1
|
import { normalizeText } from "@jskit-ai/kernel/shared/support/normalize";
|
|
2
|
-
|
|
3
|
-
function normalizeCrudListBulkAction(rawAction = {}, index = 0) {
|
|
4
|
-
if (!rawAction || typeof rawAction !== "object" || Array.isArray(rawAction)) {
|
|
5
|
-
return null;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
const key = normalizeText(rawAction.key || rawAction.id || `action-${index + 1}`);
|
|
9
|
-
const label = normalizeText(rawAction.label || rawAction.title);
|
|
10
|
-
if (!key || !label) {
|
|
11
|
-
return null;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
return Object.freeze({
|
|
15
|
-
key,
|
|
16
|
-
label,
|
|
17
|
-
icon: normalizeText(rawAction.icon),
|
|
18
|
-
color: normalizeText(rawAction.color, { fallback: "primary" }),
|
|
19
|
-
variant: normalizeText(rawAction.variant, { fallback: "tonal" }),
|
|
20
|
-
confirmLabel: normalizeText(rawAction.confirmLabel),
|
|
21
|
-
run: typeof rawAction.run === "function" ? rawAction.run : null,
|
|
22
|
-
disabled: rawAction.disabled
|
|
23
|
-
});
|
|
24
|
-
}
|
|
2
|
+
import { defineCrudListActions } from "./support/crudListActionSupport.js";
|
|
25
3
|
|
|
26
4
|
function defineCrudListBulkActions(actions = []) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
seenKeys.add(action.key);
|
|
41
|
-
normalizedActions.push(action);
|
|
5
|
+
return defineCrudListActions(actions, {
|
|
6
|
+
name: "defineCrudListBulkActions",
|
|
7
|
+
createAction: (rawAction, { key, label }) => ({
|
|
8
|
+
key,
|
|
9
|
+
label,
|
|
10
|
+
icon: normalizeText(rawAction.icon),
|
|
11
|
+
color: normalizeText(rawAction.color, { fallback: "primary" }),
|
|
12
|
+
variant: normalizeText(rawAction.variant, { fallback: "tonal" }),
|
|
13
|
+
confirmLabel: normalizeText(rawAction.confirmLabel),
|
|
14
|
+
run: typeof rawAction.run === "function" ? rawAction.run : null,
|
|
15
|
+
disabled: rawAction.disabled
|
|
16
|
+
})
|
|
42
17
|
});
|
|
43
|
-
|
|
44
|
-
return Object.freeze(normalizedActions);
|
|
45
18
|
}
|
|
46
19
|
|
|
47
20
|
export { defineCrudListBulkActions };
|
|
@@ -116,14 +116,6 @@ function resolveCancelTo(target = cancelTo.value) {
|
|
|
116
116
|
</template>
|
|
117
117
|
|
|
118
118
|
<style scoped>
|
|
119
|
-
.crud-screen {
|
|
120
|
-
--crud-screen-state-padding: 2.5rem 1.25rem;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
.crud-screen--operator {
|
|
124
|
-
--crud-screen-state-padding: 2rem 1rem;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
119
|
.crud-add-edit-form__actions {
|
|
128
120
|
display: flex;
|
|
129
121
|
flex-wrap: wrap;
|
|
@@ -138,7 +130,7 @@ function resolveCancelTo(target = cancelTo.value) {
|
|
|
138
130
|
.crud-add-edit-form__state {
|
|
139
131
|
margin-inline: auto;
|
|
140
132
|
max-width: 30rem;
|
|
141
|
-
padding:
|
|
133
|
+
padding: 2rem 1rem;
|
|
142
134
|
text-align: center;
|
|
143
135
|
}
|
|
144
136
|
|
|
@@ -13,11 +13,8 @@ const props = defineProps({
|
|
|
13
13
|
}
|
|
14
14
|
});
|
|
15
15
|
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
const displayName = String(display?.name?.value || "").trim().toLowerCase();
|
|
19
|
-
return displayName === "xs" || displayName === "sm";
|
|
20
|
-
});
|
|
16
|
+
const { smAndDown: isCompactLayout } = useDisplay();
|
|
17
|
+
|
|
21
18
|
const actions = computed(() => Array.isArray(props.runtime?.actions) ? props.runtime.actions : []);
|
|
22
19
|
const selectedCount = computed(() => Number(props.runtime?.selectedCount?.value || 0));
|
|
23
20
|
const shouldRender = computed(() =>
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed } from "vue";
|
|
3
|
+
import CrudListDateFilterControl from "./CrudListDateFilterControl.vue";
|
|
4
|
+
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
filters: {
|
|
7
|
+
type: Array,
|
|
8
|
+
default: () => []
|
|
9
|
+
},
|
|
10
|
+
runtime: {
|
|
11
|
+
type: Object,
|
|
12
|
+
default: null
|
|
13
|
+
},
|
|
14
|
+
stacked: {
|
|
15
|
+
type: Boolean,
|
|
16
|
+
default: false
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const runtimeValues = computed(() => props.runtime?.values || {});
|
|
21
|
+
|
|
22
|
+
function optionItems(filter = {}) {
|
|
23
|
+
return Array.isArray(filter.options) ? filter.options : [];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function placeholder(filter = {}, fallback = "") {
|
|
27
|
+
return String(filter?.ui?.placeholder || fallback || "").trim();
|
|
28
|
+
}
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<template>
|
|
32
|
+
<div
|
|
33
|
+
class="crud-list-filter-surface__controls"
|
|
34
|
+
:class="{ 'crud-list-filter-surface__controls--stacked': stacked }"
|
|
35
|
+
>
|
|
36
|
+
<template v-for="filter in filters" :key="filter.key">
|
|
37
|
+
<v-switch
|
|
38
|
+
v-if="filter.type === 'flag'"
|
|
39
|
+
v-model="runtimeValues[filter.key]"
|
|
40
|
+
:label="filter.label"
|
|
41
|
+
color="primary"
|
|
42
|
+
density="comfortable"
|
|
43
|
+
hide-details
|
|
44
|
+
class="crud-list-filter-surface__control"
|
|
45
|
+
/>
|
|
46
|
+
<v-select
|
|
47
|
+
v-else-if="filter.type === 'enum' || filter.type === 'enumMany' || filter.type === 'presence'"
|
|
48
|
+
v-model="runtimeValues[filter.key]"
|
|
49
|
+
:items="optionItems(filter)"
|
|
50
|
+
:label="filter.label"
|
|
51
|
+
:placeholder="placeholder(filter)"
|
|
52
|
+
:multiple="filter.type === 'enumMany'"
|
|
53
|
+
:chips="filter.type === 'enumMany'"
|
|
54
|
+
:closable-chips="filter.type === 'enumMany'"
|
|
55
|
+
clearable
|
|
56
|
+
item-title="label"
|
|
57
|
+
item-value="value"
|
|
58
|
+
variant="outlined"
|
|
59
|
+
density="comfortable"
|
|
60
|
+
hide-details="auto"
|
|
61
|
+
class="crud-list-filter-surface__control"
|
|
62
|
+
/>
|
|
63
|
+
<v-combobox
|
|
64
|
+
v-else-if="filter.type === 'recordIdMany'"
|
|
65
|
+
v-model="runtimeValues[filter.key]"
|
|
66
|
+
:label="filter.label"
|
|
67
|
+
:placeholder="placeholder(filter, 'Enter ids')"
|
|
68
|
+
multiple
|
|
69
|
+
chips
|
|
70
|
+
closable-chips
|
|
71
|
+
clearable
|
|
72
|
+
variant="outlined"
|
|
73
|
+
density="comfortable"
|
|
74
|
+
hide-details="auto"
|
|
75
|
+
class="crud-list-filter-surface__control"
|
|
76
|
+
/>
|
|
77
|
+
<v-text-field
|
|
78
|
+
v-else-if="filter.type === 'recordId'"
|
|
79
|
+
v-model="runtimeValues[filter.key]"
|
|
80
|
+
:label="filter.label"
|
|
81
|
+
:placeholder="placeholder(filter, 'Enter id')"
|
|
82
|
+
clearable
|
|
83
|
+
variant="outlined"
|
|
84
|
+
density="comfortable"
|
|
85
|
+
hide-details="auto"
|
|
86
|
+
class="crud-list-filter-surface__control"
|
|
87
|
+
/>
|
|
88
|
+
<div
|
|
89
|
+
v-else-if="filter.type === 'dateRange'"
|
|
90
|
+
class="crud-list-filter-surface__range crud-list-filter-surface__range--date"
|
|
91
|
+
role="group"
|
|
92
|
+
:aria-label="`${filter.label} date range`"
|
|
93
|
+
:data-filter-key="filter.key"
|
|
94
|
+
data-filter-type="date-range"
|
|
95
|
+
>
|
|
96
|
+
<CrudListDateFilterControl
|
|
97
|
+
v-model="runtimeValues[filter.key].from"
|
|
98
|
+
:label="`${filter.label} from`"
|
|
99
|
+
:control-id="`${filter.key}-from`"
|
|
100
|
+
:placeholder="placeholder(filter, 'Select start date')"
|
|
101
|
+
/>
|
|
102
|
+
<CrudListDateFilterControl
|
|
103
|
+
v-model="runtimeValues[filter.key].to"
|
|
104
|
+
:label="`${filter.label} to`"
|
|
105
|
+
:control-id="`${filter.key}-to`"
|
|
106
|
+
:placeholder="placeholder(filter, 'Select end date')"
|
|
107
|
+
/>
|
|
108
|
+
</div>
|
|
109
|
+
<div v-else-if="filter.type === 'numberRange'" class="crud-list-filter-surface__range">
|
|
110
|
+
<v-text-field
|
|
111
|
+
v-model="runtimeValues[filter.key].min"
|
|
112
|
+
:label="`${filter.label} min`"
|
|
113
|
+
type="number"
|
|
114
|
+
variant="outlined"
|
|
115
|
+
density="comfortable"
|
|
116
|
+
hide-details="auto"
|
|
117
|
+
/>
|
|
118
|
+
<v-text-field
|
|
119
|
+
v-model="runtimeValues[filter.key].max"
|
|
120
|
+
:label="`${filter.label} max`"
|
|
121
|
+
type="number"
|
|
122
|
+
variant="outlined"
|
|
123
|
+
density="comfortable"
|
|
124
|
+
hide-details="auto"
|
|
125
|
+
/>
|
|
126
|
+
</div>
|
|
127
|
+
<CrudListDateFilterControl
|
|
128
|
+
v-else-if="filter.type === 'date'"
|
|
129
|
+
v-model="runtimeValues[filter.key]"
|
|
130
|
+
:label="filter.label"
|
|
131
|
+
:control-id="filter.key"
|
|
132
|
+
:placeholder="placeholder(filter, 'Select date')"
|
|
133
|
+
class="crud-list-filter-surface__control"
|
|
134
|
+
/>
|
|
135
|
+
</template>
|
|
136
|
+
</div>
|
|
137
|
+
</template>
|
|
138
|
+
|
|
139
|
+
<style scoped>
|
|
140
|
+
.crud-list-filter-surface__controls {
|
|
141
|
+
display: grid;
|
|
142
|
+
gap: 0.75rem;
|
|
143
|
+
grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.crud-list-filter-surface__controls--stacked {
|
|
147
|
+
grid-template-columns: 1fr;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.crud-list-filter-surface__control {
|
|
151
|
+
min-width: 0;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.crud-list-filter-surface__range {
|
|
155
|
+
display: grid;
|
|
156
|
+
gap: 0.75rem;
|
|
157
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
158
|
+
min-width: 0;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.crud-list-filter-surface__range--date {
|
|
162
|
+
grid-column: span 2;
|
|
163
|
+
grid-template-columns: repeat(2, minmax(14rem, 1fr));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.crud-list-filter-surface__controls--stacked .crud-list-filter-surface__range--date {
|
|
167
|
+
grid-column: auto;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
@media (max-width: 640px) {
|
|
171
|
+
.crud-list-filter-surface__range {
|
|
172
|
+
grid-template-columns: 1fr;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
</style>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { computed, ref } from "vue";
|
|
3
3
|
import { useDisplay } from "vuetify";
|
|
4
|
-
import
|
|
4
|
+
import CrudListFilterControls from "./CrudListFilterControls.vue";
|
|
5
5
|
|
|
6
6
|
const props = defineProps({
|
|
7
7
|
filters: {
|
|
@@ -18,7 +18,8 @@ const props = defineProps({
|
|
|
18
18
|
}
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
const
|
|
21
|
+
const { smAndDown: isCompactLayout } = useDisplay();
|
|
22
|
+
|
|
22
23
|
const sheetOpen = ref(false);
|
|
23
24
|
|
|
24
25
|
const filterEntries = computed(() =>
|
|
@@ -27,22 +28,9 @@ const filterEntries = computed(() =>
|
|
|
27
28
|
: {})
|
|
28
29
|
.filter((filter) => filter?.key && filter?.type)
|
|
29
30
|
);
|
|
30
|
-
const runtimeValues = computed(() => props.runtime?.values || {});
|
|
31
31
|
const activeChips = computed(() => Array.isArray(props.runtime?.activeChips?.value) ? props.runtime.activeChips.value : []);
|
|
32
32
|
const hasActiveFilters = computed(() => Boolean(props.runtime?.hasActiveFilters?.value));
|
|
33
33
|
const shouldRender = computed(() => filterEntries.value.length > 0 && Boolean(props.runtime?.values));
|
|
34
|
-
const isCompactLayout = computed(() => {
|
|
35
|
-
const displayName = String(display?.name?.value || "").trim().toLowerCase();
|
|
36
|
-
return displayName === "xs" || displayName === "sm";
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
function optionItems(filter = {}) {
|
|
40
|
-
return Array.isArray(filter.options) ? filter.options : [];
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function placeholder(filter = {}, fallback = "") {
|
|
44
|
-
return String(filter?.ui?.placeholder || fallback || "").trim();
|
|
45
|
-
}
|
|
46
34
|
|
|
47
35
|
function clearChip(chip = {}) {
|
|
48
36
|
props.runtime?.clearChip?.(chip);
|
|
@@ -85,108 +73,7 @@ function clearFilters() {
|
|
|
85
73
|
</div>
|
|
86
74
|
|
|
87
75
|
<v-sheet v-if="!isCompactLayout" rounded="lg" border class="crud-list-filter-surface__panel">
|
|
88
|
-
<
|
|
89
|
-
<template v-for="filter in filterEntries" :key="filter.key">
|
|
90
|
-
<v-switch
|
|
91
|
-
v-if="filter.type === 'flag'"
|
|
92
|
-
v-model="runtimeValues[filter.key]"
|
|
93
|
-
:label="filter.label"
|
|
94
|
-
color="primary"
|
|
95
|
-
density="comfortable"
|
|
96
|
-
hide-details
|
|
97
|
-
class="crud-list-filter-surface__control"
|
|
98
|
-
/>
|
|
99
|
-
<v-select
|
|
100
|
-
v-else-if="filter.type === 'enum' || filter.type === 'enumMany' || filter.type === 'presence'"
|
|
101
|
-
v-model="runtimeValues[filter.key]"
|
|
102
|
-
:items="optionItems(filter)"
|
|
103
|
-
:label="filter.label"
|
|
104
|
-
:placeholder="placeholder(filter)"
|
|
105
|
-
:multiple="filter.type === 'enumMany'"
|
|
106
|
-
:chips="filter.type === 'enumMany'"
|
|
107
|
-
:closable-chips="filter.type === 'enumMany'"
|
|
108
|
-
clearable
|
|
109
|
-
item-title="label"
|
|
110
|
-
item-value="value"
|
|
111
|
-
variant="outlined"
|
|
112
|
-
density="comfortable"
|
|
113
|
-
hide-details="auto"
|
|
114
|
-
class="crud-list-filter-surface__control"
|
|
115
|
-
/>
|
|
116
|
-
<v-combobox
|
|
117
|
-
v-else-if="filter.type === 'recordIdMany'"
|
|
118
|
-
v-model="runtimeValues[filter.key]"
|
|
119
|
-
:label="filter.label"
|
|
120
|
-
:placeholder="placeholder(filter, 'Enter ids')"
|
|
121
|
-
multiple
|
|
122
|
-
chips
|
|
123
|
-
closable-chips
|
|
124
|
-
clearable
|
|
125
|
-
variant="outlined"
|
|
126
|
-
density="comfortable"
|
|
127
|
-
hide-details="auto"
|
|
128
|
-
class="crud-list-filter-surface__control"
|
|
129
|
-
/>
|
|
130
|
-
<v-text-field
|
|
131
|
-
v-else-if="filter.type === 'recordId'"
|
|
132
|
-
v-model="runtimeValues[filter.key]"
|
|
133
|
-
:label="filter.label"
|
|
134
|
-
:placeholder="placeholder(filter, 'Enter id')"
|
|
135
|
-
clearable
|
|
136
|
-
variant="outlined"
|
|
137
|
-
density="comfortable"
|
|
138
|
-
hide-details="auto"
|
|
139
|
-
class="crud-list-filter-surface__control"
|
|
140
|
-
/>
|
|
141
|
-
<div
|
|
142
|
-
v-else-if="filter.type === 'dateRange'"
|
|
143
|
-
class="crud-list-filter-surface__range crud-list-filter-surface__range--date"
|
|
144
|
-
role="group"
|
|
145
|
-
:aria-label="`${filter.label} date range`"
|
|
146
|
-
:data-filter-key="filter.key"
|
|
147
|
-
data-filter-type="date-range"
|
|
148
|
-
>
|
|
149
|
-
<CrudListDateFilterControl
|
|
150
|
-
v-model="runtimeValues[filter.key].from"
|
|
151
|
-
:label="`${filter.label} from`"
|
|
152
|
-
:control-id="`${filter.key}-from`"
|
|
153
|
-
:placeholder="placeholder(filter, 'Select start date')"
|
|
154
|
-
/>
|
|
155
|
-
<CrudListDateFilterControl
|
|
156
|
-
v-model="runtimeValues[filter.key].to"
|
|
157
|
-
:label="`${filter.label} to`"
|
|
158
|
-
:control-id="`${filter.key}-to`"
|
|
159
|
-
:placeholder="placeholder(filter, 'Select end date')"
|
|
160
|
-
/>
|
|
161
|
-
</div>
|
|
162
|
-
<div v-else-if="filter.type === 'numberRange'" class="crud-list-filter-surface__range">
|
|
163
|
-
<v-text-field
|
|
164
|
-
v-model="runtimeValues[filter.key].min"
|
|
165
|
-
:label="`${filter.label} min`"
|
|
166
|
-
type="number"
|
|
167
|
-
variant="outlined"
|
|
168
|
-
density="comfortable"
|
|
169
|
-
hide-details="auto"
|
|
170
|
-
/>
|
|
171
|
-
<v-text-field
|
|
172
|
-
v-model="runtimeValues[filter.key].max"
|
|
173
|
-
:label="`${filter.label} max`"
|
|
174
|
-
type="number"
|
|
175
|
-
variant="outlined"
|
|
176
|
-
density="comfortable"
|
|
177
|
-
hide-details="auto"
|
|
178
|
-
/>
|
|
179
|
-
</div>
|
|
180
|
-
<CrudListDateFilterControl
|
|
181
|
-
v-else-if="filter.type === 'date'"
|
|
182
|
-
v-model="runtimeValues[filter.key]"
|
|
183
|
-
:label="filter.label"
|
|
184
|
-
:control-id="filter.key"
|
|
185
|
-
:placeholder="placeholder(filter, 'Select date')"
|
|
186
|
-
class="crud-list-filter-surface__control"
|
|
187
|
-
/>
|
|
188
|
-
</template>
|
|
189
|
-
</div>
|
|
76
|
+
<CrudListFilterControls :filters="filterEntries" :runtime="runtime" />
|
|
190
77
|
</v-sheet>
|
|
191
78
|
|
|
192
79
|
<v-dialog v-model="sheetOpen" max-width="640" location="bottom">
|
|
@@ -196,103 +83,7 @@ function clearFilters() {
|
|
|
196
83
|
<v-btn variant="text" @click="sheetOpen = false">Close</v-btn>
|
|
197
84
|
</v-card-title>
|
|
198
85
|
<v-card-text>
|
|
199
|
-
<
|
|
200
|
-
<template v-for="filter in filterEntries" :key="filter.key">
|
|
201
|
-
<v-switch
|
|
202
|
-
v-if="filter.type === 'flag'"
|
|
203
|
-
v-model="runtimeValues[filter.key]"
|
|
204
|
-
:label="filter.label"
|
|
205
|
-
color="primary"
|
|
206
|
-
density="comfortable"
|
|
207
|
-
hide-details
|
|
208
|
-
/>
|
|
209
|
-
<v-select
|
|
210
|
-
v-else-if="filter.type === 'enum' || filter.type === 'enumMany' || filter.type === 'presence'"
|
|
211
|
-
v-model="runtimeValues[filter.key]"
|
|
212
|
-
:items="optionItems(filter)"
|
|
213
|
-
:label="filter.label"
|
|
214
|
-
:placeholder="placeholder(filter)"
|
|
215
|
-
:multiple="filter.type === 'enumMany'"
|
|
216
|
-
:chips="filter.type === 'enumMany'"
|
|
217
|
-
:closable-chips="filter.type === 'enumMany'"
|
|
218
|
-
clearable
|
|
219
|
-
item-title="label"
|
|
220
|
-
item-value="value"
|
|
221
|
-
variant="outlined"
|
|
222
|
-
density="comfortable"
|
|
223
|
-
hide-details="auto"
|
|
224
|
-
/>
|
|
225
|
-
<v-combobox
|
|
226
|
-
v-else-if="filter.type === 'recordIdMany'"
|
|
227
|
-
v-model="runtimeValues[filter.key]"
|
|
228
|
-
:label="filter.label"
|
|
229
|
-
:placeholder="placeholder(filter, 'Enter ids')"
|
|
230
|
-
multiple
|
|
231
|
-
chips
|
|
232
|
-
closable-chips
|
|
233
|
-
clearable
|
|
234
|
-
variant="outlined"
|
|
235
|
-
density="comfortable"
|
|
236
|
-
hide-details="auto"
|
|
237
|
-
/>
|
|
238
|
-
<v-text-field
|
|
239
|
-
v-else-if="filter.type === 'recordId'"
|
|
240
|
-
v-model="runtimeValues[filter.key]"
|
|
241
|
-
:label="filter.label"
|
|
242
|
-
:placeholder="placeholder(filter, 'Enter id')"
|
|
243
|
-
clearable
|
|
244
|
-
variant="outlined"
|
|
245
|
-
density="comfortable"
|
|
246
|
-
hide-details="auto"
|
|
247
|
-
/>
|
|
248
|
-
<div
|
|
249
|
-
v-else-if="filter.type === 'dateRange'"
|
|
250
|
-
class="crud-list-filter-surface__range crud-list-filter-surface__range--date"
|
|
251
|
-
role="group"
|
|
252
|
-
:aria-label="`${filter.label} date range`"
|
|
253
|
-
:data-filter-key="filter.key"
|
|
254
|
-
data-filter-type="date-range"
|
|
255
|
-
>
|
|
256
|
-
<CrudListDateFilterControl
|
|
257
|
-
v-model="runtimeValues[filter.key].from"
|
|
258
|
-
:label="`${filter.label} from`"
|
|
259
|
-
:control-id="`${filter.key}-from`"
|
|
260
|
-
:placeholder="placeholder(filter, 'Select start date')"
|
|
261
|
-
/>
|
|
262
|
-
<CrudListDateFilterControl
|
|
263
|
-
v-model="runtimeValues[filter.key].to"
|
|
264
|
-
:label="`${filter.label} to`"
|
|
265
|
-
:control-id="`${filter.key}-to`"
|
|
266
|
-
:placeholder="placeholder(filter, 'Select end date')"
|
|
267
|
-
/>
|
|
268
|
-
</div>
|
|
269
|
-
<div v-else-if="filter.type === 'numberRange'" class="crud-list-filter-surface__range">
|
|
270
|
-
<v-text-field
|
|
271
|
-
v-model="runtimeValues[filter.key].min"
|
|
272
|
-
:label="`${filter.label} min`"
|
|
273
|
-
type="number"
|
|
274
|
-
variant="outlined"
|
|
275
|
-
density="comfortable"
|
|
276
|
-
hide-details="auto"
|
|
277
|
-
/>
|
|
278
|
-
<v-text-field
|
|
279
|
-
v-model="runtimeValues[filter.key].max"
|
|
280
|
-
:label="`${filter.label} max`"
|
|
281
|
-
type="number"
|
|
282
|
-
variant="outlined"
|
|
283
|
-
density="comfortable"
|
|
284
|
-
hide-details="auto"
|
|
285
|
-
/>
|
|
286
|
-
</div>
|
|
287
|
-
<CrudListDateFilterControl
|
|
288
|
-
v-else-if="filter.type === 'date'"
|
|
289
|
-
v-model="runtimeValues[filter.key]"
|
|
290
|
-
:label="filter.label"
|
|
291
|
-
:control-id="filter.key"
|
|
292
|
-
:placeholder="placeholder(filter, 'Select date')"
|
|
293
|
-
/>
|
|
294
|
-
</template>
|
|
295
|
-
</div>
|
|
86
|
+
<CrudListFilterControls :filters="filterEntries" :runtime="runtime" stacked />
|
|
296
87
|
</v-card-text>
|
|
297
88
|
<v-card-actions class="justify-space-between">
|
|
298
89
|
<v-btn variant="text" @click="clearFilters">Clear all</v-btn>
|
|
@@ -335,36 +126,6 @@ function clearFilters() {
|
|
|
335
126
|
padding: 1rem;
|
|
336
127
|
}
|
|
337
128
|
|
|
338
|
-
.crud-list-filter-surface__controls {
|
|
339
|
-
display: grid;
|
|
340
|
-
gap: 0.75rem;
|
|
341
|
-
grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
.crud-list-filter-surface__controls--stacked {
|
|
345
|
-
grid-template-columns: 1fr;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
.crud-list-filter-surface__control {
|
|
349
|
-
min-width: 0;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
.crud-list-filter-surface__range {
|
|
353
|
-
display: grid;
|
|
354
|
-
gap: 0.75rem;
|
|
355
|
-
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
356
|
-
min-width: 0;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
.crud-list-filter-surface__range--date {
|
|
360
|
-
grid-column: span 2;
|
|
361
|
-
grid-template-columns: repeat(2, minmax(14rem, 1fr));
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
.crud-list-filter-surface__controls--stacked .crud-list-filter-surface__range--date {
|
|
365
|
-
grid-column: auto;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
129
|
.crud-list-filter-surface__sheet {
|
|
369
130
|
margin: 0.75rem;
|
|
370
131
|
}
|
|
@@ -380,9 +141,5 @@ function clearFilters() {
|
|
|
380
141
|
align-items: stretch;
|
|
381
142
|
flex-direction: column;
|
|
382
143
|
}
|
|
383
|
-
|
|
384
|
-
.crud-list-filter-surface__range {
|
|
385
|
-
grid-template-columns: 1fr;
|
|
386
|
-
}
|
|
387
144
|
}
|
|
388
145
|
</style>
|
|
@@ -320,14 +320,6 @@ function setSelectableRowsSelected(selected = true) {
|
|
|
320
320
|
</template>
|
|
321
321
|
|
|
322
322
|
<style scoped>
|
|
323
|
-
.crud-screen {
|
|
324
|
-
--crud-screen-state-padding: 2.5rem 1.25rem;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
.crud-screen--operator {
|
|
328
|
-
--crud-screen-state-padding: 2rem 1rem;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
323
|
.crud-list-actions {
|
|
332
324
|
display: flex;
|
|
333
325
|
flex-wrap: wrap;
|
|
@@ -350,7 +342,7 @@ function setSelectableRowsSelected(selected = true) {
|
|
|
350
342
|
.crud-list-state {
|
|
351
343
|
margin-inline: auto;
|
|
352
344
|
max-width: 30rem;
|
|
353
|
-
padding:
|
|
345
|
+
padding: 2rem 1rem;
|
|
354
346
|
text-align: center;
|
|
355
347
|
}
|
|
356
348
|
|
|
@@ -391,25 +383,6 @@ function setSelectableRowsSelected(selected = true) {
|
|
|
391
383
|
margin-top: 0.85rem;
|
|
392
384
|
}
|
|
393
385
|
|
|
394
|
-
.crud-list-card__field {
|
|
395
|
-
display: grid;
|
|
396
|
-
gap: 0.15rem;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
.crud-list-card__field-label {
|
|
400
|
-
color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
|
401
|
-
font-size: 0.72rem;
|
|
402
|
-
letter-spacing: 0.04em;
|
|
403
|
-
line-height: 1.2;
|
|
404
|
-
text-transform: uppercase;
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
.crud-list-card__field-value {
|
|
408
|
-
font-size: 0.95rem;
|
|
409
|
-
line-height: 1.35;
|
|
410
|
-
overflow-wrap: anywhere;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
386
|
.crud-list-table {
|
|
414
387
|
display: none;
|
|
415
388
|
overflow-x: auto;
|