1+ <template >
2+ <template v-if =" isCreating " >
3+ <td class =" px-4 py-2" ></td >
4+ <td v-for =" column in allVisibleColumns" :key =" column.name" class =" px-4 py-2" >
5+ <div v-if =" isEditableColumn(column)" class =" flex gap-2" >
6+ <ColumnValueInputWrapper
7+ ref =" input"
8+ class =" "
9+ :source =" 'create'"
10+ :column =" column"
11+ :currentValues =" formData"
12+ :mode =" 'create'"
13+ :columnOptions =" columnOptions"
14+ :unmasked =" unmasked"
15+ :setCurrentValue =" setCurrentValue"
16+ />
17+ </div >
18+ <div v-else ></div >
19+ </td >
20+ <td class =" px-4 pt-4 flex gap-2 items-center" >
21+ <button
22+ @click =" handleSave"
23+ class =" text-green-600 hover:text-green-800 disabled:opacity-50"
24+ :disabled =" saving || !isValid"
25+ >
26+ <IconCheckOutline v-if =" !saving" class =" w-5 h-5" />
27+ </button >
28+ <button
29+ @click =" cancelCreate"
30+ class =" text-red-600 hover:text-red-800"
31+ >
32+ <IconXOutline class =" w-5 h-5" />
33+ </button >
34+ </td >
35+ </template >
36+ <template v-else >
37+ <td :colspan =" visibleColumns.length + 1" class =" px-4 py-2" >
38+ <button
39+ @click =" startCreate"
40+ class =" w-full text-left text-sm text-gray-600 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-200"
41+ >
42+ <div class =" flex items-center" >
43+ <IconPlusOutline class =" w-4 h-4 mr-2" />
44+ {{ t('Add new record') }}
45+ </div >
46+ </button >
47+ </td >
48+ </template >
49+ </template >
50+
51+ <script setup>
52+ import { ref , computed } from ' vue' ;
53+ import { useCoreStore } from ' @/stores/core' ;
54+ import { callAdminForthApi } from ' @/utils' ;
55+ import { useI18n } from ' vue-i18n' ;
56+ import ColumnValueInputWrapper from ' @/components/ColumnValueInputWrapper.vue' ;
57+ import { IconCheckOutline , IconXOutline , IconPlusOutline , IconExclamationCircleSolid } from ' @iconify-prerendered/vue-flowbite' ;
58+ import { computedAsync } from ' @vueuse/core' ;
59+ import { useRouter } from ' vue-router' ;
60+ import { Tooltip } from ' @/afcl' ;
61+
62+ const props = defineProps ([' meta' ]);
63+ const emit = defineEmits ([' update:records' ]);
64+ const { t } = useI18n ();
65+ const router = useRouter ();
66+
67+ const coreStore = useCoreStore ();
68+ const isCreating = ref (false );
69+ const saving = ref (false );
70+ const formData = ref ({});
71+ const unmasked = ref ({});
72+ const invalidFields = ref ({});
73+ const emptyFields = ref ({});
74+
75+ console .log (" visibleColumns" , coreStore .resource .columns );
76+
77+
78+ // Determine which columns should be editable
79+ const visibleColumns = computed (() =>
80+ coreStore .resource .columns .filter (c => ! c .backendOnly && c .showIn ? .create !== false && ! c .primaryKey )
81+ );
82+
83+ console .log (" visibleColumns" , visibleColumns .value );
84+
85+ const allVisibleColumns = computed (() => {
86+ // Create a Map using column name as key to remove duplicates
87+ const columnsMap = new Map ();
88+
89+ // Add all visible columns
90+ coreStore .resource .columns .filter (c => c .showIn ? .list ).forEach (column => {
91+ columnsMap .set (column .label , column);
92+ });
93+
94+ // Add all editable columns
95+ visibleColumns .value .forEach (column => {
96+ columnsMap .set (column .label , column);
97+ });
98+
99+ // Convert Map values back to array
100+ return Array .from (columnsMap .values ());
101+ });
102+
103+ // Function to check if a column should be editable
104+ function isEditableColumn (column ) {
105+ return ! column .backendOnly && column .showIn ? .create !== false && ! column .primaryKey ;
106+ }
107+
108+ const columnOptions = computedAsync (async () => {
109+ return (await Promise .all (
110+ Object .values (coreStore .resource .columns ).map (async (column ) => {
111+ if (column .foreignResource ) {
112+ const list = await callAdminForthApi ({
113+ method: ' POST' ,
114+ path: ` /get_resource_foreign_data` ,
115+ body: {
116+ resourceId: coreStore .resource .resourceId ,
117+ column: column .name ,
118+ limit: 1000 ,
119+ offset: 0 ,
120+ },
121+ });
122+
123+ if (! column .required ? .create ) list .items .push ({ value: null , label: column .foreignResource .unsetLabel });
124+
125+ return { [column .name ]: list .items };
126+ }
127+ })
128+ )).reduce ((acc , val ) => Object .assign (acc, val), {})
129+ }, {});
130+
131+ const isValid = computed (() => {
132+ return ! Object .values (invalidFields .value ).some (invalid => invalid);
133+ });
134+
135+ function initializeFormData () {
136+ const newFormData = {};
137+ visibleColumns .value .forEach (column => {
138+ if (column .isArray ? .enabled ) {
139+ newFormData[column .name ] = []; // Initialize as empty array
140+ } else if (column .type === ' json' ) {
141+ newFormData[column .name ] = null ;
142+ } else if (column .suggestOnCreate !== undefined ) {
143+ newFormData[column .name ] = column .suggestOnCreate ;
144+ } else {
145+ newFormData[column .name ] = null ;
146+ }
147+ });
148+ formData .value = newFormData;
149+ invalidFields .value = {};
150+ emptyFields .value = {};
151+ }
152+
153+ function startCreate () {
154+ isCreating .value = true ;
155+ initializeFormData ();
156+ }
157+
158+ function cancelCreate () {
159+ isCreating .value = false ;
160+ formData .value = {};
161+ invalidFields .value = {};
162+ emptyFields .value = {};
163+ }
164+
165+ function setCurrentValue (field , value , arrayIndex = undefined ) {
166+ if (arrayIndex !== undefined ) {
167+ // Handle array updates
168+ if (! Array .isArray (formData .value [field])) {
169+ formData .value [field] = [];
170+ }
171+
172+ const column = coreStore .resource .columns .find (c => c .name === field);
173+ const newArray = [... formData .value [field]];
174+
175+ if (arrayIndex >= newArray .length ) {
176+ // When adding a new item, always add null
177+ newArray .push (null );
178+ } else {
179+ // For existing items, handle type conversion
180+ if (column? .isArray ? .itemType && [' integer' , ' float' , ' decimal' ].includes (column .isArray .itemType )) {
181+ newArray[arrayIndex] = value !== null && value !== ' ' ? + value : null ;
182+ } else {
183+ newArray[arrayIndex] = value;
184+ }
185+ }
186+
187+ // Assign the new array
188+ formData .value [field] = newArray;
189+ } else {
190+ // Handle non-array updates
191+ formData .value [field] = value;
192+ }
193+ }
194+
195+ async function handleSave () {
196+ if (! isValid .value ) return ;
197+
198+ saving .value = true ;
199+ try {
200+ const response = await callAdminForthApi ({
201+ method: ' POST' ,
202+ path: ` /plugin/${ props .meta .pluginInstanceId } /create` ,
203+ body: {
204+ resourceId: coreStore .resource .resourceId ,
205+ record: formData .value
206+ }
207+ });
208+
209+ if (response .error ) {
210+ adminforth .alert ({
211+ message: response .error ,
212+ variant: ' error'
213+ });
214+ return ;
215+ }
216+ cancelCreate ();
217+
218+ adminforth .alert ({
219+ message: t (' Record created successfully!' ),
220+ variant: ' success'
221+ });
222+ await adminforth .list .refresh ();
223+ } finally {
224+ saving .value = false ;
225+ }
226+ }
227+ < / script>
0 commit comments