@vc-shell/create-vc-app 1.1.98-rc.5 → 1.1.99-alpha.0

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 (83) hide show
  1. package/README.md +552 -26
  2. package/dist/cli/argv.d.ts +4 -0
  3. package/dist/cli/argv.d.ts.map +1 -0
  4. package/dist/cli/constants.d.ts +4 -0
  5. package/dist/cli/constants.d.ts.map +1 -0
  6. package/dist/cli/errors.d.ts +12 -0
  7. package/dist/cli/errors.d.ts.map +1 -0
  8. package/dist/cli/help.d.ts +3 -0
  9. package/dist/cli/help.d.ts.map +1 -0
  10. package/dist/cli/run.d.ts +2 -0
  11. package/dist/cli/run.d.ts.map +1 -0
  12. package/dist/cli/runtime.d.ts +7 -0
  13. package/dist/cli/runtime.d.ts.map +1 -0
  14. package/dist/cli/types.d.ts +30 -0
  15. package/dist/cli/types.d.ts.map +1 -0
  16. package/dist/cli/utils.d.ts +4 -0
  17. package/dist/cli/utils.d.ts.map +1 -0
  18. package/dist/cli/validation.d.ts +5 -0
  19. package/dist/cli/validation.d.ts.map +1 -0
  20. package/dist/commands/generate-blade.d.ts +16 -0
  21. package/dist/commands/generate-blade.d.ts.map +1 -0
  22. package/dist/index.js +1900 -530
  23. package/dist/templates/base/_package.json +5 -5
  24. package/dist/templates/base/ai-guides/.cursorrules-vc-shell +529 -0
  25. package/dist/templates/base/ai-guides/README.md +360 -0
  26. package/dist/templates/base/ai-guides/guides/AI_GUIDE.md +195 -0
  27. package/dist/templates/base/ai-guides/guides/blade-patterns.md +384 -0
  28. package/dist/templates/base/ai-guides/guides/complete-workflow.md +781 -0
  29. package/dist/templates/base/ai-guides/guides/composables-reference.md +338 -0
  30. package/dist/templates/base/ai-guides/guides/troubleshooting.md +529 -0
  31. package/dist/templates/base/ai-guides/guides/ui-components-reference.md +903 -0
  32. package/dist/templates/base/ai-guides/prompts/adapt-existing-module.md +1026 -0
  33. package/dist/templates/base/ai-guides/prompts/advanced-scenarios.md +852 -0
  34. package/dist/templates/base/ai-guides/prompts/api-client-generation.md +877 -0
  35. package/dist/templates/base/ai-guides/prompts/cli-usage.md +640 -0
  36. package/dist/templates/base/ai-guides/prompts/quick-start-scenarios.md +773 -0
  37. package/dist/templates/base/ai-guides/prompts/simple-modifications.md +987 -0
  38. package/dist/templates/base/src/main.ts +0 -4
  39. package/dist/templates/blades/details/blade.vue +175 -0
  40. package/dist/templates/blades/grid/blade.vue +340 -0
  41. package/dist/templates/composables/details-composable.ts +101 -0
  42. package/dist/templates/composables/grid-composable.ts +244 -0
  43. package/dist/templates/module/components/index.ts +2 -0
  44. package/dist/templates/module/components/widgets/index.ts +2 -0
  45. package/dist/templates/module/composables/index.ts +3 -0
  46. package/dist/templates/module/index.ts +13 -0
  47. package/dist/templates/module/locales/en.json +65 -0
  48. package/dist/templates/module/locales/index.ts +4 -0
  49. package/dist/templates/module/pages/index.ts +3 -0
  50. package/dist/templates/widgets/widget.vue +113 -0
  51. package/dist/utils/form-builder.d.ts +69 -0
  52. package/dist/utils/form-builder.d.ts.map +1 -0
  53. package/dist/utils/format.d.ts +24 -0
  54. package/dist/utils/format.d.ts.map +1 -0
  55. package/dist/utils/naming.d.ts +44 -0
  56. package/dist/utils/naming.d.ts.map +1 -0
  57. package/dist/utils/register-module.d.ts +21 -0
  58. package/dist/utils/register-module.d.ts.map +1 -0
  59. package/dist/workflows/create-app.d.ts +14 -0
  60. package/dist/workflows/create-app.d.ts.map +1 -0
  61. package/package.json +12 -7
  62. package/dist/templates/mocks/sample-data/constants.ts +0 -89
  63. package/dist/templates/mocks/sample-data/index.ts +0 -2
  64. package/dist/templates/mocks/sample-data/methods.ts +0 -65
  65. package/dist/templates/modules/classic-module/composables/index.ts +0 -2
  66. package/dist/templates/modules/classic-module/composables/use{{ModuleNamePascalCase}}Details/index.ts +0 -24
  67. package/dist/templates/modules/classic-module/composables/use{{ModuleNamePascalCase}}List/index.ts +0 -47
  68. package/dist/templates/modules/classic-module/index.ts +0 -8
  69. package/dist/templates/modules/classic-module/locales/en.json +0 -37
  70. package/dist/templates/modules/classic-module/locales/index.ts +0 -2
  71. package/dist/templates/modules/classic-module/pages/details.vue +0 -87
  72. package/dist/templates/modules/classic-module/pages/index.ts +0 -2
  73. package/dist/templates/modules/classic-module/pages/list.vue +0 -257
  74. package/dist/templates/sample/classic-module/composables/index.ts +0 -2
  75. package/dist/templates/sample/classic-module/composables/useDetails/index.ts +0 -54
  76. package/dist/templates/sample/classic-module/composables/useList/index.ts +0 -62
  77. package/dist/templates/sample/classic-module/index.ts +0 -8
  78. package/dist/templates/sample/classic-module/locales/en.json +0 -67
  79. package/dist/templates/sample/classic-module/locales/index.ts +0 -2
  80. package/dist/templates/sample/classic-module/pages/details.vue +0 -238
  81. package/dist/templates/sample/classic-module/pages/index.ts +0 -2
  82. package/dist/templates/sample/classic-module/pages/list.vue +0 -300
  83. package/dist/templates/sample/overrides/main.ts +0 -52
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": "1.1.98-rc.5",
4
+ "version": "1.1.99-alpha.0",
5
5
  "type": "module",
6
6
  "bin": "./dist/index.js",
7
7
  "files": [
@@ -13,24 +13,29 @@
13
13
  "postbuild": "shx cp -R src/templates dist/"
14
14
  },
15
15
  "devDependencies": {
16
+ "@types/lodash-es": "^4.17.12",
17
+ "@types/pluralize": "^0.0.33",
16
18
  "@types/prompts": "^2.4.4",
17
- "@vc-shell/ts-config": "1.1.98-rc.5",
19
+ "@vc-shell/ts-config": "1.1.99-alpha.0",
18
20
  "copyfiles": "^2.4.1",
19
21
  "cross-env": "^7.0.3",
20
22
  "shx": "^0.3.4",
21
- "typescript": "^5.8.3"
23
+ "typescript": "^5.8.3",
24
+ "vite": "^6.3.3",
25
+ "vite-plugin-dts": "^3.6.4"
22
26
  },
23
27
  "dependencies": {
24
28
  "chalk": "^2.4.2",
29
+ "lodash-es": "^4.17.21",
25
30
  "mri": "^1.2.0",
31
+ "pluralize": "^8.0.0",
32
+ "prettier": "^3.4.2",
26
33
  "prompts": "^2.4.2",
27
- "tslib": "^2.5.3",
28
- "vite": "^6.3.3",
29
- "vite-plugin-dts": "^3.6.4"
34
+ "tslib": "^2.5.3"
30
35
  },
31
36
  "publishConfig": {
32
37
  "access": "public",
33
38
  "registry": "https://registry.npmjs.org/"
34
39
  },
35
- "gitHead": "cdcb73b66d7fb58b876c9f497d8c7800a361d6b0"
40
+ "gitHead": "e0fca3bda346af415671814616883476f0d3f97c"
36
41
  }
@@ -1,89 +0,0 @@
1
- interface MockedItem {
2
- imgSrc: string;
3
- name: string;
4
- id: string;
5
- description: string;
6
- price: number;
7
- salePrice: number;
8
- guid: string;
9
- currency: string;
10
- }
11
-
12
- interface MockedQuery {
13
- keyword?: string;
14
- take?: number;
15
- skip?: number;
16
- sort?: string;
17
- }
18
-
19
- const mockedItems: MockedItem[] = [
20
- {
21
- id: "beb211ea-1379-5a79-832c-9577ad387feb",
22
- name: "Product 1",
23
- imgSrc: "https://via.placeholder.com/150",
24
- description: "Product 1 description",
25
- price: 100,
26
- salePrice: 90,
27
- guid: "a1e26bcd-2704-5a3f-b97c-3e32e3d77a38",
28
- currency: "USD",
29
- },
30
- {
31
- id: "44b96758-792a-5449-b649-f2a0cd614c4b",
32
- name: "Product 2",
33
- imgSrc: "https://via.placeholder.com/150",
34
- description: "Product 2 description",
35
- price: 200,
36
- salePrice: 90,
37
- guid: "0ab995c0-3798-5011-a4ae-498e4c683cfd",
38
- currency: "USD",
39
- },
40
- {
41
- id: "605b2bfb-ba13-5687-91d5-0261b4b60524",
42
- name: "Product 3",
43
- imgSrc: "https://via.placeholder.com/150",
44
- description: "Product 3 description",
45
- price: 300,
46
- salePrice: 90,
47
- guid: "8a9b6954-7bf7-58b2-a146-c68e06fa7bb4",
48
- currency: "USD",
49
- },
50
- {
51
- id: "5ca8185c-0c28-59bf-ab40-991f134e6db3",
52
- name: "Product 4",
53
- imgSrc: "https://via.placeholder.com/150",
54
- description: "Product 4 description",
55
- price: 400,
56
- salePrice: 90,
57
- guid: "261364c5-f976-5c86-a92c-b0f0ea14efc7",
58
- currency: "USD",
59
- },
60
- {
61
- id: "077930cb-0874-5f85-9a5b-daafdd0bf860",
62
- name: "Product 5",
63
- imgSrc: "https://via.placeholder.com/150",
64
- description: "Product 5 description",
65
- price: 500,
66
- salePrice: 90,
67
- guid: "74d302ef-31e6-5432-91f1-d92c87ee2d2a",
68
- currency: "USD",
69
- },
70
- ];
71
-
72
- const currencyOptions = [
73
- {
74
- value: "USD",
75
- label: "USD",
76
- },
77
- {
78
- value: "EUR",
79
- label: "EUR",
80
- },
81
- {
82
- value: "GBP",
83
- label: "GBP",
84
- },
85
- ];
86
-
87
- export { mockedItems, currencyOptions };
88
-
89
- export type { MockedItem, MockedQuery };
@@ -1,2 +0,0 @@
1
- export * from './constants'
2
- export * from './methods'
@@ -1,65 +0,0 @@
1
- import { type MockedItem, type MockedQuery, mockedItems } from ".";
2
-
3
- export function loadMockItemsList(query: MockedQuery) {
4
- return new Promise((resolve: (value: MockedItem[]) => void) => {
5
- setTimeout(() => resolve(mockedItems), 1000);
6
- }).then((res) => {
7
- res = res.filter((x) => {
8
- if (query.keyword) {
9
- return x.name.toLowerCase().includes(query.keyword.toLowerCase());
10
- }
11
- return true;
12
- });
13
-
14
- return { results: res, totalCount: res.length };
15
- });
16
- }
17
-
18
- export async function loadMockItem(args?: { id: string }) {
19
- return new Promise((resolve: (value: MockedItem) => void) => {
20
- setTimeout(() => {
21
- const findMockedItem = mockedItems.find((x) => x.id === args?.id);
22
-
23
- if (findMockedItem) resolve({ ...findMockedItem });
24
- }, 1000);
25
- });
26
- }
27
-
28
- export async function removeMockItem(args: { id: string }) {
29
- new Promise((resolve: (value: boolean) => void) => {
30
- setTimeout(() => {
31
- const index = mockedItems.findIndex((x) => x.id === args.id);
32
-
33
- if (index > -1) {
34
- mockedItems.splice(index, 1);
35
- resolve(true);
36
- } else {
37
- resolve(false);
38
- }
39
- }, 1000);
40
- });
41
- }
42
-
43
- export async function addNewMockItem(args: MockedItem) {
44
- return new Promise((resolve: (value: MockedItem) => void) => {
45
- setTimeout(() => {
46
- mockedItems.push(args);
47
- resolve(args);
48
- }, 1000);
49
- });
50
- }
51
-
52
- export async function updateMockItem(args: MockedItem) {
53
- return new Promise((resolve: (value: MockedItem) => void) => {
54
- setTimeout(() => {
55
- const index = mockedItems.findIndex((x) => x.id === args.id);
56
-
57
- if (index > -1) {
58
- mockedItems[index] = args;
59
- resolve(args);
60
- } else {
61
- resolve(args);
62
- }
63
- }, 1000);
64
- });
65
- }
@@ -1,2 +0,0 @@
1
- export { default as use{{ModuleNamePascalCase}}List } from "./use{{ModuleNamePascalCase}}List";
2
- export { default as use{{ModuleNamePascalCase}}Details } from "./use{{ModuleNamePascalCase}}Details";
@@ -1,24 +0,0 @@
1
- import { computed, ref } from "vue";
2
- import { useAsync, useLoading, useModificationTracker } from "@vc-shell/framework";
3
-
4
- export default () => {
5
- const item = ref({});
6
-
7
- const { isModified, currentValue, resetModificationState } = useModificationTracker(item);
8
-
9
- // Implement your own load function
10
- const { loading: itemLoading, action: getItem } = useAsync<{ id: string }>(async (payload) => {
11
- item.value = {};
12
-
13
- resetModificationState();
14
- });
15
-
16
- const loading = useLoading(itemLoading);
17
-
18
- return {
19
- item: currentValue,
20
- loading: computed(() => loading.value),
21
- getItem,
22
- isModified,
23
- };
24
- };
@@ -1,47 +0,0 @@
1
- import { computed, ref } from "vue";
2
- import { useAsync, useLoading } from "@vc-shell/framework";
3
-
4
- // Replace with the actual search query interface from the API client
5
- interface SearchQuery {
6
- take?: number;
7
- skip?: number;
8
- sort?: string;
9
- keyword?: string;
10
- }
11
-
12
- export default (options?: { pageSize?: number, sort?: string }) => {
13
- const pageSize = options?.pageSize || 20;
14
- const searchResult = ref();
15
- const searchQuery = ref<SearchQuery>({
16
- take: pageSize,
17
- skip: 0,
18
- sort: options?.sort || "createdDate:DESC",
19
- });
20
-
21
- // Implement your own load function
22
- const { loading: itemLoading, action: getItems } = useAsync<SearchQuery>(async (payload) => {
23
- searchQuery.value = { ...searchQuery.value, ...payload };
24
- searchResult.value = {
25
- totalCount: 0,
26
- items: [],
27
- };
28
- });
29
-
30
- // Implement your own remove function
31
- const { loading: removeLoading, action: removeItems } = useAsync<{ ids: string[] }>(async (payload) => {
32
- return;
33
- });
34
-
35
- const loading = useLoading(itemLoading, removeLoading);
36
-
37
- return {
38
- data: computed(() => searchResult.value?.items),
39
- loading: computed(() => loading.value),
40
- totalCount: computed(() => searchResult.value?.totalCount || 0),
41
- pages: computed(() => Math.ceil((searchResult.value?.totalCount || 1) / pageSize)),
42
- currentPage: computed(() => Math.ceil((searchQuery.value?.skip || 0) / Math.max(1, pageSize) + 1)),
43
- getItems,
44
- removeItems,
45
- searchQuery,
46
- };
47
- };
@@ -1,8 +0,0 @@
1
- import * as pages from "./pages";
2
- import * as locales from "./locales";
3
- import { createAppModule } from "@vc-shell/framework";
4
-
5
- export default createAppModule(pages, locales);
6
-
7
- export * from "./pages";
8
- export * from "./composables";
@@ -1,37 +0,0 @@
1
- {
2
- "{{ModuleNameUppercaseSnakeCase}}": {
3
- "MENU": {
4
- "TITLE": "{{ModuleNameSentenceCase}}"
5
- },
6
- "PAGES": {
7
- "LIST": {
8
- "TITLE": "{{ModuleNameSentenceCase}} list",
9
- "TOOLBAR": {
10
- "REFRESH": "Refresh",
11
- "ADD": "Add"
12
- },
13
- "SEARCH": {
14
- "PLACEHOLDER": "Search keywords"
15
- },
16
- "TABLE": {
17
- "TOTALS": "Count:",
18
- "HEADER": {}
19
- },
20
- "EMPTY": {
21
- "NO_ITEMS": "No items found",
22
- "ADD": "Add items"
23
- },
24
- "NOT_FOUND": {
25
- "EMPTY": "No items found",
26
- "RESET": "Reset"
27
- }
28
- },
29
- "DETAILS": {
30
- "TITLE": "{{ModuleNameSentenceCase}} details"
31
- },
32
- "ALERTS": {
33
- "CLOSE_CONFIRMATION": "You have unsaved changes. Close anyway?"
34
- }
35
- }
36
- }
37
- }
@@ -1,2 +0,0 @@
1
- import * as en from "./en.json";
2
- export { en };
@@ -1,87 +0,0 @@
1
- <template>
2
- <VcBlade
3
- v-loading="loading"
4
- :title="title"
5
- :expanded="expanded"
6
- :closable="closable"
7
- width="70%"
8
- :toolbar-items="bladeToolbar"
9
- @close="$emit('close:blade')"
10
- @expand="$emit('expand:blade')"
11
- @collapse="$emit('collapse:blade')"
12
- >
13
- <VcContainer class="tw-p-2">
14
- <VcForm>
15
- <!-- You can add form fields here -->
16
- </VcForm>
17
- </VcContainer>
18
- </VcBlade>
19
- </template>
20
-
21
- <script lang="ts" setup>
22
- import { IBladeToolbar, IParentCallArgs, useBladeNavigation, usePopup, useBeforeUnload } from "@vc-shell/framework";
23
- import { use{{ModuleNamePascalCase}}Details } from "./../composables";
24
- import { computed, onMounted, ref } from "vue";
25
- import { useI18n } from "vue-i18n";
26
- import { useForm } from "vee-validate";
27
-
28
- export interface Props {
29
- expanded?: boolean;
30
- closable?: boolean;
31
- param?: string;
32
- }
33
-
34
- export interface Emits {
35
- (event: "parent:call", args: IParentCallArgs): void;
36
- (event: "collapse:blade"): void;
37
- (event: "expand:blade"): void;
38
- (event: "close:blade"): void;
39
- }
40
-
41
- defineOptions({
42
- url: "/{{ModuleName}}-details",
43
- name: "{{ModuleNamePascalCase}}Details",
44
- });
45
-
46
- const props = withDefaults(defineProps<Props>(), {
47
- expanded: true,
48
- closable: true,
49
- param: undefined,
50
- });
51
-
52
- defineEmits<Emits>();
53
-
54
- const { loading, getItem, isModified } = use{{ModuleNamePascalCase}}Details();
55
- const { onBeforeClose } = useBladeNavigation();
56
- const { showConfirmation } = usePopup();
57
- const { t } = useI18n({ useScope: "global" });
58
-
59
- const { meta } = useForm({
60
- validateOnMount: false,
61
- });
62
-
63
- const isDisabled = computed(() => {
64
- return !meta.value.dirty || !meta.value.valid;
65
- });
66
-
67
- const bladeToolbar = ref<IBladeToolbar[]>([]);
68
- const title = computed(() => t("{{ModuleNameUppercaseSnakeCase}}.PAGES.DETAILS.TITLE"));
69
-
70
- onMounted(async () => {
71
- if (props.param) {
72
- await getItem({ id: props.param });
73
- }
74
- });
75
-
76
- onBeforeClose(async () => {
77
- if (!isDisabled.value && isModified.value) {
78
- return await showConfirmation(t("SAMPLE_APP.PAGES.ALERTS.CLOSE_CONFIRMATION"));
79
- }
80
- });
81
-
82
- useBeforeUnload(computed(() => !isDisabled.value && isModified.value));
83
-
84
- defineExpose({
85
- title,
86
- });
87
- </script>
@@ -1,2 +0,0 @@
1
- export { default as List } from "./list.vue";
2
- export {default as Details } from './details.vue'
@@ -1,257 +0,0 @@
1
- <template>
2
- <VcBlade
3
- :title="title"
4
- width="50%"
5
- :expanded="expanded"
6
- :closable="closable"
7
- :toolbar-items="bladeToolbar"
8
- @close="$emit('close:blade')"
9
- @expand="$emit('expand:blade')"
10
- @collapse="$emit('collapse:blade')"
11
- >
12
- <!-- Blade contents -->
13
- <!-- @vue-generic {never} -->
14
- <VcTable
15
- :expanded="expanded"
16
- class="tw-grow tw-basis-0"
17
- multiselect
18
- :loading="loading"
19
- :columns="columns"
20
- :sort="sortExpression"
21
- :current-page="currentPage"
22
- :search-value="searchValue"
23
- enable-item-actions
24
- :item-action-builder="actionBuilder"
25
- :pages="pages"
26
- :empty="empty"
27
- :notfound="notfound"
28
- :total-count="totalCount"
29
- :selected-item-id="selectedItemId"
30
- :search-placeholder="$t('{{ModuleNameUppercaseSnakeCase}}.PAGES.LIST.SEARCH.PLACEHOLDER')"
31
- :total-label="$t('{{ModuleNameUppercaseSnakeCase}}.PAGES.LIST.TABLE.TOTALS')"
32
- state-key="{{ModuleNameUppercaseSnakeCase}}"
33
- :items="data"
34
- @item-click="onItemClick"
35
- @header-click="onHeaderClick"
36
- @search:change="onSearchList"
37
- @pagination-click="onPaginationClick"
38
- @selection-changed="onSelectionChanged"
39
- >
40
- </VcTable>
41
- </VcBlade>
42
- </template>
43
-
44
- <script lang="ts" setup>
45
- import { computed, ref, markRaw, onMounted, watch } from "vue";
46
- import { IBladeToolbar, IParentCallArgs, ITableColumns, useBladeNavigation, useTableSort, IActionBuilderResult, useFunctions, usePopup } from "@vc-shell/framework";
47
- import { useI18n } from "vue-i18n";
48
- import { use{{ModuleNamePascalCase}}List } from "./../composables";
49
- import Details from "./details.vue";
50
-
51
- export interface Props {
52
- expanded?: boolean;
53
- closable?: boolean;
54
- param?: string;
55
- options?: Record<string, unknown>;
56
- }
57
-
58
- export interface Emits {
59
- (event: "parent:call", args: IParentCallArgs): void;
60
- (event: "collapse:blade"): void;
61
- (event: "expand:blade"): void;
62
- (event: "close:blade"): void;
63
- }
64
-
65
- defineOptions({
66
- url: "/{{ModuleName}}",
67
- name: "{{ModuleNamePascalCase}}List",
68
- isWorkspace: true,
69
- menuItem: {
70
- title: "{{ModuleNameUppercaseSnakeCase}}.MENU.TITLE",
71
- icon: "lucide-file",
72
- priority: 1,
73
- },
74
- });
75
-
76
- const props = withDefaults(defineProps<Props>(), {
77
- expanded: true,
78
- closable: true,
79
- });
80
-
81
- defineEmits<Emits>();
82
-
83
- const { t } = useI18n({ useScope: "global" });
84
- const { openBlade } = useBladeNavigation();
85
- const { debounce } = useFunctions();
86
- const { showConfirmation } = usePopup();
87
- const { sortExpression, handleSortChange: tableSortHandler } = useTableSort({
88
- initialDirection: "DESC",
89
- initialProperty: "createdDate",
90
- });
91
-
92
- const { getItems, data, loading, totalCount, pages, currentPage, searchQuery, removeItems } = use{{ModuleNamePascalCase}}List({
93
- sort: sortExpression.value,
94
- pageSize: 20,
95
- });
96
-
97
- const searchValue = ref();
98
- const selectedItemId = ref<string>();
99
- const selectedItemsIds = ref<string[]>([]);
100
-
101
- const empty = {
102
- icon: "lucide-file",
103
- text: computed(() => t("{{ModuleNameUppercaseSnakeCase}}.PAGES.LIST.EMPTY.NO_ITEMS")),
104
- action: computed(() => t("{{ModuleNameUppercaseSnakeCase}}.PAGES.LIST.EMPTY.ADD")),
105
- clickHandler: () => {
106
- addItem();
107
- },
108
- };
109
-
110
- const notfound = {
111
- icon: "lucide-file",
112
- text: computed(() => t("{{ModuleNameUppercaseSnakeCase}}.PAGES.LIST.NOT_FOUND.EMPTY")),
113
- action: computed(() => t("{{ModuleNameUppercaseSnakeCase}}.PAGES.LIST.NOT_FOUND.RESET")),
114
- clickHandler: async () => {
115
- searchValue.value = "";
116
- await getItems({
117
- ...searchQuery.value,
118
- keyword: "",
119
- });
120
- },
121
- };
122
-
123
- watch(
124
- () => props.param,
125
- (newVal) => {
126
- selectedItemId.value = newVal;
127
- },
128
- { immediate: true },
129
- );
130
-
131
- onMounted(async () => {
132
- await getItems({
133
- ...searchQuery.value,
134
- sort: sortExpression.value,
135
- });
136
- });
137
-
138
- const bladeToolbar = ref<IBladeToolbar[]>([
139
- {
140
- id: "refresh",
141
- title: computed(() => t("{{ModuleNameUppercaseSnakeCase}}.PAGES.LIST.TOOLBAR.REFRESH")),
142
- icon: "material-refresh",
143
- async clickHandler() {
144
- await reload();
145
- },
146
- },
147
- {
148
- id: "add",
149
- icon: "material-add",
150
- title: computed(() => t("{{ModuleNameUppercaseSnakeCase}}.PAGES.LIST.TOOLBAR.ADD")),
151
- clickHandler: () => {
152
- addItem();
153
- },
154
- },
155
- ]);
156
-
157
- const columns = ref<ITableColumns[]>([
158
- // You can add columns here
159
- ]);
160
-
161
- const title = computed(() => t("{{ModuleNameUppercaseSnakeCase}}.PAGES.LIST.TITLE"));
162
-
163
- const onSearchList = debounce(async (keyword: string) => {
164
- searchValue.value = keyword;
165
- await getItems({
166
- ...searchQuery.value,
167
- keyword,
168
- });
169
- }, 1000);
170
-
171
- const reload = async () => {
172
- await getItems({
173
- ...searchQuery.value,
174
- skip: (currentPage.value - 1) * (searchQuery.value.take ?? 10),
175
- sort: sortExpression.value,
176
- });
177
- };
178
-
179
- const addItem = () => {
180
- openBlade({
181
- blade: markRaw(Details),
182
- });
183
- };
184
-
185
- const onItemClick = (item: { id: string }) => {
186
- openBlade({
187
- blade: markRaw(Details),
188
- param: item.id,
189
- onOpen() {
190
- selectedItemId.value = item.id;
191
- },
192
- onClose() {
193
- selectedItemId.value = undefined;
194
- },
195
- });
196
- };
197
-
198
- const onHeaderClick = (item: ITableColumns) => {
199
- tableSortHandler(item.id);
200
- };
201
-
202
- const actionBuilder = (): IActionBuilderResult[] => {
203
- const result: IActionBuilderResult[] = [];
204
- result.push({
205
- icon: "material-delete",
206
- title: "Delete",
207
- type: "danger",
208
- async clickHandler(_item: { id: string }) {
209
- if (_item.id && !selectedItemsIds.value.includes(_item.id)) {
210
- selectedItemsIds.value.push(_item.id);
211
- }
212
- await remove(selectedItemsIds.value);
213
- selectedItemsIds.value = [];
214
- },
215
- });
216
-
217
- return result;
218
- };
219
-
220
- const onPaginationClick = async (page: number) => {
221
- await getItems({
222
- ...searchQuery.value,
223
- skip: (page - 1) * (searchQuery.value.take ?? 20),
224
- });
225
- };
226
-
227
- const onSelectionChanged = (items: Record<string, any>[]) => {
228
- selectedItemsIds.value = items.flatMap((item) => (item.id ? [item.id] : []));
229
- };
230
-
231
- async function remove(ids: string[]) {
232
- if (
233
- await showConfirmation(
234
- t(`{{ModuleNameUppercaseSnakeCase}}.PAGES.ALERTS.DELETE_SELECTED_CONFIRMATION.MESSAGE`, {
235
- count: selectedItemsIds.value.length,
236
- }),
237
- )
238
- ) {
239
- await removeItems({ ids });
240
- await reload();
241
- }
242
- }
243
-
244
- watch(
245
- () => sortExpression.value,
246
- async (newVal) => {
247
- await getItems({
248
- sort: newVal,
249
- });
250
- },
251
- );
252
-
253
- defineExpose({
254
- title,
255
- reload,
256
- });
257
- </script>
@@ -1,2 +0,0 @@
1
- export { default as useList } from "./useList";
2
- export { default as useDetails } from "./useDetails";