@vc-shell/create-vc-app 2.0.10-pr242.2e7f6b3 → 2.0.10-pr242.bfb451e
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.
|
@@ -14,7 +14,6 @@
|
|
|
14
14
|
:pagination="{ currentPage, pages }"
|
|
15
15
|
:searchable="true"
|
|
16
16
|
:state-key="'<%- ModuleNameScreamingSnake %>'"
|
|
17
|
-
@search="onSearch"
|
|
18
17
|
@row-click="onRowClick"
|
|
19
18
|
@pagination-click="onPaginationClick"
|
|
20
19
|
>
|
|
@@ -26,7 +25,7 @@
|
|
|
26
25
|
</template>
|
|
27
26
|
|
|
28
27
|
<script setup lang="ts">
|
|
29
|
-
import { useBlade, useDataTableSort, useTableQueryState, type IBladeToolbar } from "@vc-shell/framework";
|
|
28
|
+
import { useBlade, useDataTableSort, useTableQueryState, useFunctions, type IBladeToolbar } from "@vc-shell/framework";
|
|
30
29
|
import { VcBlade, VcDataTable, VcColumn } from "@vc-shell/framework/ui";
|
|
31
30
|
import { computed, ref, watch } from "vue";
|
|
32
31
|
import use<%- ModuleNamePascalCase %>List from "../composables/useList";
|
|
@@ -45,6 +44,7 @@ defineBlade({
|
|
|
45
44
|
|
|
46
45
|
const { t } = useI18n({ useScope: "global" });
|
|
47
46
|
const { openBlade, exposeToChildren } = useBlade();
|
|
47
|
+
const { debounce } = useFunctions();
|
|
48
48
|
|
|
49
49
|
const PAGE_SIZE = 20;
|
|
50
50
|
|
|
@@ -55,59 +55,39 @@ const { sortField, sortOrder, sortExpression } = useDataTableSort({
|
|
|
55
55
|
|
|
56
56
|
const { data, loading, totalCount, getItems } = use<%- ModuleNamePascalCase %>List();
|
|
57
57
|
|
|
58
|
-
const searchValue = ref<string>();
|
|
59
|
-
const appliedKeyword = ref<string>(); // applied filter — drives the loader
|
|
58
|
+
const searchValue = ref<string>();
|
|
60
59
|
const currentPage = ref(1);
|
|
61
|
-
|
|
62
60
|
const pages = computed(() => Math.ceil(totalCount.value / PAGE_SIZE) || 0);
|
|
63
61
|
|
|
64
|
-
//
|
|
65
|
-
// BEFORE the loader watch below — so a reload costs exactly one request.
|
|
62
|
+
// Restore sort/search/page from the URL, then load once below.
|
|
66
63
|
const restored = useTableQueryState("<%- ModuleNameScreamingSnake %>").read();
|
|
67
64
|
if (restored.sort) {
|
|
68
65
|
const [field, direction] = restored.sort.split(":");
|
|
69
66
|
sortField.value = field;
|
|
70
67
|
sortOrder.value = direction === "DESC" ? -1 : 1;
|
|
71
68
|
}
|
|
72
|
-
if (restored.search
|
|
73
|
-
|
|
74
|
-
appliedKeyword.value = restored.search;
|
|
75
|
-
}
|
|
76
|
-
if (restored.page) {
|
|
77
|
-
currentPage.value = restored.page;
|
|
78
|
-
}
|
|
69
|
+
if (restored.search) searchValue.value = restored.search;
|
|
70
|
+
if (restored.page) currentPage.value = restored.page;
|
|
79
71
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
watch(
|
|
83
|
-
() => ({
|
|
72
|
+
function load() {
|
|
73
|
+
return getItems({
|
|
84
74
|
sort: sortExpression.value,
|
|
85
|
-
keyword:
|
|
75
|
+
keyword: searchValue.value || undefined,
|
|
86
76
|
skip: (currentPage.value - 1) * PAGE_SIZE,
|
|
87
77
|
take: PAGE_SIZE,
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const onSearch = (keyword: string) => {
|
|
96
|
-
appliedKeyword.value = keyword;
|
|
97
|
-
currentPage.value = 1;
|
|
98
|
-
};
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// One loader for sort/search/page. Debounced so typing doesn't fetch per keystroke.
|
|
82
|
+
load();
|
|
83
|
+
watch(searchValue, () => (currentPage.value = 1));
|
|
84
|
+
watch([sortExpression, searchValue, currentPage], debounce(load, 300));
|
|
99
85
|
|
|
100
86
|
const onPaginationClick = (page: number) => {
|
|
101
87
|
currentPage.value = page;
|
|
102
88
|
};
|
|
103
89
|
|
|
104
|
-
const reload = () =>
|
|
105
|
-
getItems({
|
|
106
|
-
sort: sortExpression.value,
|
|
107
|
-
keyword: appliedKeyword.value || undefined,
|
|
108
|
-
skip: (currentPage.value - 1) * PAGE_SIZE,
|
|
109
|
-
take: PAGE_SIZE,
|
|
110
|
-
});
|
|
90
|
+
const reload = () => load();
|
|
111
91
|
|
|
112
92
|
const bladeToolbar = ref<IBladeToolbar[]>([
|
|
113
93
|
{
|
|
@@ -34,7 +34,6 @@
|
|
|
34
34
|
:total-label="$t('SAMPLE_APP.PAGES.LIST.TABLE.TOTALS')"
|
|
35
35
|
:total-count="totalCount"
|
|
36
36
|
state-key="SAMPLE_APP"
|
|
37
|
-
@search="onSearchList"
|
|
38
37
|
@row-click="onItemClick"
|
|
39
38
|
@pagination-click="onPaginationClick"
|
|
40
39
|
>
|
|
@@ -76,7 +75,7 @@
|
|
|
76
75
|
|
|
77
76
|
<script lang="ts" setup>
|
|
78
77
|
import { computed, ref, watch } from "vue";
|
|
79
|
-
import { IBladeToolbar, useBlade, usePopup, useDataTableSort, useTableQueryState } from "@vc-shell/framework";
|
|
78
|
+
import { IBladeToolbar, useBlade, usePopup, useDataTableSort, useTableQueryState, useFunctions } from "@vc-shell/framework";
|
|
80
79
|
import type { TableAction } from "@vc-shell/framework";
|
|
81
80
|
import { VcColumn, VcDataTable, VcBlade } from "@vc-shell/framework/ui";
|
|
82
81
|
import { useI18n } from "vue-i18n";
|
|
@@ -97,6 +96,7 @@ defineBlade({
|
|
|
97
96
|
const { t } = useI18n({ useScope: "global" });
|
|
98
97
|
const { param, openBlade, exposeToChildren } = useBlade();
|
|
99
98
|
const { showConfirmation } = usePopup();
|
|
99
|
+
const { debounce } = useFunctions();
|
|
100
100
|
|
|
101
101
|
const PAGE_SIZE = 20;
|
|
102
102
|
|
|
@@ -110,30 +110,22 @@ const { getItems, removeItems, data, loading, totalCount, pages } = useList({
|
|
|
110
110
|
pageSize: PAGE_SIZE,
|
|
111
111
|
});
|
|
112
112
|
|
|
113
|
-
const searchValue = ref<string>();
|
|
114
|
-
const appliedKeyword = ref<string>(); // applied filter — drives the loader
|
|
113
|
+
const searchValue = ref<string>();
|
|
115
114
|
const currentPage = ref(1);
|
|
116
115
|
const selectedItemId = ref<string>();
|
|
117
116
|
const selectedItems = ref<MockedItem[]>([]);
|
|
118
117
|
|
|
119
118
|
const selectedIds = computed(() => selectedItems.value.map((item) => item.id).filter(Boolean) as string[]);
|
|
120
119
|
|
|
121
|
-
//
|
|
122
|
-
// BEFORE the loader watch below — so a page reload costs exactly one request with
|
|
123
|
-
// the full criteria, instead of several uncoordinated loads.
|
|
120
|
+
// Restore sort/search/page from the URL, then load once below.
|
|
124
121
|
const restored = useTableQueryState("SAMPLE_APP").read();
|
|
125
122
|
if (restored.sort) {
|
|
126
123
|
const [field, direction] = restored.sort.split(":");
|
|
127
124
|
sortField.value = field;
|
|
128
125
|
sortOrder.value = direction === "DESC" ? -1 : 1;
|
|
129
126
|
}
|
|
130
|
-
if (restored.search
|
|
131
|
-
|
|
132
|
-
appliedKeyword.value = restored.search;
|
|
133
|
-
}
|
|
134
|
-
if (restored.page) {
|
|
135
|
-
currentPage.value = restored.page;
|
|
136
|
-
}
|
|
127
|
+
if (restored.search) searchValue.value = restored.search;
|
|
128
|
+
if (restored.page) currentPage.value = restored.page;
|
|
137
129
|
|
|
138
130
|
watch(
|
|
139
131
|
param,
|
|
@@ -143,36 +135,25 @@ watch(
|
|
|
143
135
|
{ immediate: true },
|
|
144
136
|
);
|
|
145
137
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
// yields one request.
|
|
149
|
-
watch(
|
|
150
|
-
() => ({
|
|
138
|
+
function load() {
|
|
139
|
+
return getItems({
|
|
151
140
|
sort: sortExpression.value,
|
|
152
|
-
keyword:
|
|
141
|
+
keyword: searchValue.value || undefined,
|
|
153
142
|
skip: (currentPage.value - 1) * PAGE_SIZE,
|
|
154
|
-
})
|
|
155
|
-
|
|
156
|
-
{ immediate: true },
|
|
157
|
-
);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
158
145
|
|
|
159
|
-
//
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
currentPage.value = 1;
|
|
164
|
-
};
|
|
146
|
+
// One loader for sort/search/page. Debounced so typing doesn't fetch per keystroke.
|
|
147
|
+
load();
|
|
148
|
+
watch(searchValue, () => (currentPage.value = 1));
|
|
149
|
+
watch([sortExpression, searchValue, currentPage], debounce(load, 300));
|
|
165
150
|
|
|
166
151
|
const clearSearch = () => {
|
|
167
152
|
searchValue.value = "";
|
|
168
|
-
appliedKeyword.value = "";
|
|
169
|
-
currentPage.value = 1;
|
|
170
153
|
};
|
|
171
154
|
|
|
172
155
|
const addItem = () => {
|
|
173
|
-
openBlade({
|
|
174
|
-
name: "SampleDetails",
|
|
175
|
-
});
|
|
156
|
+
openBlade({ name: "SampleDetails" });
|
|
176
157
|
};
|
|
177
158
|
|
|
178
159
|
const onPaginationClick = (page: number) => {
|
|
@@ -203,13 +184,7 @@ const title = computed(() => t("SAMPLE_APP.PAGES.LIST.TITLE"));
|
|
|
203
184
|
|
|
204
185
|
const reload = async () => {
|
|
205
186
|
selectedItems.value = [];
|
|
206
|
-
|
|
207
|
-
// not fire; reload calls the API directly with the current combined criteria.
|
|
208
|
-
await getItems({
|
|
209
|
-
sort: sortExpression.value,
|
|
210
|
-
keyword: appliedKeyword.value || undefined,
|
|
211
|
-
skip: (currentPage.value - 1) * PAGE_SIZE,
|
|
212
|
-
});
|
|
187
|
+
await load();
|
|
213
188
|
};
|
|
214
189
|
|
|
215
190
|
const onItemClick = (event: { data: MockedItem; index: number; originalEvent: Event }) => {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vc-shell/create-vc-app",
|
|
3
3
|
"description": "Application scaffolding",
|
|
4
|
-
"version": "2.0.10-pr242.
|
|
4
|
+
"version": "2.0.10-pr242.bfb451e",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": "./dist/index.js",
|
|
7
7
|
"files": [
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"devDependencies": {
|
|
17
17
|
"@types/ejs": "^3.1.5",
|
|
18
18
|
"@types/prompts": "^2.4.4",
|
|
19
|
-
"@vc-shell/ts-config": "2.0.10-pr242.
|
|
19
|
+
"@vc-shell/ts-config": "2.0.10-pr242.bfb451e",
|
|
20
20
|
"copyfiles": "^2.4.1",
|
|
21
21
|
"cross-env": "^7.0.3",
|
|
22
22
|
"shx": "^0.3.4",
|