@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.
- package/README.md +552 -26
- package/dist/cli/argv.d.ts +4 -0
- package/dist/cli/argv.d.ts.map +1 -0
- package/dist/cli/constants.d.ts +4 -0
- package/dist/cli/constants.d.ts.map +1 -0
- package/dist/cli/errors.d.ts +12 -0
- package/dist/cli/errors.d.ts.map +1 -0
- package/dist/cli/help.d.ts +3 -0
- package/dist/cli/help.d.ts.map +1 -0
- package/dist/cli/run.d.ts +2 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/runtime.d.ts +7 -0
- package/dist/cli/runtime.d.ts.map +1 -0
- package/dist/cli/types.d.ts +30 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/utils.d.ts +4 -0
- package/dist/cli/utils.d.ts.map +1 -0
- package/dist/cli/validation.d.ts +5 -0
- package/dist/cli/validation.d.ts.map +1 -0
- package/dist/commands/generate-blade.d.ts +16 -0
- package/dist/commands/generate-blade.d.ts.map +1 -0
- package/dist/index.js +1900 -530
- package/dist/templates/base/_package.json +5 -5
- package/dist/templates/base/ai-guides/.cursorrules-vc-shell +529 -0
- package/dist/templates/base/ai-guides/README.md +360 -0
- package/dist/templates/base/ai-guides/guides/AI_GUIDE.md +195 -0
- package/dist/templates/base/ai-guides/guides/blade-patterns.md +384 -0
- package/dist/templates/base/ai-guides/guides/complete-workflow.md +781 -0
- package/dist/templates/base/ai-guides/guides/composables-reference.md +338 -0
- package/dist/templates/base/ai-guides/guides/troubleshooting.md +529 -0
- package/dist/templates/base/ai-guides/guides/ui-components-reference.md +903 -0
- package/dist/templates/base/ai-guides/prompts/adapt-existing-module.md +1026 -0
- package/dist/templates/base/ai-guides/prompts/advanced-scenarios.md +852 -0
- package/dist/templates/base/ai-guides/prompts/api-client-generation.md +877 -0
- package/dist/templates/base/ai-guides/prompts/cli-usage.md +640 -0
- package/dist/templates/base/ai-guides/prompts/quick-start-scenarios.md +773 -0
- package/dist/templates/base/ai-guides/prompts/simple-modifications.md +987 -0
- package/dist/templates/base/src/main.ts +0 -4
- package/dist/templates/blades/details/blade.vue +175 -0
- package/dist/templates/blades/grid/blade.vue +340 -0
- package/dist/templates/composables/details-composable.ts +101 -0
- package/dist/templates/composables/grid-composable.ts +244 -0
- package/dist/templates/module/components/index.ts +2 -0
- package/dist/templates/module/components/widgets/index.ts +2 -0
- package/dist/templates/module/composables/index.ts +3 -0
- package/dist/templates/module/index.ts +13 -0
- package/dist/templates/module/locales/en.json +65 -0
- package/dist/templates/module/locales/index.ts +4 -0
- package/dist/templates/module/pages/index.ts +3 -0
- package/dist/templates/widgets/widget.vue +113 -0
- package/dist/utils/form-builder.d.ts +69 -0
- package/dist/utils/form-builder.d.ts.map +1 -0
- package/dist/utils/format.d.ts +24 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/naming.d.ts +44 -0
- package/dist/utils/naming.d.ts.map +1 -0
- package/dist/utils/register-module.d.ts +21 -0
- package/dist/utils/register-module.d.ts.map +1 -0
- package/dist/workflows/create-app.d.ts +14 -0
- package/dist/workflows/create-app.d.ts.map +1 -0
- package/package.json +12 -7
- package/dist/templates/mocks/sample-data/constants.ts +0 -89
- package/dist/templates/mocks/sample-data/index.ts +0 -2
- package/dist/templates/mocks/sample-data/methods.ts +0 -65
- package/dist/templates/modules/classic-module/composables/index.ts +0 -2
- package/dist/templates/modules/classic-module/composables/use{{ModuleNamePascalCase}}Details/index.ts +0 -24
- package/dist/templates/modules/classic-module/composables/use{{ModuleNamePascalCase}}List/index.ts +0 -47
- package/dist/templates/modules/classic-module/index.ts +0 -8
- package/dist/templates/modules/classic-module/locales/en.json +0 -37
- package/dist/templates/modules/classic-module/locales/index.ts +0 -2
- package/dist/templates/modules/classic-module/pages/details.vue +0 -87
- package/dist/templates/modules/classic-module/pages/index.ts +0 -2
- package/dist/templates/modules/classic-module/pages/list.vue +0 -257
- package/dist/templates/sample/classic-module/composables/index.ts +0 -2
- package/dist/templates/sample/classic-module/composables/useDetails/index.ts +0 -54
- package/dist/templates/sample/classic-module/composables/useList/index.ts +0 -62
- package/dist/templates/sample/classic-module/index.ts +0 -8
- package/dist/templates/sample/classic-module/locales/en.json +0 -67
- package/dist/templates/sample/classic-module/locales/index.ts +0 -2
- package/dist/templates/sample/classic-module/pages/details.vue +0 -238
- package/dist/templates/sample/classic-module/pages/index.ts +0 -2
- package/dist/templates/sample/classic-module/pages/list.vue +0 -300
- package/dist/templates/sample/overrides/main.ts +0 -52
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { computed, ref, ComputedRef, Ref } from "vue";
|
|
2
|
+
import { useAsync, useApiClient } from "@vc-shell/framework";
|
|
3
|
+
import { useI18n } from "vue-i18n";
|
|
4
|
+
|
|
5
|
+
// TODO: Replace with your actual API client imports
|
|
6
|
+
// Example: import { ProductsClient, IProduct, IProductSearchQuery, ProductSearchResult } from "@your-app/api/products";
|
|
7
|
+
|
|
8
|
+
// @ts-expect-error - Replace with your API types
|
|
9
|
+
interface I{{EntityName}}SearchQuery {
|
|
10
|
+
take?: number;
|
|
11
|
+
skip?: number;
|
|
12
|
+
keyword?: string;
|
|
13
|
+
sort?: string;
|
|
14
|
+
// Add your filter fields here
|
|
15
|
+
status?: string;
|
|
16
|
+
startDate?: Date;
|
|
17
|
+
endDate?: Date;
|
|
18
|
+
[key: string]: any;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// @ts-expect-error - Replace with your API types
|
|
22
|
+
interface I{{EntityName}} {
|
|
23
|
+
id?: string;
|
|
24
|
+
name?: string;
|
|
25
|
+
createdDate?: string;
|
|
26
|
+
[key: string]: any;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// @ts-expect-error - Replace with your search result type
|
|
30
|
+
interface {{EntityName}}SearchResult {
|
|
31
|
+
results?: I{{EntityName}}[];
|
|
32
|
+
totalCount?: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// @ts-expect-error - Replace with your API client
|
|
36
|
+
class {{EntityName}}Client {
|
|
37
|
+
// TODO: Replace these mock methods with your actual API client methods
|
|
38
|
+
async search{{EntityName}}s(query: I{{EntityName}}SearchQuery): Promise<{{EntityName}}SearchResult> {
|
|
39
|
+
throw new Error("Method not implemented. Replace with your actual API method.");
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface FilterState {
|
|
44
|
+
status: string[];
|
|
45
|
+
startDate?: string;
|
|
46
|
+
endDate?: string;
|
|
47
|
+
[key: string]: string[] | string | undefined;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface IUse{{EntityName}}List {
|
|
51
|
+
items: ComputedRef<I{{EntityName}}[]>;
|
|
52
|
+
totalCount: ComputedRef<number>;
|
|
53
|
+
pages: ComputedRef<number>;
|
|
54
|
+
currentPage: ComputedRef<number>;
|
|
55
|
+
searchQuery: Ref<I{{EntityName}}SearchQuery>;
|
|
56
|
+
load{{EntityName}}s: (query?: I{{EntityName}}SearchQuery) => Promise<void>;
|
|
57
|
+
loading: ComputedRef<boolean>;
|
|
58
|
+
statuses: ComputedRef<Array<{ value: string | undefined; displayValue: string | undefined }>>;
|
|
59
|
+
|
|
60
|
+
// Filters - staged/applied architecture
|
|
61
|
+
stagedFilters: Ref<FilterState>;
|
|
62
|
+
appliedFilters: Ref<FilterState>;
|
|
63
|
+
hasFilterChanges: ComputedRef<boolean>;
|
|
64
|
+
hasFiltersApplied: ComputedRef<boolean>;
|
|
65
|
+
activeFilterCount: ComputedRef<number>;
|
|
66
|
+
toggleFilter: (filterType: keyof FilterState, value: string, checked: boolean) => void;
|
|
67
|
+
applyFilters: () => Promise<void>;
|
|
68
|
+
resetFilters: () => Promise<void>;
|
|
69
|
+
resetSearch: () => Promise<void>;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface Use{{EntityName}}ListOptions {
|
|
73
|
+
pageSize?: number;
|
|
74
|
+
sort?: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Example status enum - customize for your entity
|
|
78
|
+
enum {{EntityName}}Status {
|
|
79
|
+
Active = "Active",
|
|
80
|
+
Inactive = "Inactive",
|
|
81
|
+
Pending = "Pending",
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function use{{EntityName}}List(options?: Use{{EntityName}}ListOptions): IUse{{EntityName}}List {
|
|
85
|
+
const { getApiClient } = useApiClient({{EntityName}}Client);
|
|
86
|
+
const { t } = useI18n({ useScope: "global" });
|
|
87
|
+
|
|
88
|
+
const pageSize = options?.pageSize || 20;
|
|
89
|
+
const searchQuery = ref<I{{EntityName}}SearchQuery>({
|
|
90
|
+
take: pageSize,
|
|
91
|
+
sort: options?.sort,
|
|
92
|
+
});
|
|
93
|
+
const searchResult = ref<{{EntityName}}SearchResult>();
|
|
94
|
+
|
|
95
|
+
const { action: load{{EntityName}}s, loading: loading{{EntityName}}s } = useAsync<I{{EntityName}}SearchQuery>(async (_query) => {
|
|
96
|
+
searchQuery.value = { ...searchQuery.value, ...(_query || {}) };
|
|
97
|
+
|
|
98
|
+
const apiClient = await getApiClient();
|
|
99
|
+
searchResult.value = await apiClient.search{{EntityName}}s(searchQuery.value);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Filter state with staged/applied architecture
|
|
103
|
+
const stagedFilters = ref<FilterState>({ status: [] });
|
|
104
|
+
const appliedFilters = ref<FilterState>({ status: [] });
|
|
105
|
+
|
|
106
|
+
const hasFilterChanges = computed((): boolean => {
|
|
107
|
+
// Deep comparison of filter arrays and values
|
|
108
|
+
const stagedStatus = [...stagedFilters.value.status].sort();
|
|
109
|
+
const appliedStatus = [...appliedFilters.value.status].sort();
|
|
110
|
+
|
|
111
|
+
return (
|
|
112
|
+
JSON.stringify(stagedStatus) !== JSON.stringify(appliedStatus) ||
|
|
113
|
+
stagedFilters.value.startDate !== appliedFilters.value.startDate ||
|
|
114
|
+
stagedFilters.value.endDate !== appliedFilters.value.endDate
|
|
115
|
+
);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const hasFiltersApplied = computed((): boolean => {
|
|
119
|
+
return (
|
|
120
|
+
appliedFilters.value.status.length > 0 ||
|
|
121
|
+
!!appliedFilters.value.startDate ||
|
|
122
|
+
!!appliedFilters.value.endDate
|
|
123
|
+
);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const activeFilterCount = computed((): number => {
|
|
127
|
+
let count = 0;
|
|
128
|
+
if (appliedFilters.value.status.length > 0) count++;
|
|
129
|
+
if (appliedFilters.value.startDate) count++;
|
|
130
|
+
if (appliedFilters.value.endDate) count++;
|
|
131
|
+
return count;
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
const toggleFilter = (filterType: keyof FilterState, value: string, checked: boolean) => {
|
|
135
|
+
if (filterType === 'status') {
|
|
136
|
+
const currentFilters = [...stagedFilters.value.status];
|
|
137
|
+
|
|
138
|
+
if (checked) {
|
|
139
|
+
// For status, use radio behavior - replace all with single value
|
|
140
|
+
stagedFilters.value = {
|
|
141
|
+
...stagedFilters.value,
|
|
142
|
+
status: [value],
|
|
143
|
+
};
|
|
144
|
+
} else {
|
|
145
|
+
stagedFilters.value = {
|
|
146
|
+
...stagedFilters.value,
|
|
147
|
+
status: currentFilters.filter((item) => item !== value),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
} else if (filterType === 'startDate' || filterType === 'endDate') {
|
|
151
|
+
stagedFilters.value = {
|
|
152
|
+
...stagedFilters.value,
|
|
153
|
+
[filterType]: value || undefined,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const applyFilters = async () => {
|
|
159
|
+
// Deep copy staged to applied
|
|
160
|
+
appliedFilters.value = {
|
|
161
|
+
status: [...stagedFilters.value.status],
|
|
162
|
+
startDate: stagedFilters.value.startDate,
|
|
163
|
+
endDate: stagedFilters.value.endDate,
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
// Convert to API query format with proper Date types
|
|
167
|
+
const queryWithFilters = {
|
|
168
|
+
...searchQuery.value,
|
|
169
|
+
status: appliedFilters.value.status.length > 0 ? appliedFilters.value.status[0] : undefined,
|
|
170
|
+
startDate: appliedFilters.value.startDate ? new Date(appliedFilters.value.startDate) : undefined,
|
|
171
|
+
endDate: appliedFilters.value.endDate ? new Date(appliedFilters.value.endDate) : undefined,
|
|
172
|
+
skip: 0, // Reset pagination
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
await load{{EntityName}}s(queryWithFilters);
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const resetFilters = async () => {
|
|
179
|
+
stagedFilters.value = { status: [] };
|
|
180
|
+
appliedFilters.value = { status: [] };
|
|
181
|
+
|
|
182
|
+
const queryWithoutFilters = {
|
|
183
|
+
...searchQuery.value,
|
|
184
|
+
status: undefined,
|
|
185
|
+
startDate: undefined,
|
|
186
|
+
endDate: undefined,
|
|
187
|
+
skip: 0,
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
await load{{EntityName}}s(queryWithoutFilters);
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const resetSearch = async () => {
|
|
194
|
+
stagedFilters.value = { status: [] };
|
|
195
|
+
appliedFilters.value = { status: [] };
|
|
196
|
+
|
|
197
|
+
const resetQuery = {
|
|
198
|
+
take: pageSize,
|
|
199
|
+
sort: options?.sort,
|
|
200
|
+
skip: 0,
|
|
201
|
+
keyword: "",
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
await load{{EntityName}}s(resetQuery);
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
// Computed properties
|
|
208
|
+
const items = computed(() => searchResult.value?.results || []);
|
|
209
|
+
const totalCount = computed(() => searchResult.value?.totalCount || 0);
|
|
210
|
+
const pages = computed(() => Math.ceil(totalCount.value / pageSize));
|
|
211
|
+
const currentPage = computed(() => Math.floor((searchQuery.value.skip || 0) / pageSize) + 1);
|
|
212
|
+
const loading = computed(() => loading{{EntityName}}s.value);
|
|
213
|
+
|
|
214
|
+
// Example statuses - customize for your entity
|
|
215
|
+
const statuses = computed(() => {
|
|
216
|
+
const statusEntries = Object.entries({{EntityName}}Status);
|
|
217
|
+
return statusEntries.map(([value, displayValue]) => ({
|
|
218
|
+
value,
|
|
219
|
+
displayValue: t(`{{MODULE_NAME_UPPERCASE}}.PAGES.LIST.TABLE.FILTER.STATUS.${displayValue}`),
|
|
220
|
+
}));
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
items,
|
|
225
|
+
totalCount,
|
|
226
|
+
pages,
|
|
227
|
+
currentPage,
|
|
228
|
+
searchQuery,
|
|
229
|
+
load{{EntityName}}s,
|
|
230
|
+
loading,
|
|
231
|
+
statuses,
|
|
232
|
+
|
|
233
|
+
// Filters
|
|
234
|
+
stagedFilters,
|
|
235
|
+
appliedFilters,
|
|
236
|
+
hasFilterChanges,
|
|
237
|
+
hasFiltersApplied,
|
|
238
|
+
activeFilterCount,
|
|
239
|
+
toggleFilter,
|
|
240
|
+
applyFilters,
|
|
241
|
+
resetFilters,
|
|
242
|
+
resetSearch,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as pages from "./pages";
|
|
2
|
+
import * as composables from "./composables";
|
|
3
|
+
import * as components from "./components";
|
|
4
|
+
import * as locales from "./locales";
|
|
5
|
+
import { createAppModule } from "@vc-shell/framework";
|
|
6
|
+
|
|
7
|
+
export default createAppModule(
|
|
8
|
+
pages,
|
|
9
|
+
locales,
|
|
10
|
+
composables,
|
|
11
|
+
components,
|
|
12
|
+
);
|
|
13
|
+
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"{{MODULE_NAME_UPPERCASE}}": {
|
|
3
|
+
"MENU": {
|
|
4
|
+
"TITLE": "{{ModuleName}}"
|
|
5
|
+
},
|
|
6
|
+
"PAGES": {
|
|
7
|
+
"LIST": {
|
|
8
|
+
"TITLE": "{{ModuleName}} List",
|
|
9
|
+
"SEARCH": {
|
|
10
|
+
"PLACEHOLDER": "Search {{entity_name_plural}}..."
|
|
11
|
+
},
|
|
12
|
+
"TABLE": {
|
|
13
|
+
"TOTALS": "{{ModuleName}}s",
|
|
14
|
+
"HEADER": {
|
|
15
|
+
"NAME": "Name",
|
|
16
|
+
"CREATED_DATE": "Created Date",
|
|
17
|
+
"STATUS": "Status"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"TOOLBAR": {
|
|
21
|
+
"REFRESH": "Refresh",
|
|
22
|
+
"ADD": "Add",
|
|
23
|
+
"DELETE": "Delete"
|
|
24
|
+
},
|
|
25
|
+
"EMPTY": {
|
|
26
|
+
"NO_ITEMS": "No items yet",
|
|
27
|
+
"ADD": "Add new"
|
|
28
|
+
},
|
|
29
|
+
"NOT_FOUND": {
|
|
30
|
+
"EMPTY": "No results found",
|
|
31
|
+
"RESET": "Reset search"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"DETAILS": {
|
|
35
|
+
"TITLE": "New {{EntityName}}",
|
|
36
|
+
"TITLE_SUFFIX": "Details",
|
|
37
|
+
"FORM": {
|
|
38
|
+
"INFO": {
|
|
39
|
+
"TITLE": "Information",
|
|
40
|
+
"NAME": "Name",
|
|
41
|
+
"NAME_PLACEHOLDER": "Enter name",
|
|
42
|
+
"CREATED_DATE": "Created Date"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"TOOLBAR": {
|
|
46
|
+
"SAVE": "Save",
|
|
47
|
+
"DELETE": "Delete"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"ALERTS": {
|
|
51
|
+
"DELETE": "Are you sure you want to delete this item?",
|
|
52
|
+
"DELETE_SELECTED_CONFIRMATION": {
|
|
53
|
+
"MESSAGE": "Are you sure you want to delete {count} item(s)?",
|
|
54
|
+
"ALL": "all {totalCount}"
|
|
55
|
+
},
|
|
56
|
+
"CLOSE_CONFIRMATION": "You have unsaved changes. Are you sure you want to close?",
|
|
57
|
+
"NOT_VALID": "Please fix validation errors"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"WIDGETS": {
|
|
61
|
+
"{{WIDGET_NAME_UPPERCASE}}": "{{WidgetName}}"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<VcWidget
|
|
3
|
+
v-loading:500="loading"
|
|
4
|
+
:value="count"
|
|
5
|
+
:title="$t('{{MODULE_NAME_UPPERCASE}}.WIDGETS.{{WIDGET_NAME_UPPERCASE}}.TITLE')"
|
|
6
|
+
icon="{{WIDGET_ICON}}"
|
|
7
|
+
@click="clickHandler"
|
|
8
|
+
>
|
|
9
|
+
</VcWidget>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script setup lang="ts">
|
|
13
|
+
import { VcWidget, useApiClient, useAsync, useBladeNavigation } from "@vc-shell/framework";
|
|
14
|
+
import { inject, onMounted, ref, toRef, Ref, watch } from "vue";
|
|
15
|
+
import { useRoute } from "vue-router";
|
|
16
|
+
|
|
17
|
+
// TODO: Replace with your actual API client imports and types
|
|
18
|
+
// Example: import { {{ParentEntity}}sClient, I{{ParentEntity}} } from "@your-app/api/{{parentEntityCamel}}s";
|
|
19
|
+
|
|
20
|
+
interface I{{ParentEntity}} {
|
|
21
|
+
id?: string;
|
|
22
|
+
name?: string;
|
|
23
|
+
[key: string]: any;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface Props {
|
|
27
|
+
item: I{{ParentEntity}};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const props = defineProps<Props>();
|
|
31
|
+
const route = useRoute();
|
|
32
|
+
|
|
33
|
+
// TODO: Initialize your API client here
|
|
34
|
+
// const { getApiClient } = useApiClient(YourApiClient);
|
|
35
|
+
// const client = getApiClient();
|
|
36
|
+
|
|
37
|
+
const { openBlade, resolveBladeByName } = useBladeNavigation();
|
|
38
|
+
|
|
39
|
+
const widgetOpened = ref(false);
|
|
40
|
+
const count = ref(0);
|
|
41
|
+
|
|
42
|
+
const item = toRef(props, "item");
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Handles widget click
|
|
46
|
+
* TODO: Implement your click behavior here
|
|
47
|
+
*/
|
|
48
|
+
function clickHandler() {
|
|
49
|
+
// Option 1: Open a related blade (uncomment and adjust blade name)
|
|
50
|
+
// if (!widgetOpened.value) {
|
|
51
|
+
// openBlade({
|
|
52
|
+
// blade: resolveBladeByName("YourBladeName"),
|
|
53
|
+
// param: item.value?.id,
|
|
54
|
+
// options: {
|
|
55
|
+
// {{parentEntityCamel}}: item.value,
|
|
56
|
+
// },
|
|
57
|
+
// onOpen() {
|
|
58
|
+
// widgetOpened.value = true;
|
|
59
|
+
// },
|
|
60
|
+
// onClose() {
|
|
61
|
+
// widgetOpened.value = false;
|
|
62
|
+
// },
|
|
63
|
+
// });
|
|
64
|
+
// }
|
|
65
|
+
|
|
66
|
+
// Option 2: Show notification (temporary placeholder)
|
|
67
|
+
console.log("Widget clicked", item.value);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Fetches count of related entities
|
|
72
|
+
* TODO: Implement your API call here
|
|
73
|
+
*/
|
|
74
|
+
const { loading, action: getCount } = useAsync<any, number | undefined>(async (query) => {
|
|
75
|
+
// TODO: Replace with your actual API call
|
|
76
|
+
// return (await client).searchYourEntities(query).then((res) => res.totalCount);
|
|
77
|
+
return 0; // Placeholder
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Updates the widget counter
|
|
82
|
+
*/
|
|
83
|
+
async function populateCounter() {
|
|
84
|
+
count.value =
|
|
85
|
+
(await getCount({
|
|
86
|
+
take: 0,
|
|
87
|
+
{{parentEntityCamel}}Id: item.value?.id,
|
|
88
|
+
})) ?? 0;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
onMounted(async () => {
|
|
92
|
+
if (item.value?.id) {
|
|
93
|
+
await populateCounter();
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
watch(
|
|
98
|
+
() => item.value?.id,
|
|
99
|
+
async (newVal) => {
|
|
100
|
+
if (newVal) {
|
|
101
|
+
await populateCounter();
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
{ deep: true },
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Exposes method for parent blade to update widget count
|
|
109
|
+
*/
|
|
110
|
+
defineExpose({
|
|
111
|
+
updateActiveWidgetCount: populateCounter,
|
|
112
|
+
});
|
|
113
|
+
</script>
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Form field type enum
|
|
3
|
+
*/
|
|
4
|
+
export declare enum FieldType {
|
|
5
|
+
Text = "text",
|
|
6
|
+
Textarea = "textarea",
|
|
7
|
+
Number = "number",
|
|
8
|
+
Date = "date",
|
|
9
|
+
Select = "select",
|
|
10
|
+
Checkbox = "checkbox",
|
|
11
|
+
RadioButton = "radio",
|
|
12
|
+
Switch = "switch",
|
|
13
|
+
Currency = "currency",
|
|
14
|
+
Editor = "editor",
|
|
15
|
+
Image = "image",
|
|
16
|
+
Multivalue = "multivalue",
|
|
17
|
+
Gallery = "gallery",
|
|
18
|
+
DataField = "data-field"
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Form field configuration
|
|
22
|
+
*/
|
|
23
|
+
export interface FormField {
|
|
24
|
+
name: string;
|
|
25
|
+
type: FieldType;
|
|
26
|
+
label?: string;
|
|
27
|
+
required: boolean;
|
|
28
|
+
placeholder?: string;
|
|
29
|
+
options?: string[];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Prompts user to add custom form fields interactively
|
|
33
|
+
*
|
|
34
|
+
* @returns Array of form field configurations
|
|
35
|
+
*/
|
|
36
|
+
export declare function promptFormFields(): Promise<FormField[]>;
|
|
37
|
+
/**
|
|
38
|
+
* Generates script setup additions for VcGallery
|
|
39
|
+
* Returns additional code to be inserted into <script setup>
|
|
40
|
+
*/
|
|
41
|
+
export declare function generateVcGalleryScriptAdditions(entityName: string): string;
|
|
42
|
+
/**
|
|
43
|
+
* Checks if form fields contain VcGallery
|
|
44
|
+
*/
|
|
45
|
+
export declare function hasGalleryField(fields: FormField[]): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Generates Vue template code for form fields
|
|
48
|
+
*
|
|
49
|
+
* @param fields - Array of form field configurations
|
|
50
|
+
* @param moduleNameUpperSnake - Module name in UPPER_SNAKE_CASE for i18n keys
|
|
51
|
+
* @returns Vue template string
|
|
52
|
+
*/
|
|
53
|
+
export declare function generateFormFieldsTemplate(fields: FormField[], moduleNameUpperSnake: string): string;
|
|
54
|
+
/**
|
|
55
|
+
* Generates locale entries for form fields
|
|
56
|
+
*
|
|
57
|
+
* @param fields - Array of form field configurations
|
|
58
|
+
* @returns Object with locale entries
|
|
59
|
+
*/
|
|
60
|
+
export declare function generateFormFieldsLocale(fields: FormField[]): Record<string, string>;
|
|
61
|
+
/**
|
|
62
|
+
* Generates default form fields (name + createdDate)
|
|
63
|
+
* Used when user doesn't customize the form
|
|
64
|
+
*
|
|
65
|
+
* @param moduleNameUpperSnake - Module name in UPPER_SNAKE_CASE for i18n keys
|
|
66
|
+
* @returns Vue template string with default fields
|
|
67
|
+
*/
|
|
68
|
+
export declare function generateDefaultFormFields(moduleNameUpperSnake: string): string;
|
|
69
|
+
//# sourceMappingURL=form-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-builder.d.ts","sourceRoot":"","sources":["../../src/utils/form-builder.ts"],"names":[],"mappings":"AAUA;;GAEG;AACH,oBAAY,SAAS;IACnB,IAAI,SAAS;IACb,QAAQ,aAAa;IACrB,MAAM,WAAW;IACjB,IAAI,SAAS;IACb,MAAM,WAAW;IACjB,QAAQ,aAAa;IACrB,WAAW,UAAU;IACrB,MAAM,WAAW;IACjB,QAAQ,aAAa;IACrB,MAAM,WAAW;IACjB,KAAK,UAAU;IACf,UAAU,eAAe;IACzB,OAAO,YAAY;IACnB,SAAS,eAAe;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAmG7D;AAqJD;;;GAGG;AACH,wBAAgB,gCAAgC,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAgD3E;AAoHD;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAE5D;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,oBAAoB,EAAE,MAAM,GAAG,MAAM,CAyCpG;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASpF;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,oBAAoB,EAAE,MAAM,GAAG,MAAM,CA4B9E"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formats a file using Prettier
|
|
3
|
+
* Automatically detects parser based on file extension and uses project's .prettierrc
|
|
4
|
+
*
|
|
5
|
+
* @param filePath - Path to file to format
|
|
6
|
+
* @returns Promise that resolves when formatting is complete
|
|
7
|
+
*/
|
|
8
|
+
export declare function formatFile(filePath: string): Promise<void>;
|
|
9
|
+
/**
|
|
10
|
+
* Formats multiple files
|
|
11
|
+
*
|
|
12
|
+
* @param filePaths - Array of file paths to format
|
|
13
|
+
* @returns Promise that resolves when all files are formatted
|
|
14
|
+
*/
|
|
15
|
+
export declare function formatFiles(filePaths: string[]): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Formats all files in a directory recursively
|
|
18
|
+
*
|
|
19
|
+
* @param dirPath - Directory path
|
|
20
|
+
* @param extensions - File extensions to format (default: .ts, .vue, .js, .json)
|
|
21
|
+
* @returns Promise that resolves when all files are formatted
|
|
22
|
+
*/
|
|
23
|
+
export declare function formatDirectory(dirPath: string, extensions?: string[]): Promise<void>;
|
|
24
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/utils/format.ts"],"names":[],"mappings":"AAKA;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDhE;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAIpE;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,UAAU,GAAE,MAAM,EAAoC,GACrD,OAAO,CAAC,IAAI,CAAC,CAaf"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration interface for entity naming conventions
|
|
3
|
+
* Used throughout the generator to maintain consistent naming
|
|
4
|
+
*/
|
|
5
|
+
export interface NamingConfig {
|
|
6
|
+
entitySingular: string;
|
|
7
|
+
entityPlural: string;
|
|
8
|
+
moduleName: string;
|
|
9
|
+
entitySingularPascal: string;
|
|
10
|
+
entitySingularCamel: string;
|
|
11
|
+
entitySingularKebab: string;
|
|
12
|
+
entityPluralPascal: string;
|
|
13
|
+
entityPluralCamel: string;
|
|
14
|
+
entityPluralKebab: string;
|
|
15
|
+
moduleNamePascal: string;
|
|
16
|
+
moduleNameUpperSnake: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Creates a complete naming configuration from user inputs
|
|
20
|
+
* Ensures valid JavaScript identifiers and consistent naming throughout generated code
|
|
21
|
+
* Uses pluralize library to automatically generate plural forms
|
|
22
|
+
*
|
|
23
|
+
* @param singular - Singular form of entity (e.g., "Offer", "Product")
|
|
24
|
+
* @param module - Module name (e.g., "offers", "products")
|
|
25
|
+
* @returns Complete naming configuration
|
|
26
|
+
*/
|
|
27
|
+
export declare function createNamingConfig(singular: string, module: string): NamingConfig;
|
|
28
|
+
/**
|
|
29
|
+
* Creates replacements map for template string interpolation
|
|
30
|
+
* Used to replace placeholders in template files with actual values
|
|
31
|
+
*
|
|
32
|
+
* @param config - Naming configuration
|
|
33
|
+
* @returns Map of template keys to values
|
|
34
|
+
*/
|
|
35
|
+
export declare function createReplacementsMap(config: NamingConfig): Record<string, string>;
|
|
36
|
+
/**
|
|
37
|
+
* Replaces all placeholders in template content with actual values
|
|
38
|
+
*
|
|
39
|
+
* @param content - Template content
|
|
40
|
+
* @param replacements - Map of placeholders to values
|
|
41
|
+
* @returns Content with replaced placeholders
|
|
42
|
+
*/
|
|
43
|
+
export declare function applyReplacements(content: string, replacements: Record<string, string>): string;
|
|
44
|
+
//# sourceMappingURL=naming.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"naming.d.ts","sourceRoot":"","sources":["../../src/utils/naming.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,MAAM,WAAW,YAAY;IAE3B,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IAGnB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAG5B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAG1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,CAwBjF;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAgBlF;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAM/F"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registers a new module in main.ts by adding import and .use() call
|
|
3
|
+
*
|
|
4
|
+
* @param cwd - Current working directory
|
|
5
|
+
* @param moduleName - Module name (e.g., "orders")
|
|
6
|
+
* @param moduleNamePascal - Module name in PascalCase (e.g., "Orders")
|
|
7
|
+
* @returns true if successful, false otherwise
|
|
8
|
+
*/
|
|
9
|
+
export declare function registerModuleInMainTs(cwd: string, moduleName: string, moduleNamePascal: string): Promise<boolean>;
|
|
10
|
+
/**
|
|
11
|
+
* Registers blades in pages/index.ts
|
|
12
|
+
*
|
|
13
|
+
* @param modulePath - Path to module directory
|
|
14
|
+
* @param bladeNames - Array of blade names to export
|
|
15
|
+
* @returns true if successful
|
|
16
|
+
*/
|
|
17
|
+
export declare function registerBladesInIndex(modulePath: string, bladeNames: Array<{
|
|
18
|
+
exportName: string;
|
|
19
|
+
fileName: string;
|
|
20
|
+
}>): Promise<boolean>;
|
|
21
|
+
//# sourceMappingURL=register-module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-module.d.ts","sourceRoot":"","sources":["../../src/utils/register-module.ts"],"names":[],"mappings":"AAKA;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,EAClB,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC,OAAO,CAAC,CAqFlB;AAED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,KAAK,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,GAC1D,OAAO,CAAC,OAAO,CAAC,CA2BlB"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { CLIArgs, CreateAppConfig } from '../cli/types.js';
|
|
2
|
+
|
|
3
|
+
interface CreateAppContext {
|
|
4
|
+
cwd: string;
|
|
5
|
+
args: CLIArgs;
|
|
6
|
+
}
|
|
7
|
+
export interface CreateAppResult {
|
|
8
|
+
root: string;
|
|
9
|
+
filesCreated: number;
|
|
10
|
+
config: CreateAppConfig;
|
|
11
|
+
}
|
|
12
|
+
export declare function createApplication(context: CreateAppContext): Promise<CreateAppResult>;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=create-app.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-app.d.ts","sourceRoot":"","sources":["../../src/workflows/create-app.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAOhE,UAAU,gBAAgB;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,OAAO,CAAC;CACf;AAQD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,eAAe,CAAC;CACzB;AAED,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAiD3F"}
|