diff --git a/navigation/index.js b/navigation/index.js
index 1da6349..101ebfa 100644
--- a/navigation/index.js
+++ b/navigation/index.js
@@ -122,4 +122,70 @@ export default [
],
meta: {},
},
+ // {
+ // header: "Pentadbiran",
+ // description: "Urus aplikasi anda",
+ // child: [
+ // {
+ // title: "Konfigurasi",
+ // icon: "ic:outline-settings",
+ // child: [
+ // {
+ // title: "Persekitaran",
+ // path: "/devtool/config/environment",
+ // },
+ // ],
+ // },
+ // {
+ // title: "Penyunting Menu",
+ // icon: "ci:menu-alt-03",
+ // path: "/devtool/menu-editor",
+ // child: [],
+ // },
+ // {
+ // title: "Urus Pengguna",
+ // path: "/devtool/user-management",
+ // icon: "ph:user-circle-gear",
+ // child: [
+ // {
+ // title: "Senarai Pengguna",
+ // path: "/devtool/user-management/user",
+ // icon: "",
+ // child: [],
+ // },
+ // {
+ // title: "Senarai Peranan",
+ // path: "/devtool/user-management/role",
+ // icon: "",
+ // child: [],
+ // },
+ // ],
+ // },
+ // {
+ // title: "Kandungan",
+ // icon: "mdi:pencil-ruler",
+ // child: [
+ // {
+ // title: "Penyunting",
+ // path: "/devtool/content-editor",
+ // },
+ // {
+ // title: "Templat",
+ // path: "/devtool/content-editor/template",
+ // },
+ // ],
+ // },
+ // {
+ // title: "Penyunting API",
+ // path: "/devtool/api-editor",
+ // icon: "material-symbols:api-rounded",
+ // child: [],
+ // },
+ // ],
+ // meta: {
+ // auth: {
+ // role: ["Developer"],
+ // },
+ // },
+ // },
];
diff --git a/pages/devtool/api-editor/code/index.vue b/pages/devtool/api-editor/code/index.vue
index 8989fe2..d7a2ee0 100644
--- a/pages/devtool/api-editor/code/index.vue
+++ b/pages/devtool/api-editor/code/index.vue
@@ -3,7 +3,7 @@
import { useThemeStore } from "~/stores/theme";
definePageMeta({
- title: "Penyunting Kod API",
+ title: "API Code Editor",
middleware: ["auth"],
requiresAuth: true,
});
@@ -31,6 +31,9 @@ const linterErrorText = ref("");
const linterErrorColumn = ref(0);
const linterErrorLine = ref(0);
+// Add new ref for loading state
+const isLinterChecking = ref(false);
+
// Get all themes
const themes = codemirrorThemes();
@@ -63,8 +66,8 @@ if (data.value.statusCode === 200) {
} else {
$swal
.fire({
- title: "Ralat",
- text: "API yang anda cuba sunting tidak dijumpai. Sila pilih API untuk disunting.",
+ title: "Error",
+ text: "The API you are trying to edit is not found. Please choose a API to edit.",
icon: "error",
confirmButtonText: "Ok",
})
@@ -92,25 +95,30 @@ async function formatCode() {
}
async function checkLinterVue() {
- // Call API to get the code
- const { data } = await useFetch("/api/devtool/api/linter", {
- initialCache: false,
- method: "POST",
- body: JSON.stringify({
- code: fileCode.value,
- }),
- });
+ isLinterChecking.value = true;
+ try {
+ // Call API to get the code
+ const { data } = await useFetch("/api/devtool/api/linter", {
+ initialCache: false,
+ method: "POST",
+ body: JSON.stringify({
+ code: fileCode.value,
+ }),
+ });
- if (data.value.statusCode === 200) {
- linterError.value = false;
- linterErrorText.value = "";
- linterErrorColumn.value = 0;
- linterErrorLine.value = 0;
- } else if (data.value.statusCode === 400) {
- linterError.value = true;
- linterErrorText.value = data.value.data.message;
- linterErrorColumn.value = data.value.data.column;
- linterErrorLine.value = data.value.data.line;
+ if (data.value.statusCode === 200) {
+ linterError.value = false;
+ linterErrorText.value = "";
+ linterErrorColumn.value = 0;
+ linterErrorLine.value = 0;
+ } else if (data.value.statusCode === 400) {
+ linterError.value = true;
+ linterErrorText.value = data.value.data.message;
+ linterErrorColumn.value = data.value.data.column;
+ linterErrorLine.value = data.value.data.line;
+ }
+ } finally {
+ isLinterChecking.value = false;
}
}
@@ -134,8 +142,8 @@ const saveCode = async () => {
if (linterError.value) {
$swal.fire({
- title: "Ralat",
- text: "Terdapat ralat dalam kod anda. Sila betulkannya sebelum menyimpan.",
+ title: "Error",
+ text: "There is an error in your code. Please fix it before saving.",
icon: "error",
confirmButtonText: "Ok",
});
@@ -153,8 +161,8 @@ const saveCode = async () => {
});
if (data.value.statusCode === 200) {
$swal.fire({
- title: "Berjaya",
- text: "Kod telah berjaya disimpan.",
+ title: "Success",
+ text: "The code has been saved successfully.",
icon: "success",
confirmButtonText: "Ok",
timer: 1000,
@@ -170,40 +178,49 @@ const saveCode = async () => {
-
{{
+ {{
error
}}
-
+
-
-
- Format Kod
-
-
- Simpan API
+
+
+
+ {{ isLinterChecking ? "Checking..." : "Save API" }}
+
-
+
-
Ralat ESLint
+
ESLint Error
{{ linterErrorText }}
- Baris: {{ linterErrorLine }} Lajur: {{ linterErrorColumn }}
+ Line: {{ linterErrorLine }} Column: {{ linterErrorColumn }}
@@ -216,7 +233,7 @@ const saveCode = async () => {
mode="javascript"
/>
-
+
diff --git a/pages/devtool/api-editor/index.vue b/pages/devtool/api-editor/index.vue
index 351fc62..e632c55 100644
--- a/pages/devtool/api-editor/index.vue
+++ b/pages/devtool/api-editor/index.vue
@@ -23,35 +23,34 @@ const showModalEditForm = ref({
const openModalAdd = () => {
showModalAddForm.value = {
apiURL: "",
+ method: "all",
};
showModalAdd.value = true;
};
-const openModalEdit = (url) => {
+const openModalEdit = (url, method = "all") => {
const apiURL = url.replace("/api/", "");
showModalEditForm.value = {
apiURL: apiURL,
oldApiURL: apiURL,
+ method: method,
};
showModalEdit.value = true;
};
-// Get api list from api folder
-const getApiList = async () => {
- const { data } = await useFetch("/api/devtool/api/list", {
- initialCache: false,
- });
- return data;
-};
-
-const apiList = await getApiList();
+const { data: apiList, refresh } = await useFetch("/api/devtool/api/list");
const searchApi = () => {
+ if (!apiList.value || !apiList.value.data) return [];
+
return apiList.value.data.filter((api) => {
- return api.name.toLowerCase().includes(searchText.value.toLowerCase());
+ return (
+ api.name.toLowerCase().includes(searchText.value.toLowerCase()) ||
+ api.url.toLowerCase().includes(searchText.value.toLowerCase())
+ );
});
};
@@ -78,17 +77,15 @@ const saveAddAPI = async () => {
if (data.value.statusCode === 200) {
nuxtApp.$swal.fire({
- title: "Berjaya",
- text: "Kod telah berjaya disimpan.",
+ title: "Success",
+ text: "The code has been saved successfully.",
icon: "success",
confirmButtonText: "Ok",
timer: 1000,
});
- setTimeout(() => {
- nuxtApp.$router.go(
- `/devtool/api-editor/code?path=/api${data.value.data.path}`
- );
- }, 1000);
+ // Close modal and refresh list
+ showModalAdd.value = false;
+ refresh();
}
};
@@ -105,31 +102,28 @@ const saveEditAPI = async () => {
if (data.value.statusCode === 200) {
nuxtApp.$swal.fire({
- title: "Berjaya",
- text: "Kod telah berjaya disimpan.",
+ title: "Success",
+ text: "The code has been saved successfully.",
icon: "success",
confirmButtonText: "Ok",
timer: 1000,
});
- setTimeout(() => {
- nuxtApp.$router.go(
- `/devtool/api-editor/code?path=/api/${showModalEditForm.value.apiURL}`
- );
- }, 1000);
+ // Close modal and refresh list
+ showModalEdit.value = false;
+ refresh();
}
};
const deleteAPI = async (apiURL) => {
nuxtApp.$swal
.fire({
- title: "Adakah anda pasti untuk memadam API ini?",
- text: "Anda tidak akan dapat memulihkan ini!",
+ title: "Are you sure to delete this API?",
+ text: "You won't be able to revert this!",
icon: "warning",
showCancelButton: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
- confirmButtonText: "Ya, padamkan!",
- cancelButtonText: "Batal",
+ confirmButtonText: "Yes, delete it!",
})
.then(async (result) => {
if (result.isConfirmed) {
@@ -144,15 +138,14 @@ const deleteAPI = async (apiURL) => {
if (data.value.statusCode === 200) {
nuxtApp.$swal.fire({
- title: "Berjaya",
- text: "Kod telah berjaya disimpan.",
+ title: "Success",
+ text: "The code has been saved successfully.",
icon: "success",
confirmButtonText: "Ok",
timer: 1000,
});
- setTimeout(() => {
- nuxtApp.$router.go();
- }, 1000);
+ // Refresh list after deletion
+ refresh();
}
}
});
@@ -165,13 +158,13 @@ const deleteAPI = async (apiURL) => {
Maklumat
+ >Info
- Halaman ini digunakan untuk mengedit API untuk bahagian pelayan. Anda boleh mengedit
- API dengan memilih API untuk diedit dari senarai kad di bawah.
+ This page is used to edit the api for the server side. You can edit
+ the api by choosing the api to edit from the card list below.
@@ -181,14 +174,14 @@ const deleteAPI = async (apiURL) => {
- Tambah API
+ Add API
@@ -215,7 +208,7 @@ const deleteAPI = async (apiURL) => {
name="material-symbols:code-blocks-outline-rounded"
class="mr-2"
/>
- Editor Kod
+ Code Editor
@@ -233,34 +226,102 @@ const deleteAPI = async (apiURL) => {
-
-
-
-
- /api/
+
+
+
+
+
+
+ /api/
+
+
+
+
+
+
+
+
+ Cancel
+
+
+
+ Save
+
-
-
+
+
+
-
-
-
-
- /api/
+
+
+
+
+
+
+ /api/
+
+
+
+
+
+
+
+
+ Cancel
+
+
+
+ Save
+
-
-
+
+
+
diff --git a/pages/devtool/code-playground/index.js b/pages/devtool/code-playground/index.js
new file mode 100644
index 0000000..fc98745
--- /dev/null
+++ b/pages/devtool/code-playground/index.js
@@ -0,0 +1,35 @@
+import RsAlert from "../../../components/RsAlert.vue";
+import RsBadge from "../../../components/RsBadge.vue";
+import RsButton from "../../../components/RsButton.vue";
+import RsCard from "../../../components/RsCard.vue";
+import RsCodeMirror from "../../../components/RsCodeMirror.vue";
+import RsCollapse from "../../../components/RsCollapse.vue";
+import RsCollapseItem from "../../../components/RsCollapseItem.vue";
+import RsDropdown from "../../../components/RsDropdown.vue";
+import RsDropdownItem from "../../../components/RsDropdownItem.vue";
+import RsFieldset from "../../../components/RsFieldset.vue";
+import RsModal from "../../../components/RsModal.vue";
+import RsProgressBar from "../../../components/RsProgressBar.vue";
+import RsTab from "../../../components/RsTab.vue";
+import RsTabItem from "../../../components/RsTabItem.vue";
+import RsTable from "../../../components/RsTable.vue";
+import RsWizard from "../../../components/RsWizard.vue";
+
+export {
+ RsAlert,
+ RsBadge,
+ RsButton,
+ RsCard,
+ RsCodeMirror,
+ RsCollapse,
+ RsCollapseItem,
+ RsDropdown,
+ RsDropdownItem,
+ RsFieldset,
+ RsModal,
+ RsProgressBar,
+ RsTab,
+ RsTabItem,
+ RsTable,
+ RsWizard,
+};
diff --git a/pages/devtool/code-playground/index.vue b/pages/devtool/code-playground/index.vue
new file mode 100644
index 0000000..f31e8e2
--- /dev/null
+++ b/pages/devtool/code-playground/index.vue
@@ -0,0 +1,422 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Reset Code
+
+
Code Playground
+
+
+
+
+
+
+
+
+
+
+
+
Preview
+
+
+
+ {{ size.name }}
+
+
+
+
+
+
+
+
+
+
+
+ Something went wrong. Please refer the error in the editor.
+
+
+
+
+
Waiting for code changes...
+
+
+
+
+
+
+
+
diff --git a/pages/devtool/config/application-log/index.vue b/pages/devtool/config/application-log/index.vue
index eeb3421..677f24b 100644
--- a/pages/devtool/config/application-log/index.vue
+++ b/pages/devtool/config/application-log/index.vue
@@ -1,11 +1,7 @@
-
-
+
+
+
+
diff --git a/pages/devtool/content-editor/code/index.vue b/pages/devtool/content-editor/code/index.vue
index ee47da3..223aea6 100644
--- a/pages/devtool/content-editor/code/index.vue
+++ b/pages/devtool/content-editor/code/index.vue
@@ -1,6 +1,6 @@
diff --git a/pages/devtool/menu-editor/index.vue b/pages/devtool/menu-editor/index.vue
index 7767a17..9666eee 100644
--- a/pages/devtool/menu-editor/index.vue
+++ b/pages/devtool/menu-editor/index.vue
@@ -14,7 +14,7 @@ const router = useRouter();
const getRoutes = router.getRoutes();
const getNavigation = Menu ? ref(Menu) : ref([]);
-const allMenus = [];
+const allMenus = reactive([]);
const showCode = ref(false);
let i = 1;
@@ -43,6 +43,16 @@ const showModalAddForm = ref({
path: "",
});
+const systemPages = [
+ "/devtool",
+ "/dashboard",
+ "/login",
+ "/logout",
+ "/register",
+ "/reset-password",
+ "/forgot-password",
+];
+
const kebabtoTitle = (str) => {
if (!str) return str;
return str
@@ -116,6 +126,10 @@ const openModalEdit = (menu) => {
};
const saveEditMenu = async () => {
+ // Clean the name and title ensure not spacing at the beginning or end
+ showModalEditForm.value.title = showModalEditForm.value.title.trim();
+ showModalEditForm.value.name = showModalEditForm.value.name.trim();
+
const res = await useFetch("/api/devtool/menu/edit", {
method: "POST",
initialCache: false,
@@ -133,6 +147,8 @@ const saveEditMenu = async () => {
const data = res.data.value;
if (data.statusCode === 200) {
+ showModalEdit.value = false;
+
nuxtApp.$swal.fire({
title: "Success",
text: data.message,
@@ -140,8 +156,8 @@ const saveEditMenu = async () => {
timer: 2000,
showConfirmButton: false,
});
- // refresh the page
- nuxtApp.$router.go();
+
+ window.location.reload();
}
};
@@ -154,6 +170,10 @@ const openModalAdd = () => {
};
const saveAddMenu = async () => {
+ // Clean the name and title ensure not spacing at the beginning or end
+ showModalAddForm.value.title = showModalAddForm.value.title.trim();
+ showModalAddForm.value.name = showModalAddForm.value.name.trim();
+
const res = await useFetch("/api/devtool/menu/add", {
method: "POST",
initialCache: false,
@@ -170,6 +190,8 @@ const saveAddMenu = async () => {
const data = res.data.value;
if (data.statusCode === 200) {
+ showModalAdd.value = false;
+
nuxtApp.$swal.fire({
title: "Success",
text: data.message,
@@ -177,8 +199,8 @@ const saveAddMenu = async () => {
timer: 2000,
showConfirmButton: false,
});
- // refresh the page
- nuxtApp.$router.go();
+
+ window.location.reload();
} else {
nuxtApp.$swal.fire({
title: "Error",
@@ -222,8 +244,7 @@ const deleteMenu = async (menu) => {
showConfirmButton: false,
});
- // refresh the page
- nuxtApp.$router.go();
+ window.location.reload();
}
}
});
@@ -319,9 +340,6 @@ const overwriteJsonFileLocal = async (menus) => {
timer: 2000,
showConfirmButton: false,
});
-
- // refresh the page
- nuxtApp.$router.go();
}
};
@@ -398,6 +416,21 @@ const addMenuFromList = () => {
//-----------------------------------------------------------------------------
//-------------------------SECOND CHILD TAB ITEM (END)-------------------------
//-----------------------------------------------------------------------------
+
+// Add this watcher after the showModalEditForm ref declaration
+watch(
+ () => showModalEditForm.value,
+ (newTitle) => {
+ showModalEditForm.value.name = newTitle.toLowerCase().replace(/\s+/g, "-");
+ }
+);
+
+watch(
+ () => showModalAddForm.value.title,
+ (newTitle) => {
+ showModalAddForm.value.name = newTitle.toLowerCase().replace(/\s+/g, "-");
+ }
+);
@@ -408,14 +441,14 @@ const addMenuFromList = () => {
Maklumat
+ >Info
- Halaman ini digunakan untuk mengedit menu laman web. Anda boleh
- menambah, mengedit, dan memadam item menu. Anda juga boleh mengubah
- susunan item menu dengan menyeret dan melepaskannya.
+ This page is used to edit the menu of the website. You can add, edit,
+ and delete menu items. You can also change the order of the menu items
+ by dragging and dropping them.
@@ -423,11 +456,11 @@ const addMenuFromList = () => {
-
+
- Tambah Menu
+ Add Menu
@@ -447,7 +480,7 @@ const addMenuFromList = () => {
>
{{ data.text }} {
-
-
-
+
-
-
-
+
- {{ showCode ? "Sembunyikan" : "Tunjukkan" }} Kod JSON
+ {{ showCode ? "Hide" : "Show" }} JSON Code
- Simpan Menu
+ Save Menu
@@ -510,7 +548,7 @@ const addMenuFromList = () => {
@@ -598,62 +636,110 @@ const addMenuFromList = () => {
>
-
-
-
-
-
- /
-
-
+
+
+
+
+
+
+
+
+ /
+
+
+
+
+
+ Cancel
+
+
+
+ Save Changes
+
+
+
+
+
+
-
-
-
-
-
-
- /
+
+
+
+
+
+
+
+
+ /
+
+
+
+
+
+ Cancel
+
+
+
+ Add Menu
+
-
-
+
+
+
+
diff --git a/pages/devtool/orm/index.vue b/pages/devtool/orm/index.vue
new file mode 100644
index 0000000..7ab6ae1
--- /dev/null
+++ b/pages/devtool/orm/index.vue
@@ -0,0 +1,169 @@
+
+
+
+
+
+
+
+
+
+ Info
+
+
+
+
+ This page is used to edit the ORM schema. You can add, edit, and
+ delete the model and its fields. The changes will be saved to the
+ database.
+
+
+
+
+
+
+
+
+
+
+ Add Table
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ tbl.name }}
+
+
+
+
+ {{ field }}
+
+
+
+
+
+
+
+ View Data
+
+
+
+
+
+
+
+ Modify
+
+
+
+
+ Delete
+
+
+
+ Cannot Modify System Table
+
+
+
+
+
+
+
+
diff --git a/pages/devtool/orm/table/create/index.vue b/pages/devtool/orm/table/create/index.vue
new file mode 100644
index 0000000..13bdac5
--- /dev/null
+++ b/pages/devtool/orm/table/create/index.vue
@@ -0,0 +1,315 @@
+
+
+
+
+
+
+
+
+
Create Table
+
+ Create a new table in the database.
+
+
+
+
+
+ Reset Table
+
+
+ Save
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/devtool/orm/table/modify/[table].vue b/pages/devtool/orm/table/modify/[table].vue
new file mode 100644
index 0000000..b2e8855
--- /dev/null
+++ b/pages/devtool/orm/table/modify/[table].vue
@@ -0,0 +1,360 @@
+
+
+
+
+
+
+
+
+
Modify Table
+
+ Modify a new table in the database.
+
+
+
+
+
+ Reset Table
+
+
+ Save
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/devtool/orm/view/[table]/index.vue b/pages/devtool/orm/view/[table]/index.vue
new file mode 100644
index 0000000..6d984cc
--- /dev/null
+++ b/pages/devtool/orm/view/[table]/index.vue
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
Table - {{ table }}
+
+ Below is the data of the table.
+
+
+
+
+ Open Prisma Studio
+
+
+
+
+
+
+
Data Not Found
+
+ There is no data available for this table.
+
+
+
+
+
+
diff --git a/pages/devtool/user-management/role-list.vue b/pages/devtool/user-management/role/index.vue
similarity index 85%
rename from pages/devtool/user-management/role-list.vue
rename to pages/devtool/user-management/role/index.vue
index 6fe9f0f..74212ef 100644
--- a/pages/devtool/user-management/role-list.vue
+++ b/pages/devtool/user-management/role/index.vue
@@ -1,6 +1,6 @@
-
-
diff --git a/pages/e-library/maklumat/[noSiri]/index.vue b/pages/e-library/maklumat/[noSiri]/index.vue
deleted file mode 100644
index 3c646e0..0000000
--- a/pages/e-library/maklumat/[noSiri]/index.vue
+++ /dev/null
@@ -1,83 +0,0 @@
-
-
-
Maklumat E-Library
-
- Loading...
- {{ error }}
-
-
No. Siri: {{ noSiri }}
-
-
-
Nama Pemohon: {{ permohonanData.namaPemohon }}
-
Pangkat Pemohon: {{ permohonanData.pangkatPemohon }}
-
- No. Pegawai Pemohon: {{ permohonanData.noPegawaiPemohon }}
-
-
-
-
Nama Penghantar: {{ permohonanData.namaPenghantar }}
-
- Pangkat Penghantar: {{ permohonanData.pangkatPenghantar }}
-
-
- No. Pegawai Penghantar:
- {{ permohonanData.noPegawaiPenghantar }}
-
-
-
-
-
- Ringkasan Kenyataan Kes:
- {{ permohonanData.ringkasanKenyataanKes }}
-
-
- No. Kertas Siasatan: {{ permohonanData.noKertasSiasatan }}
-
-
No. Laporan Polis: {{ permohonanData.noLaporanPolis }}
-
Tarikh Temujanji: {{ permohonanData.tarikhTemujanji }}
-
Slot Masa: {{ permohonanData.slotMasa }}
-
-
-
Senarai Barang
-
-
- {{ barang.jenisBarangDetailLabel }} - {{ barang.jenisBarangSiber }}
-
-
-
-
-
-
-
-
-
-
-
diff --git a/pages/kemaskini-daftar/kemaskini/[noSiri]/index.vue b/pages/kemaskini-daftar/kemaskini/[noSiri]/index.vue
deleted file mode 100644
index a5a3c1e..0000000
--- a/pages/kemaskini-daftar/kemaskini/[noSiri]/index.vue
+++ /dev/null
@@ -1,305 +0,0 @@
-
-
-
-
Kemaskini Permohonan
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Senarai Barang
-
-
-
- Jenis Barang
- Kuantiti
-
-
-
-
-
- {{
- barang.jenisBarangDetailLabel
- ? barang.jenisBarangDetailLabel
- : barang.jenisBarangDetail
- }}
-
-
- {{ barang.kuantitiBarang }}
-
-
-
-
-
Tiada barang ditambah
-
-
-
-
-
- Kembali
-
- Hantar
-
-
-
-
-
-
-
-
-
diff --git a/pages/kemaskini-daftar/kemaskini/batal/[noSiri]/index.vue b/pages/kemaskini-daftar/kemaskini/batal/[noSiri]/index.vue
deleted file mode 100644
index c291c5d..0000000
--- a/pages/kemaskini-daftar/kemaskini/batal/[noSiri]/index.vue
+++ /dev/null
@@ -1,158 +0,0 @@
-@ -1,157 +0,0 @@
-
-
-
-
Borang Akuan Penolakan Barang Kes
-
-
-
-
-
-
-
-
-
- Kembali
- Sah
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/pages/kemaskini-daftar/kemaskini/sah/[noSiri]/index.vue b/pages/kemaskini-daftar/kemaskini/sah/[noSiri]/index.vue
deleted file mode 100644
index 4dfd35b..0000000
--- a/pages/kemaskini-daftar/kemaskini/sah/[noSiri]/index.vue
+++ /dev/null
@@ -1,194 +0,0 @@
-
-
-
-
-
Borang Akuan Penerimaan Barang Kes
-
-
-
-
-
-
-
-
-
-
-
-
-
- Kembali
- Sah
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/pages/kemaskini-daftar/laporan/[reportID]/index.vue b/pages/kemaskini-daftar/laporan/[reportID]/index.vue
deleted file mode 100644
index e6def6a..0000000
--- a/pages/kemaskini-daftar/laporan/[reportID]/index.vue
+++ /dev/null
@@ -1,345 +0,0 @@
-
-
-
-
Laporan Bahan Bukti
-
- Jana PDF
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Butiran Pegawai
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Document Tambahan
-
-
-
-
-
-
-
-
-
-
-
- Kembali
- Hantar Laporan
-
-
-
-
-
-
-
-
-
diff --git a/pages/kemaskini-daftar/maklumat/[noSiri]/index.vue b/pages/kemaskini-daftar/maklumat/[noSiri]/index.vue
deleted file mode 100644
index 9cac5bb..0000000
--- a/pages/kemaskini-daftar/maklumat/[noSiri]/index.vue
+++ /dev/null
@@ -1,734 +0,0 @@
-
-
-
-
-
-
Status Semakan
-
- {{ statusSemakan }}
-
-
-
-
Status Penerimaan
-
- {{ statusPenerimaan }}
-
-
-
-
- Semak
- Terima
- Tolak
-
-
-
-
-
-
-
Pegawai Forensik Yang Terlibat
-
- Tambah Pegawai
-
-
-
-
-
- Pangkat
- Nama
- No Pegawai
- Tindakan
-
-
-
- {{ data.text }}
-
-
- {{ data.text }}
-
-
- {{ data.text }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Tidak ada pegawai forensik yang terlibat.
-
-
-
-
-
- Bahan Bukti
-
-
-
- No
- Jenis Barang
- Tag No.
- Keadaan
- Kuantiti
- Tindakan
-
-
-
- {{ data.text }}
-
-
- {{ data.text }}
-
-
- {{ data.text }}
-
-
- {{ data.text }}
-
-
-
-
-
-
-
-
-
Tidak ada bahan bukti yang terlibat.
-
-
-
-
-
-
-
- {{ editMode ? "Edit Pegawai Forensik" : "Tambah Pegawai Forensik" }}
-
-
-
-
-
-
-
- Tutup
- Simpan
-
-
-
-
-
-
-
-
- Semak Maklumat
-
-
-
-
-
-
-
-
-
-
-
- Batal
- Hantar
-
-
-
-
-
-
-
- Batal
- Hantar
-
-
-
-
-
-
-
-
-
-
-
- Terima Permohonan
-
-
-
-
-
-
-
-
-
-
- Batal
- Hantar
-
-
-
-
-
-
-
-
-
-
-
- Tolak Permohonan
-
-
-
-
-
-
- Batal
- Hantar
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/pages/kemaskini-daftar/senarai/index.vue b/pages/kemaskini-daftar/senarai/index.vue
deleted file mode 100644
index 50ca6c4..0000000
--- a/pages/kemaskini-daftar/senarai/index.vue
+++ /dev/null
@@ -1,149 +0,0 @@
-
-
-
-
Senarai Permohonan
-
-
-
-
-
-
- No
- No Siri
- Tarikh & Masa
- Status
- Butiran
-
-
-
- {{ data.text }}
-
-
- {{ data.text || "N/A" }}
-
-
- {{ data.text || "N/A" }}
-
-
-
- {{ data.text || "N/A" }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/pages/pengesanan-penyamaran/baru/index.vue b/pages/pengesanan-penyamaran/baru/index.vue
deleted file mode 100644
index a32b9f3..0000000
--- a/pages/pengesanan-penyamaran/baru/index.vue
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
Tambah Temujanji
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Kembali
- Hantar
-
-
-
-
-
-
-
diff --git a/pages/pengesanan-penyamaran/kemaskini/[kesID]/index.vue b/pages/pengesanan-penyamaran/kemaskini/[kesID]/index.vue
deleted file mode 100644
index 9a501ab..0000000
--- a/pages/pengesanan-penyamaran/kemaskini/[kesID]/index.vue
+++ /dev/null
@@ -1,300 +0,0 @@
-
-
-
-
Kemaskini Maklumat Pengesanan Penyamaran
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Kembali
- Kemaskini
-
-
-
-
-
-
-
-
-
diff --git a/pages/pengesanan-penyamaran/senarai/index.vue b/pages/pengesanan-penyamaran/senarai/index.vue
deleted file mode 100644
index 9fcf442..0000000
--- a/pages/pengesanan-penyamaran/senarai/index.vue
+++ /dev/null
@@ -1,152 +0,0 @@
-
-
-
-
-
Senarai Temujanji
-
- Tambah Temujanji
-
-
-
-
-
-
-
-
- {{ data.text }}
-
-
- {{ data.text || "N/A" }}
-
-
- {{ data.text || "N/A" }}
-
-
- {{ data.text || "N/A" }}
-
-
-
- {{ data.text || "N/A" }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/pages/permohonan-temujanji/baru/index.vue b/pages/permohonan-temujanji/baru/index.vue
deleted file mode 100644
index 90e2f06..0000000
--- a/pages/permohonan-temujanji/baru/index.vue
+++ /dev/null
@@ -1,520 +0,0 @@
-
-
-
-
Permohonan Baru
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Senarai Barang
-
-
-
- Jenis Barang
- Kuantiti
- Tindakan
-
-
-
-
-
- {{
- barang.jenisBarangDetailLabel
- ? barang.jenisBarangDetailLabel
- : barang.jenisBarangDetail
- }}
-
-
- {{ barang.kuantitiBarang }}
-
-
-
- Edit
-
-
- Buang
-
-
-
-
-
-
Tiada barang ditambah
-
- Tambah Barang
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Kembali
- Simpan
- Hantar
-
-
-
-
-
-
-
-
- {{ editingBarangIndex === null ? "Tambah" : "Edit" }} Barang
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Batal
- Simpan
-
-
-
-
-
-
-
-
-
-
diff --git a/pages/permohonan-temujanji/kemaskini/[noSiri]/index.vue b/pages/permohonan-temujanji/kemaskini/[noSiri]/index.vue
deleted file mode 100644
index 9b27559..0000000
--- a/pages/permohonan-temujanji/kemaskini/[noSiri]/index.vue
+++ /dev/null
@@ -1,557 +0,0 @@
-
-
-
-
Kemaskini Permohonan
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Senarai Barang
-
-
-
- Jenis Barang
- Kuantiti
- Tindakan
-
-
-
-
-
- {{
- barang.jenisBarangDetailLabel
- ? barang.jenisBarangDetailLabel
- : barang.jenisBarangDetail
- }}
-
-
- {{ barang.kuantitiBarang }}
-
-
-
- Edit
-
-
- Buang
-
-
-
-
-
-
Tiada barang ditambah
-
- Tambah Barang
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Kembali
- Kemaskini
- Hantar
-
-
-
-
-
-
-
-
- {{ editingBarangIndex === null ? "Tambah" : "Edit" }} Barang
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Batal
- Simpan
-
-
-
-
-
-
-
-
-
-
diff --git a/pages/permohonan-temujanji/senarai/index.vue b/pages/permohonan-temujanji/senarai/index.vue
deleted file mode 100644
index 19c8dab..0000000
--- a/pages/permohonan-temujanji/senarai/index.vue
+++ /dev/null
@@ -1,171 +0,0 @@
-
-
-
-
-
Senarai Permohonan
-
-
- Permohonan Baru
-
-
-
-
-
-
-
-
-
- No
- No Siri
- Tarikh & Masa
- Status
- Butiran
-
-
-
-
-
- {{ data.text }}
-
-
- {{ data.text || "N/A" }}
-
-
- {{ data.text || "N/A" }}
-
-
-
- {{ data.text || "N/A" }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{
- data.value.status === "Sah"
- ? "Permohonan telah disahkan"
- : "Permohonan telah dihantar"
- }}
-
-
-
-
-
-
-
-
diff --git a/pages/prototype/for-01/kemaskini-daftar/index.vue b/pages/prototype/for-01/kemaskini-daftar/index.vue
deleted file mode 100644
index 055a17c..0000000
--- a/pages/prototype/for-01/kemaskini-daftar/index.vue
+++ /dev/null
@@ -1,233 +0,0 @@
-
-
-
-
-
-
-
-
- Kemaskini Daftar FR2
-
-
-
-
-
- Pengesahan ID Kes
-
-
-
- Semak
-
-
-
-
-
-
Borang FR2
-
-
-
-
-
-
-
-
-
-
-
- Kemas Kini
-
-
-
-
-
-
-
-
diff --git a/pages/prototype/for-01/permohonan/index.vue b/pages/prototype/for-01/permohonan/index.vue
deleted file mode 100644
index e7ebeb7..0000000
--- a/pages/prototype/for-01/permohonan/index.vue
+++ /dev/null
@@ -1,334 +0,0 @@
-
-
-
-
-
-
-
-
-
-
- Butir Permohonan
-
-
-
-
-
Butir-butir Pemohon
-
-
- Nama: {{ applicantName }}
-
-
- Pangkat: {{ applicantRank }}
-
-
- Nombor Pegawai:
- {{ applicantOfficerNumber }}
-
-
-
-
-
-
- Butir-butir Penghantar Barang Kes
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Maklumat Kes
-
-
-
-
-
Maklumat Barang Kes
-
-
-
-
-
-
-
-
-
-
Maklumat Tambahan
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Adakah anda pasti untuk menghantar permohonan ini?
-
-
- Kembali
- Sahkan
-
-
-
-
-
-
-
-
-
-
- Kembali
- Sahkan
-
-
-
-
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index 0560b9e..3cfc6be 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -16,168 +16,16 @@ model audit {
auditCreatedDate DateTime? @db.DateTime(0)
}
-model document {
- documentID Int @id @default(autoincrement())
- userID Int?
- documentName String? @db.VarChar(255)
- documentURL String? @db.VarChar(255)
- documentType String? @db.VarChar(255)
- documentExtension String? @db.VarChar(255)
- imageMIMEType String? @db.VarChar(255)
- documentSize Int?
- documentStatus String? @default("ACTIVE") @db.VarChar(255)
- documentCreatedDate String? @db.VarChar(255)
- documentModifiedDate String? @db.VarChar(255)
- user user? @relation(fields: [userID], references: [userID], onDelete: NoAction, onUpdate: NoAction, map: "document_ibfk_1")
- permohonan_forensik_checking permohonan_forensik_checking[]
- report report[]
- report_doc_support report_doc_support[]
- temujanji_temujanji_gambarSubjekTodocument temujanji[] @relation("temujanji_gambarSubjekTodocument")
- temujanji_temujanji_gambarCapJariTodocument temujanji[] @relation("temujanji_gambarCapJariTodocument")
- temujanji_detail temujanji_detail[]
- temujanji_log temujanji_log[]
-
- @@index([userID], map: "userID")
-}
-
model lookup {
- lookupID Int @id @default(autoincrement())
- lookupOrder Int?
- lookupTitle String? @db.VarChar(255)
- lookupRefCode String? @db.VarChar(255)
- lookupValue String? @db.VarChar(255)
- lookupType String? @db.VarChar(255)
- lookupStatus String? @db.VarChar(255)
- lookupCreatedDate DateTime? @db.DateTime(0)
- lookupModifiedDate DateTime? @db.DateTime(0)
- permohonan permohonan[]
- permohonan_jenis_barang permohonan_jenis_barang[]
- permohonan_penolakan permohonan_penolakan[]
- report_report_dapatanTolookup report[] @relation("report_dapatanTolookup")
- report_report_jenis_barangTolookup report[] @relation("report_jenis_barangTolookup")
-}
-
-/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments
-model notifikasi {
- notifikasiID Int @id @default(autoincrement())
- penghantarID Int
- penerimaID Int
- body String @db.Text
- status Int
-}
-
-model pemohon {
- id Int @id @default(autoincrement())
- userID Int
- pangkat_pemohon String @db.VarChar(255)
- no_pegawai_pemohon String @db.VarChar(255)
- user user @relation(fields: [userID], references: [userID], onDelete: NoAction, onUpdate: NoAction, map: "pemohon_ibfk_1")
- permohonan permohonan[]
- temujanji temujanji[]
-
- @@index([userID], map: "userID")
-}
-
-model penghantar {
- id Int @id @default(autoincrement())
- nama_penghantar String @db.VarChar(255)
- pangkat_penghantar String @db.VarChar(255)
- no_pegawai_penghantar String @db.VarChar(255)
- permohonan permohonan[]
-}
-
-model permohonan {
- id Int @id @default(autoincrement())
- no_siri String @unique(map: "Permohonan_no_siri_key") @db.VarChar(255)
- pemohonID Int?
- penghantar_sama_dengan_pemohon Int?
- penghantarID Int?
- status_permohonan String @db.VarChar(255)
- ringkasan_kenyataan_kes String? @db.Text
- bilangan Int?
- jenis_barang Int?
- tanda_barang String? @db.VarChar(255)
- keadaan_barang String? @db.VarChar(255)
- kuantiti_barang Int?
- jenis_barang_details String? @db.Text
- no_laporan_polis String? @db.VarChar(255)
- no_kertas_siasatan String? @db.VarChar(255)
- tarikh_temujanji DateTime? @db.DateTime(0)
- slot_masa DateTime? @db.Time(0)
- create_at DateTime? @db.DateTime(0)
- modified_at DateTime? @db.DateTime(0)
- lookup lookup? @relation(fields: [jenis_barang], references: [lookupID], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_ibfk_3")
- pemohon pemohon? @relation(fields: [pemohonID], references: [id], onDelete: Cascade, onUpdate: Restrict, map: "permohonan_ibfk_2")
- penghantar penghantar? @relation(fields: [penghantarID], references: [id], onDelete: Cascade, onUpdate: Restrict, map: "permohonan_ibfk_1")
- permohonan_assign_forensik permohonan_assign_forensik[]
- permohonan_jenis_barang permohonan_jenis_barang[]
- permohonan_penerimaan permohonan_penerimaan?
- permohonan_semakan permohonan_semakan?
- report report[]
-
- @@index([pemohonID], map: "idx_pemohon")
- @@index([penghantarID], map: "idx_penghantar")
- @@index([jenis_barang], map: "jenis_barang")
-}
-
-model permohonan_assign_forensik {
- assignID Int @id @default(autoincrement())
- permohonanID Int
- pegawai_forensikID Int
- permohonan permohonan @relation(fields: [permohonanID], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_assign_forensik_ibfk_2")
- user user @relation(fields: [pegawai_forensikID], references: [userID], onUpdate: Restrict, map: "permohonan_assign_forensik_ibfk_3")
- permohonan_forensik_checking permohonan_forensik_checking[]
-
- @@index([pegawai_forensikID], map: "pegawai_forensikID")
- @@index([permohonanID], map: "permohonanID")
-}
-
-model permohonan_penerimaan {
- penerimaanID Int @id @default(autoincrement())
- permohonanID Int @unique(map: "permohonanID")
- peralatan_keadaan_baik Int
- pegawai_berkelayakan Int
- kaedah_dpt_dilakukan Int
- subkontrak_diperlukan Int
- tugasan_diterima Int
- ulasan_pegawai String? @db.Text
- create_at DateTime @db.DateTime(0)
- diterima_oleh Int
- permohonan permohonan @relation(fields: [permohonanID], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_penerimaan_ibfk_1")
- user user @relation(fields: [diterima_oleh], references: [userID], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_penerimaan_ibfk_2")
-
- @@index([diterima_oleh], map: "diterima_oleh")
-}
-
-model permohonan_penolakan {
- penolakanID Int @id @default(autoincrement())
- permohonanID Int @unique(map: "permohonanID")
- sebab_penolakan Int
- lain_sebab String? @db.VarChar(255)
- create_at DateTime? @db.DateTime(0)
- ditolak_oleh Int?
- lookup lookup @relation(fields: [sebab_penolakan], references: [lookupID], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_penolakan_ibfk_1")
- user user? @relation(fields: [ditolak_oleh], references: [userID], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_penolakan_ibfk_2")
-
- @@index([ditolak_oleh], map: "ditolak_oleh")
- @@index([sebab_penolakan], map: "sebab_penolakan")
-}
-
-model permohonan_semakan {
- semakanID Int @id @default(autoincrement())
- permohonanID Int @unique(map: "permohonanID")
- peralatan_keadaan_baik Int?
- pegawai_berkelayakan Int?
- kaedah_dpt_dilakukan Int?
- subkontrak_diperlukan Int?
- tugasan_diterima Int?
- ulasan_pegawai String? @db.Text
- create_at DateTime? @db.DateTime(0)
- disemak_oleh Int?
- permohonan permohonan @relation(fields: [permohonanID], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_semakan_ibfk_1")
- user user? @relation(fields: [disemak_oleh], references: [userID], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_semakan_ibfk_2")
-
- @@index([disemak_oleh], map: "disemak_oleh")
+ lookupID Int @id @default(autoincrement())
+ lookupOrder Int?
+ lookupTitle String? @db.VarChar(255)
+ lookupRefCode String? @db.VarChar(255)
+ lookupValue String? @db.VarChar(255)
+ lookupType String? @db.VarChar(255)
+ lookupStatus String? @db.VarChar(255)
+ lookupCreatedDate DateTime? @db.DateTime(0)
+ lookupModifiedDate DateTime? @db.DateTime(0)
}
model role {
@@ -190,30 +38,18 @@ model role {
userrole userrole[]
}
-model status {
- statusID Int @id @default(autoincrement())
- status_name String @db.VarChar(255)
-}
-
model user {
- userID Int @id @default(autoincrement())
- userSecretKey String? @db.VarChar(255)
- userUsername String? @db.VarChar(255)
- userPassword String? @db.VarChar(255)
- userFullName String? @db.VarChar(255)
- userEmail String? @db.VarChar(255)
- userPhone String? @db.VarChar(255)
- userStatus String? @db.VarChar(255)
- userCreatedDate DateTime? @db.DateTime(0)
- userModifiedDate DateTime? @db.DateTime(0)
- document document[]
- pemohon pemohon[]
- permohonan_approval permohonan_approval[]
- permohonan_assign_forensik permohonan_assign_forensik[]
- permohonan_penerimaan permohonan_penerimaan[]
- permohonan_penolakan permohonan_penolakan[]
- permohonan_semakan permohonan_semakan[]
- userrole userrole[]
+ userID Int @id @default(autoincrement())
+ userSecretKey String? @db.VarChar(255)
+ userUsername String? @db.VarChar(255)
+ userPassword String? @db.VarChar(255)
+ userFullName String? @db.VarChar(255)
+ userEmail String? @db.VarChar(255)
+ userPhone String? @db.VarChar(255)
+ userStatus String? @db.VarChar(255)
+ userCreatedDate DateTime? @db.DateTime(0)
+ userModifiedDate DateTime? @db.DateTime(0)
+ userrole userrole[]
}
model userrole {
@@ -228,191 +64,14 @@ model userrole {
@@index([userRoleUserID], map: "FK_userrole_user")
}
-/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments
-model permohonan_approval {
- approvalID Int @id @default(autoincrement())
- permohonanID Int
- approve_by Int
- approval_status Int
- ulasan String? @db.Text
- approval_date DateTime @db.DateTime(0)
- user user @relation(fields: [approve_by], references: [userID], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_approval_ibfk_1")
-
- @@index([approve_by], map: "userID")
-}
-
-/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments
-model permohonan_forensik_checking {
- checkingID Int @id @default(autoincrement())
- assignID Int
- gambar Int?
- ulasan String? @db.Text
- dapatan String @db.VarChar(255)
- create_at DateTime @db.DateTime(0)
- permohonan_assign_forensik permohonan_assign_forensik @relation(fields: [assignID], references: [assignID], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_forensik_checking_ibfk_1")
- document document? @relation(fields: [gambar], references: [documentID], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_forensik_checking_ibfk_2")
-
- @@index([assignID], map: "assignID")
- @@index([gambar], map: "gambar")
-}
-
-model permohonan_jenis_barang {
- barangID Int @id @default(autoincrement())
- permohonanID Int
- jenis_barang Int
- barang_status String @default("ACTIVE") @db.VarChar(255)
- lookup lookup @relation(fields: [jenis_barang], references: [lookupID], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_jenis_barang_ibfk_1")
- permohonan permohonan @relation(fields: [permohonanID], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_jenis_barang_ibfk_2")
-
- @@index([jenis_barang], map: "jenis_barang")
- @@index([permohonanID], map: "permohonanID")
-}
-
-model permohonan_tanda_barang {
- tandaID Int @id @default(autoincrement())
- tanda_name String @db.VarChar(255)
- tanda_status String @default("ACTIVE") @db.VarChar(255)
-}
-
-model report {
- reportID Int @id @default(autoincrement())
- permohonanID Int
- jenis_barang Int
- tanda_barang String? @db.VarChar(255)
- keadaan_barang String? @db.VarChar(255)
- kuantiti_barang Int?
- peralatan String? @db.VarChar(255)
- langkah_langkah String? @db.VarChar(255)
- gambarID Int?
- ulasan String? @db.Text
- dapatan Int?
- create_at DateTime? @db.DateTime(0)
- create_by Int
- document document? @relation(fields: [gambarID], references: [documentID], onDelete: NoAction, onUpdate: NoAction, map: "report_ibfk_2")
- lookup_report_dapatanTolookup lookup? @relation("report_dapatanTolookup", fields: [dapatan], references: [lookupID], onDelete: NoAction, onUpdate: NoAction, map: "report_ibfk_3")
- lookup_report_jenis_barangTolookup lookup @relation("report_jenis_barangTolookup", fields: [jenis_barang], references: [lookupID], onDelete: NoAction, onUpdate: NoAction, map: "report_ibfk_4")
- permohonan permohonan @relation(fields: [permohonanID], references: [id], onDelete: Cascade, onUpdate: Restrict, map: "report_ibfk_1")
- report_doc_support report_doc_support[]
-
- @@index([dapatan], map: "dapatan")
- @@index([gambarID], map: "gambarID")
- @@index([jenis_barang], map: "jenis_barang")
- @@index([permohonanID], map: "permohonanID")
-}
-
-model report_doc_support {
- report_attachID Int @id @default(autoincrement())
- reportID Int
- documentID Int
- document document @relation(fields: [documentID], references: [documentID], onDelete: NoAction, onUpdate: NoAction, map: "report_doc_support_ibfk_1")
- report report @relation(fields: [reportID], references: [reportID], onDelete: NoAction, onUpdate: NoAction, map: "report_doc_support_ibfk_2")
-
- @@index([documentID], map: "documentID")
- @@index([reportID], map: "reportID")
-}
-
-model temujanji {
- temujanjiID Int @id @default(autoincrement())
- noSiri String @db.VarChar(255)
- temujanjiDetailID Int?
- pemohonID Int
- jenisSemakan String @db.VarChar(255)
- tarikh DateTime @db.Date
- masa DateTime @db.Time(0)
- status String? @db.VarChar(255)
- gambarSubjek Int?
- gambarCapJari Int?
- create_at DateTime? @default(now()) @db.DateTime(0)
- modified_at DateTime? @db.DateTime(0)
- document_temujanji_gambarSubjekTodocument document? @relation("temujanji_gambarSubjekTodocument", fields: [gambarSubjek], references: [documentID], onDelete: NoAction, onUpdate: NoAction, map: "fk_gambarSubjek")
- document_temujanji_gambarCapJariTodocument document? @relation("temujanji_gambarCapJariTodocument", fields: [gambarCapJari], references: [documentID], onDelete: NoAction, onUpdate: NoAction, map: "fk_gambarCapJari")
- pemohon pemohon @relation(fields: [pemohonID], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "temujanji_ibfk_1")
- temujanji_detail temujanji_detail? @relation(fields: [temujanjiDetailID], references: [temujanjiDetailID], onDelete: NoAction, onUpdate: NoAction, map: "temujanji_ibfk_4")
- temujanji_log temujanji_log[]
-
- @@index([gambarCapJari], map: "idx_gambarCapJari")
- @@index([gambarSubjek], map: "idx_gambarSubjek")
- @@index([pemohonID], map: "idx_pemohonID")
- @@index([temujanjiDetailID], map: "temujanjiDetailID")
-}
-
-model temujanji_detail {
- temujanjiDetailID Int @id @default(autoincrement())
- negara String? @db.VarChar(255)
- namaPemilik String? @db.VarChar(255)
- noDokumen String? @db.VarChar(255)
- kewarganegaraan String? @db.VarChar(255)
- tarikhLahir DateTime? @db.Date
- jantina String? @db.VarChar(255)
- tarikhLuputDokumen DateTime? @db.Date
- skorPersamaanMuka Decimal? @db.Decimal(10, 2)
- skorPersamaanCapJari Decimal? @db.Decimal(10, 2)
- umur Int?
- tinggi Decimal? @db.Decimal(10, 2)
- warnaRambut String? @db.VarChar(255)
- bangsa String? @db.VarChar(255)
- etnik String? @db.VarChar(255)
- bentukKepala String? @db.VarChar(255)
- mata String? @db.VarChar(255)
- telinga String? @db.VarChar(255)
- hidung String? @db.VarChar(255)
- mulut String? @db.VarChar(255)
- parut String? @db.VarChar(255)
- sejarahPerjalanan String? @db.VarChar(255)
- persamaanTandaTangan String? @db.VarChar(255)
- pemeriksaanLain String? @db.VarChar(255)
- dapatan String? @db.VarChar(255)
- laporanSystemTdb Int?
- create_at DateTime? @db.DateTime(0)
- modified_at DateTime? @db.DateTime(0)
- temujanji temujanji[]
- document document? @relation(fields: [laporanSystemTdb], references: [documentID], onDelete: NoAction, onUpdate: NoAction, map: "temujanji_detail_ibfk_2")
-
- @@index([laporanSystemTdb], map: "idx_laporanSystemTdb")
-}
-
-model temujanji_log {
- temujanjiLogID Int @id @default(autoincrement())
- temujanjiID Int
- pemohonID Int?
- jenisSemakan String? @db.VarChar(255)
- tarikh DateTime? @db.Date
- masa DateTime? @db.Time(0)
- gambarSubjek Int?
- gambarCapJari Int?
- negara String? @db.VarChar(255)
- namaPemilik String? @db.VarChar(255)
- noDokumen String? @db.VarChar(255)
- kewarganegaraan String? @db.VarChar(255)
- tarikhLahir DateTime? @db.Date
- jantina String? @db.VarChar(255)
- tarikhLuputDokumen DateTime? @db.Date
- skorPersamaanMuka Decimal? @db.Decimal(10, 2)
- skorPersamaanCapJari Decimal? @db.Decimal(10, 2)
- umur Int?
- tinggi Decimal? @db.Decimal(10, 2)
- warnaRambut String? @db.VarChar(255)
- bangsa String? @db.VarChar(255)
- etnik String? @db.VarChar(255)
- bentukKepala String? @db.VarChar(255)
- mata String? @db.VarChar(255)
- telinga String? @db.VarChar(255)
- hidung String? @db.VarChar(255)
- mulut String? @db.VarChar(255)
- parut String? @db.VarChar(255)
- sejarahPerjalanan String? @db.VarChar(255)
- persamaanTandaTangan String? @db.VarChar(255)
- pemeriksaanLain String? @db.VarChar(255)
- dapatan String? @db.VarChar(255)
- laporanSystemTdb Int?
- create_at DateTime? @db.DateTime(0)
- modified_at DateTime? @db.DateTime(0)
- document document? @relation(fields: [laporanSystemTdb], references: [documentID], onDelete: NoAction, onUpdate: NoAction, map: "temujanji_log_ibfk_1")
- temujanji temujanji @relation(fields: [temujanjiID], references: [temujanjiID], onDelete: NoAction, onUpdate: NoAction, map: "temujanji_log_ibfk_2")
-
- @@index([gambarCapJari], map: "gambarCapJari")
- @@index([gambarSubjek], map: "gambarSubjek")
- @@index([laporanSystemTdb], map: "laporanSystemTdb")
- @@index([pemohonID], map: "pemohonID")
- @@index([temujanjiID], map: "temujanjiID")
+model customer {
+ cust_id Int @id @default(autoincrement())
+ cust_name String? @db.VarChar(255)
+ cust_username String? @db.VarChar(255)
+ cust_ic_number String? @db.VarChar(255)
+ cust_address String? @db.VarChar(255)
+ cust_dob DateTime? @db.Date
+ cust_gender String? @db.VarChar(255)
+ cust_status Int?
+ cust_created_datetime DateTime? @db.DateTime(0)
}
diff --git a/server/api/devtool/api/linter.js b/server/api/devtool/api/linter.js
index 3c2f35d..32572eb 100644
--- a/server/api/devtool/api/linter.js
+++ b/server/api/devtool/api/linter.js
@@ -14,40 +14,170 @@ export default defineEventHandler(async (event) => {
// run linter
const code = body.code;
+ const validateNitroCode = (code) => {
+ // Check if this is a server route file
+ const isServerRoute = code.includes("defineEventHandler");
- // enable babel-eslint parser and requireConfigFile: false
- // ignore code export default defineEventHandler((event) => {
+ if (isServerRoute) {
+ let lineNumber = 1;
- const eslint = new ESLint({
- overrideConfig: {
- parser: "@babel/eslint-parser",
- extends: ["@kiwicom"],
- parserOptions: {
- requireConfigFile: false,
- ecmaVersion: 2020,
- sourceType: "module",
+ // 1. Validate event handler structure
+ if (!code.includes("export default defineEventHandler")) {
+ throw {
+ message:
+ "Nitro route handlers must use 'export default defineEventHandler'",
+ line: 1,
+ column: 0,
+ };
+ }
+
+ // 2. Check for proper request handling
+ const hasRequestBody = code.includes("await readBody(event)");
+ const hasRequestQuery = code.includes("getQuery(event)");
+ const usesEventWithoutImport =
+ code.includes("event.") && !hasRequestBody && !hasRequestQuery;
+
+ if (usesEventWithoutImport) {
+ // Find the line where event is improperly used
+ const lines = code.split("\n");
+ for (let i = 0; i < lines.length; i++) {
+ if (
+ lines[i].includes("event.") &&
+ !lines[i].includes("readBody") &&
+ !lines[i].includes("getQuery")
+ ) {
+ throw {
+ message:
+ "Use 'readBody(event)' for POST data or 'getQuery(event)' for query parameters",
+ line: i + 1,
+ column: lines[i].indexOf("event."),
+ };
+ }
+ }
+ }
+
+ // 3. Validate response structure
+ const responseRegex = /return\s+{([^}]+)}/g;
+ let match;
+ let lastIndex = 0;
+
+ while ((match = responseRegex.exec(code)) !== null) {
+ lineNumber += (code.slice(lastIndex, match.index).match(/\n/g) || [])
+ .length;
+ lastIndex = match.index;
+
+ const responseContent = match[1];
+
+ // Check for required response properties
+ if (!responseContent.includes("statusCode")) {
+ throw {
+ message: "API responses must include a 'statusCode' property",
+ line: lineNumber,
+ column: match.index - code.lastIndexOf("\n", match.index),
+ };
+ }
+
+ // Validate status code usage
+ const statusMatch = responseContent.match(/statusCode:\s*(\d+)/);
+ if (statusMatch) {
+ const statusCode = parseInt(statusMatch[1]);
+ if (![200, 201, 400, 401, 403, 404, 500].includes(statusCode)) {
+ throw {
+ message: `Invalid status code: ${statusCode}. Use standard HTTP status codes.`,
+ line: lineNumber,
+ column: statusMatch.index,
+ };
+ }
+ }
+ }
+
+ // 4. Check error handling
+ if (code.includes("try") && !code.includes("catch")) {
+ throw {
+ message:
+ "Missing error handling. Add a catch block for try statements.",
+ line:
+ code.split("\n").findIndex((line) => line.includes("try")) + 1,
+ column: 0,
+ };
+ }
+
+ // 5. Validate async/await usage
+ const asyncLines = code.match(/async.*=>/g) || [];
+ const awaitLines = code.match(/await\s+/g) || [];
+
+ if (awaitLines.length > 0 && asyncLines.length === 0) {
+ throw {
+ message: "Using 'await' requires an async function",
+ line:
+ code.split("\n").findIndex((line) => line.includes("await")) + 1,
+ column: 0,
+ };
+ }
+
+ // // 6. Check for proper imports
+ // const requiredImports = new Set();
+ // if (hasRequestBody) requiredImports.add("readBody");
+ // if (hasRequestQuery) requiredImports.add("getQuery");
+
+ // const importLines = code.match(/import.*from/g) || [];
+ // requiredImports.forEach((imp) => {
+ // if (!importLines.some((line) => line.includes(imp))) {
+ // throw {
+ // message: `Missing import for '${imp}' utility`,
+ // line: 1,
+ // column: 0,
+ // };
+ // }
+ // });
+ }
+ };
+
+ try {
+ validateNitroCode(code);
+
+ const eslint = new ESLint({
+ overrideConfig: {
+ parser: "@babel/eslint-parser",
+ extends: ["@kiwicom"],
+ parserOptions: {
+ requireConfigFile: false,
+ ecmaVersion: 2020,
+ sourceType: "module",
+ },
},
- },
- useEslintrc: false,
- });
+ useEslintrc: false,
+ });
- const results = await eslint.lintText(code);
+ const results = await eslint.lintText(code);
- if (results[0].messages.length > 0) {
- const messages = results[0].messages[0];
+ if (results[0].messages.length > 0) {
+ const messages = results[0].messages[0];
+
+ if (messages.fatal === true) {
+ return {
+ statusCode: 400,
+ message: "Bad Linter Test",
+ data: messages,
+ };
+ }
- if (messages.fatal === true) {
return {
- statusCode: 400,
- message: "Bad Linter Test",
+ statusCode: 200,
+ message: "Good Linter test",
data: messages,
};
}
-
+ } catch (error) {
+ console.log(error);
return {
- statusCode: 200,
- message: "Good Linter test",
- data: messages,
+ statusCode: 400,
+ message: "Bad Linter Test",
+ data: {
+ message: error.message,
+ line: error.line || 1,
+ column: error.column || 0,
+ },
};
}
} catch (error) {
diff --git a/server/api/devtool/api/save.js b/server/api/devtool/api/save.js
index 0991e28..567ff59 100644
--- a/server/api/devtool/api/save.js
+++ b/server/api/devtool/api/save.js
@@ -8,8 +8,8 @@ export default defineEventHandler(async (event) => {
const codeDefault = `
export default defineEventHandler(async (event) => {
- // const query = await getQuery(event); || Get Params from URL
- // const body = await readBody(event); || Get Body Data
+ // const query = await getQuery(event); // Get Params from URL
+ // const body = await readBody(event); // Get Body Data
return {
statusCode: 200,
diff --git a/server/api/devtool/content/code/linter.js b/server/api/devtool/content/code/linter.js
index 01a52d4..60399ad 100644
--- a/server/api/devtool/content/code/linter.js
+++ b/server/api/devtool/content/code/linter.js
@@ -1,4 +1,3 @@
-// import esline vue
import { ESLint } from "eslint";
export default defineEventHandler(async (event) => {
@@ -12,9 +11,366 @@ export default defineEventHandler(async (event) => {
};
}
- // run linter
const code = body.code;
+ // Extract script and template content once
+ const scriptContent =
+ code.match(/
-
-
-
-
-
- `
- );
+ // Create template content
+ const templateContent = buildNuxtTemplate({
+ title: body.formData.title || body.formData.name,
+ name: body.formData.name,
+ });
+
+ // Write file with template
+ fs.writeFileSync(newFilePath, templateContent);
return {
statusCode: 200,
diff --git a/server/api/devtool/menu/delete.js b/server/api/devtool/menu/delete.js
index c3590fa..49e9e74 100644
--- a/server/api/devtool/menu/delete.js
+++ b/server/api/devtool/menu/delete.js
@@ -1,5 +1,6 @@
import fs from "fs";
import path from "path";
+import navigationData from "~/navigation";
export default defineEventHandler(async (event) => {
const body = await readBody(event);
@@ -11,15 +12,50 @@ export default defineEventHandler(async (event) => {
// Delete path
fs.rmSync(filePath, { recursive: true, force: true });
+ // Remove menu from navigation
+ removeMenuFromNavigation(body.filePath);
+
return {
statusCode: 200,
- message: "Menu successfully added!",
+ message: "Menu successfully deleted and removed from navigation!",
};
} catch (error) {
- console.log(error);
+ console.error(error);
return {
statusCode: 500,
message: error.message,
};
}
});
+
+function removeMenuFromNavigation(menuPath) {
+ const removeMenuItem = (items) => {
+ for (let i = 0; i < items.length; i++) {
+ if (items[i].path === menuPath) {
+ items.splice(i, 1);
+ return true;
+ }
+ if (items[i].child && items[i].child.length > 0) {
+ if (removeMenuItem(items[i].child)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+
+ navigationData.forEach((section) => {
+ if (section.child) {
+ removeMenuItem(section.child);
+ }
+ });
+
+ // Save updated navigation data
+ const navigationFilePath = path.join(process.cwd(), "navigation", "index.js");
+ const navigationContent = `export default ${JSON.stringify(
+ navigationData,
+ null,
+ 2
+ )};`;
+ fs.writeFileSync(navigationFilePath, navigationContent, "utf8");
+}
diff --git a/server/api/devtool/menu/edit.js b/server/api/devtool/menu/edit.js
index b026985..f459a38 100644
--- a/server/api/devtool/menu/edit.js
+++ b/server/api/devtool/menu/edit.js
@@ -4,76 +4,62 @@ import path from "path";
export default defineEventHandler(async (event) => {
const body = await readBody(event);
- if (body.filePath != body.formData.path) {
- try {
- // Check if last character is not slash
- if (body.filePath.slice(-1) != "/") {
- body.filePath = body.filePath + "/";
- }
+ // Normalize paths
+ const oldPath = body.filePath.endsWith("/")
+ ? body.filePath
+ : body.filePath + "/";
+ const newPath = body.formData.path.endsWith("/")
+ ? body.formData.path
+ : body.formData.path + "/";
- // Get old file path
- const oldFilePath = path.join(
- process.cwd() + "pages",
- body.filePath + "index.vue"
- );
+ // Get file paths
+ const oldFilePath = path.join(process.cwd(), "pages", oldPath, "index.vue");
+ const newFilePath = path.join(process.cwd(), "pages", newPath, "index.vue");
- // Check if last character is not a slash
- if (body.formData.path.slice(-1) != "/") {
- body.formData.path = body.formData.path + "/";
- }
+ try {
+ // Create template content
+ const templateContent = buildNuxtTemplate({
+ title: body.formData.title || body.formData.name,
+ name: body.formData.name,
+ });
- // Get new file path
- const newFilePath = path.join(
- process.cwd(),
- "pages",
- body.formData.path,
- "index.vue"
- );
-
- // Create the folder if doesn't exist
+ if (oldPath !== newPath) {
+ // Create the new folder if it doesn't exist
fs.mkdirSync(path.dirname(newFilePath), { recursive: true });
- // Create new file
- fs.writeFileSync(
- newFilePath,
- `
-
-
-
-
-
- `
- );
+ // Write the new file
+ fs.writeFileSync(newFilePath, templateContent);
- // copy old file to new file
- fs.copyFile(oldFilePath, newFilePath, (err) => {
- if (err) throw err;
- console.log("successfully copied old file to new file");
- });
+ // Delete the old file
+ fs.unlinkSync(oldFilePath);
- return {
- statusCode: 200,
- message: "Menu successfully saved",
- };
- } catch (error) {
- console.log(error);
- return {
- statusCode: 500,
- message: error,
- };
+ // Remove empty directories
+ let dirToCheck = path.dirname(oldFilePath);
+ while (dirToCheck !== path.join(process.cwd(), "pages")) {
+ if (fs.readdirSync(dirToCheck).length === 0) {
+ fs.rmdirSync(dirToCheck);
+ dirToCheck = path.dirname(dirToCheck);
+ } else {
+ break;
+ }
+ }
+ } else {
+ // Update existing file
+ fs.writeFileSync(oldFilePath, templateContent);
}
- // fs.writeFile;
+ return {
+ statusCode: 200,
+ message:
+ oldPath !== newPath
+ ? "Menu successfully moved and updated"
+ : "Menu successfully updated",
+ };
+ } catch (error) {
+ console.error(error);
+ return {
+ statusCode: 500,
+ message: error.message,
+ };
}
-
- return {
- statusCode: 200,
- message: "null",
- };
});
diff --git a/server/api/devtool/orm/data/get.get.js b/server/api/devtool/orm/data/get.get.js
new file mode 100644
index 0000000..0abbb4e
--- /dev/null
+++ b/server/api/devtool/orm/data/get.get.js
@@ -0,0 +1,36 @@
+export default defineEventHandler(async (event) => {
+ try {
+ const { tableName } = getQuery(event);
+
+ if (!tableName) {
+ return {
+ statusCode: 400,
+ message: "Table name is required",
+ };
+ }
+
+ // const JSONSchemaTable = getPrismaSchemaTable(tableName);
+ // console.log(JSONSchemaTable);
+
+ const getData = await prisma.$queryRawUnsafe(`SELECT * FROM ${tableName}`);
+
+ if (getData.length === 0) {
+ return {
+ statusCode: 404,
+ message: "Data not found",
+ };
+ }
+
+ return {
+ statusCode: 200,
+ message: "Data successfully fetched",
+ data: getData,
+ };
+ } catch (error) {
+ console.log(error.message);
+ return {
+ statusCode: 500,
+ message: "Internal Server Error",
+ };
+ }
+});
diff --git a/server/api/devtool/orm/schema.get.js b/server/api/devtool/orm/schema.get.js
new file mode 100644
index 0000000..51bb0a0
--- /dev/null
+++ b/server/api/devtool/orm/schema.get.js
@@ -0,0 +1,37 @@
+import fs from "fs";
+import path from "path";
+
+export default defineEventHandler(async (event) => {
+ try {
+ const { type } = getQuery(event);
+
+ if (!type) {
+ return {
+ statusCode: 400,
+ message: "Type is required",
+ };
+ }
+
+ if (type !== "table" && type !== "field") {
+ return {
+ statusCode: 400,
+ message: "Invalid type",
+ };
+ }
+
+ let schema = null;
+ if (type == "table") schema = getPrismaSchemaTable();
+
+ return {
+ statusCode: 200,
+ message: "Schema successfully fetched",
+ data: schema,
+ };
+ } catch (error) {
+ console.log(error.message);
+ return {
+ statusCode: 500,
+ message: "Internal Server Error",
+ };
+ }
+});
diff --git a/server/api/devtool/orm/studio.get.js b/server/api/devtool/orm/studio.get.js
new file mode 100644
index 0000000..8fa1b69
--- /dev/null
+++ b/server/api/devtool/orm/studio.get.js
@@ -0,0 +1,34 @@
+import { exec } from "node:child_process";
+
+export default defineEventHandler(async (event) => {
+ try {
+ let error = false;
+
+ // Run command yarn prisma studio
+ exec("npx prisma studio", (error, stdout, stderr) => {
+ if (error) {
+ console.error(`exec error: ${error}`);
+ error = true;
+ }
+ console.log(`stdout: ${stdout}`);
+ console.error(`stderr: ${stderr}`);
+ });
+
+ if (error)
+ return {
+ statusCode: 500,
+ message: "Internal Server Error",
+ };
+
+ return {
+ statusCode: 200,
+ message: "Prisma Studio successfully launched",
+ };
+ } catch (error) {
+ console.log(error.message);
+ return {
+ statusCode: 500,
+ message: "Internal Server Error",
+ };
+ }
+});
diff --git a/server/api/devtool/orm/table/config/configuration.json b/server/api/devtool/orm/table/config/configuration.json
new file mode 100644
index 0000000..f69f609
--- /dev/null
+++ b/server/api/devtool/orm/table/config/configuration.json
@@ -0,0 +1,106 @@
+{
+ "columnTypes": [
+ {
+ "group": "Numbers",
+ "options": [
+ "TINYINT",
+ "SMALLINT",
+ "MEDIUMINT",
+ "INT",
+ "BIGINT",
+ "DECIMAL",
+ "FLOAT",
+ "DOUBLE"
+ ]
+ },
+ {
+ "group": "Date and Time",
+ "options": ["DATE", "TIME", "DATETIME", "TIMESTAMP", "YEAR"]
+ },
+ {
+ "group": "Strings",
+ "options": [
+ "CHAR",
+ "VARCHAR",
+ "TINYTEXT",
+ "TEXT",
+ "MEDIUMTEXT",
+ "LONGTEXT",
+ "JSON"
+ ]
+ },
+ {
+ "group": "Lists",
+ "options": ["ENUM", "SET"]
+ },
+ {
+ "group": "Binary",
+ "options": [
+ "BIT",
+ "BINARY",
+ "VARBINARY",
+ "TINYBLOB",
+ "BLOB",
+ "MEDIUMBLOB",
+ "LONGBLOB"
+ ]
+ },
+ {
+ "group": "Geometry",
+ "options": [
+ "GEOMETRY",
+ "POINT",
+ "LINESTRING",
+ "POLYGON",
+ "MULTIPOINT",
+ "MULTILINESTRING",
+ "MULTIPOLYGON",
+ "GEOMETRYCOLLECTION"
+ ]
+ }
+ ],
+ "dataTypes": [
+ "",
+ "INT",
+ "TINYINT",
+ "SMALLINT",
+ "MEDIUMINT",
+ "BIGINT",
+ "DECIMAL",
+ "NUMERIC",
+ "FLOAT",
+ "DOUBLE",
+ "CHAR",
+ "VARCHAR",
+ "TEXT",
+ "ENUM",
+ "SET",
+ "BINARY",
+ "VARBINARY",
+ "BLOB",
+ "DATE",
+ "TIME",
+ "DATETIME",
+ "TIMESTAMP",
+ "YEAR",
+ "BOOL",
+ "BOOLEAN",
+ "JSON",
+ "JSONB",
+ "XML",
+ "UUID",
+ "GEOMETRY",
+ "POINT",
+ "LINESTRING",
+ "POLYGON"
+ ],
+ "tableField": [
+ "name",
+ "type",
+ "length",
+ "defaultValue",
+ "nullable",
+ "primaryKey",
+ "actions"
+ ]
+}
diff --git a/server/api/devtool/orm/table/config/index.get.js b/server/api/devtool/orm/table/config/index.get.js
new file mode 100644
index 0000000..c8943d9
--- /dev/null
+++ b/server/api/devtool/orm/table/config/index.get.js
@@ -0,0 +1,81 @@
+import fileConfig from "./configuration.json";
+
+export default defineEventHandler(async (event) => {
+ try {
+ // read configuration file if it exists and return error if it doesn't
+ if (!fileConfig) {
+ return {
+ statusCode: 404,
+ message: "Configuration file not found",
+ };
+ }
+
+ // Get all tables with primary key
+ const tables = await getAllTableWithPK();
+ if (!tables) {
+ return {
+ statusCode: 500,
+ message: "Please check your database connection",
+ };
+ }
+
+ // Remove columnTypes [{"group": "Foreign Keys", "options": [{"label": "TABLE_NAME (COLUMN_NAME)", "value": "TABLE_NAME"}]}] from fileconfig before appending
+ fileConfig.columnTypes = fileConfig.columnTypes.filter(
+ (columnType) => columnType.group !== "Foreign Keys"
+ );
+
+ // Append columnTypes from fileconfig with tables
+ fileConfig.columnTypes.push({
+ ...tables,
+ });
+
+ return {
+ statusCode: 200,
+ message: "Configuration file successfully loaded",
+ data: fileConfig,
+ };
+ } catch (error) {
+ console.log(error.message);
+ return {
+ statusCode: 500,
+ message: "Internal Server Error",
+ };
+ }
+});
+
+async function getAllTableWithPK() {
+ try {
+ const tables = await prisma.$queryRaw` SELECT
+ table_name,
+ column_name
+ FROM
+ information_schema.columns
+ WHERE table_schema = DATABASE()
+ AND column_key = 'PRI'`;
+
+ if (!tables) return false;
+
+ // Reformat to {group: "table_name", options: [{label: "TABLE_NAME (COLUMN_NAME)", value: "TABLE_NAME"}]}
+ const remapTables = tables.reduce((acc, table) => {
+ const group = "Foreign Keys";
+ const option = {
+ label: `${table.TABLE_NAME} (${table.COLUMN_NAME})`,
+ value: `[[${table.TABLE_NAME}]]`,
+ };
+ const existingGroup = acc.find((item) => item.group === group);
+
+ if (existingGroup) {
+ existingGroup.options.push(option);
+ } else {
+ acc.push({ group, options: [option] });
+ }
+
+ return acc;
+ }, []);
+
+ return remapTables[0];
+ } catch (error) {
+ console.log(error.message);
+ return false;
+ }
+}
diff --git a/server/api/devtool/orm/table/create/index.post.js b/server/api/devtool/orm/table/create/index.post.js
new file mode 100644
index 0000000..1298f73
--- /dev/null
+++ b/server/api/devtool/orm/table/create/index.post.js
@@ -0,0 +1,171 @@
+import { spawn } from "node:child_process";
+import { fileURLToPath } from "url";
+import { dirname, resolve } from "path";
+import os from "os";
+
+export default defineEventHandler(async (event) => {
+ try {
+ const { tableName, tableSchema, autoIncrementColumn } =
+ await readBody(event);
+
+ if (!tableName || !tableSchema) {
+ return {
+ statusCode: 400,
+ message: "Bad Request",
+ };
+ }
+
+ // Create Table
+ const isTableCreated = await createTable(
+ tableName,
+ tableSchema,
+ autoIncrementColumn
+ );
+
+ if (isTableCreated.statusCode !== 200)
+ return {
+ statusCode: 500,
+ message: isTableCreated.message,
+ };
+
+ // Run Prisma Command
+ const isPrismaCommandRun = await runPrismaCommand();
+ if (!isPrismaCommandRun)
+ return {
+ statusCode: 500,
+ message: "Prisma Command Failed",
+ };
+
+ return {
+ statusCode: 200,
+ message: "Table Created",
+ };
+ } catch (error) {
+ console.log(error);
+ return {
+ statusCode: 500,
+ message: "Internal Server Error",
+ };
+ }
+});
+
+async function createTable(tableName, tableSchema) {
+ try {
+ let rawSchema = ``;
+ for (let i = 0; i < tableSchema.length; i++) {
+ const column = tableSchema[i];
+
+ // Sanitize rawSchema
+ if (column.type.includes("[[") && column.type.includes("]]")) {
+ const FKTableName = column.type.replace("[[", "").replace("]]", "");
+ const primaryKey = await prisma.$queryRawUnsafe(
+ "SHOW COLUMNS from " + FKTableName + " where `Key` = 'PRI'"
+ );
+
+ rawSchema += `${column.name} INT NOT NULL, FOREIGN KEY (${column.name}) REFERENCES ${FKTableName}(${primaryKey[0].Field})`;
+ } else {
+ rawSchema += `${column.name}
+ ${column.type}${column.length ? "(" + column.length + ")" : ""}
+ ${column.defaultValue ? " DEFAULT " + column.defaultValue : ""}
+ ${column.nullable ? " NULL" : " NOT NULL "}
+ ${column.primaryKey ? " PRIMARY KEY AUTO_INCREMENT" : ""}`;
+ }
+
+ if (i < tableSchema.length - 1) rawSchema += ", ";
+ }
+
+ const sqlStatement = `CREATE TABLE ${tableName} (${rawSchema})`;
+ console.log(sqlStatement);
+
+ const createTable = await prisma.$queryRawUnsafe(sqlStatement);
+ if (!createTable)
+ return {
+ statusCode: 500,
+ message: "Table Creation Failed",
+ };
+
+ return {
+ statusCode: 200,
+ message: "Table Created",
+ };
+ } catch (error) {
+ console.log(error.message);
+
+ // Get Message
+ if (error.message.includes("already exists")) {
+ return {
+ statusCode: 500,
+ message: `Table '${tableName}' already exists!`,
+ };
+ }
+
+ if (error.message.includes("1064")) {
+ return {
+ statusCode: 500,
+ message: "Please ensure the SQL syntax is correct!",
+ };
+ }
+
+ return {
+ statusCode: 500,
+ message: "Table Creation Failed",
+ };
+ }
+}
+
+async function runPrismaCommand() {
+ try {
+ console.log("---------- Run Prisma Command ----------");
+
+ const __dirname = dirname(fileURLToPath(import.meta.url));
+ const directory = resolve(__dirname, "../..");
+
+ // Command to execute
+ const command = "npx prisma db pull && npx prisma generate";
+
+ // Determine the appropriate shell command based on the platform
+ let shellCommand;
+ let spawnOptions;
+ switch (os.platform()) {
+ case "win32":
+ shellCommand = `Start-Process cmd -ArgumentList '/c cd "${directory}" && ${command}' -Verb RunAs`;
+ spawnOptions = {
+ shell: "powershell.exe",
+ args: ["-Command", shellCommand],
+ };
+ break;
+ case "darwin":
+ case "linux":
+ shellCommand = `cd "${directory}" && ${command}`;
+ spawnOptions = {
+ shell: "sh",
+ args: ["-c", shellCommand],
+ };
+ break;
+ default:
+ console.error("Unsupported platform:", os.platform());
+ return false;
+ }
+
+ // Spawn child process using the appropriate shell command
+ const childProcess = spawn(spawnOptions.shell, spawnOptions.args, {
+ stdio: "inherit",
+ });
+
+ // Listen for child process events
+ return new Promise((resolve, reject) => {
+ childProcess.on("close", (code) => {
+ if (code === 0) {
+ console.log("Prisma commands executed successfully");
+ resolve(true);
+ } else {
+ console.error(`Child process exited with code ${code}`);
+ reject(new Error(`Child process exited with code ${code}`));
+ }
+ });
+ });
+ } catch (error) {
+ console.error("Error running Prisma commands:", error);
+ return false;
+ }
+}
diff --git a/server/api/devtool/orm/table/delete/[table]/index.delete.js b/server/api/devtool/orm/table/delete/[table]/index.delete.js
new file mode 100644
index 0000000..a50d716
--- /dev/null
+++ b/server/api/devtool/orm/table/delete/[table]/index.delete.js
@@ -0,0 +1,90 @@
+import { spawn } from "node:child_process";
+import { fileURLToPath } from "url";
+import { dirname, resolve } from "path";
+import os from "os";
+
+export default defineEventHandler(async (event) => {
+ const tableName = event.context.params.table;
+
+ try {
+ // Drop the table
+ await prisma.$executeRawUnsafe(`DROP TABLE IF EXISTS ${tableName}`);
+
+ // Run Prisma Command to update the schema
+ const isPrismaCommandRun = await runPrismaCommand();
+ if (!isPrismaCommandRun) {
+ return {
+ statusCode: 500,
+ message: "Prisma Command Failed after table deletion",
+ };
+ }
+
+ return {
+ statusCode: 200,
+ message: `Table '${tableName}' has been successfully deleted.`,
+ };
+ } catch (error) {
+ console.error("Error deleting table:", error);
+ return {
+ statusCode: 500,
+ message: `Failed to delete table '${tableName}'. Error: ${error.message}`,
+ };
+ }
+});
+
+async function runPrismaCommand() {
+ try {
+ console.log("---------- Run Prisma Command ----------");
+
+ const __dirname = dirname(fileURLToPath(import.meta.url));
+ const directory = resolve(__dirname, "../..");
+
+ // Command to execute
+ const command = "npx prisma db pull && npx prisma generate";
+
+ // Determine the appropriate shell command based on the platform
+ let shellCommand;
+ let spawnOptions;
+ switch (os.platform()) {
+ case "win32":
+ shellCommand = `Start-Process cmd -ArgumentList '/c cd "${directory}" && ${command}' -Verb RunAs`;
+ spawnOptions = {
+ shell: "powershell.exe",
+ args: ["-Command", shellCommand],
+ };
+ break;
+ case "darwin":
+ case "linux":
+ shellCommand = `cd "${directory}" && ${command}`;
+ spawnOptions = {
+ shell: "sh",
+ args: ["-c", shellCommand],
+ };
+ break;
+ default:
+ console.error("Unsupported platform:", os.platform());
+ return false;
+ }
+
+ // Spawn child process using the appropriate shell command
+ const childProcess = spawn(spawnOptions.shell, spawnOptions.args, {
+ stdio: "inherit",
+ });
+
+ // Listen for child process events
+ return new Promise((resolve, reject) => {
+ childProcess.on("close", (code) => {
+ if (code === 0) {
+ console.log("Prisma commands executed successfully");
+ resolve(true);
+ } else {
+ console.error(`Child process exited with code ${code}`);
+ reject(new Error(`Child process exited with code ${code}`));
+ }
+ });
+ });
+ } catch (error) {
+ console.error("Error running Prisma commands:", error);
+ return false;
+ }
+}
diff --git a/server/api/devtool/orm/table/modify/get.get.js b/server/api/devtool/orm/table/modify/get.get.js
new file mode 100644
index 0000000..358e4c0
--- /dev/null
+++ b/server/api/devtool/orm/table/modify/get.get.js
@@ -0,0 +1,113 @@
+export default defineEventHandler(async (event) => {
+ try {
+ const { tableName } = getQuery(event);
+
+ if (!tableName) {
+ return {
+ statusCode: 400,
+ message: "Table name is required",
+ };
+ }
+
+ const result = await prisma.$queryRaw`SELECT DATABASE() AS db_name`;
+ // console.log(result[0].db_name);
+
+ if (result.length === 0) {
+ return {
+ statusCode: 500,
+ message: "Please check your database connection",
+ };
+ }
+
+ let sqlRaw = ` SELECT
+ c.COLUMN_NAME,
+ c.DATA_TYPE,
+ c.CHARACTER_MAXIMUM_LENGTH,
+ c.COLUMN_DEFAULT,
+ c.IS_NULLABLE,
+ c.COLUMN_KEY,
+ kcu.REFERENCED_TABLE_NAME,
+ kcu.REFERENCED_COLUMN_NAME
+ FROM
+ INFORMATION_SCHEMA.COLUMNS c
+ LEFT JOIN
+ INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu ON
+ c.TABLE_SCHEMA = kcu.TABLE_SCHEMA AND
+ c.TABLE_NAME = kcu.TABLE_NAME AND
+ c.COLUMN_NAME = kcu.COLUMN_NAME
+ WHERE
+ c.TABLE_SCHEMA = '${result[0].db_name}' AND
+ c.TABLE_NAME = '${tableName}';`;
+
+ // console.log(sqlRaw);
+
+ const getTableDetails = await prisma.$queryRawUnsafe(sqlRaw);
+ // console.log(getTableDetails);
+
+ /*
+ [{
+ "actions": "",
+ "defaultValue": "",
+ "length": "",
+ "name": "PID",
+ "nullable": "",
+ "primaryKey": true,
+ "type": "INT"
+ },
+ {
+ "actions": "",
+ "defaultValue": "",
+ "length": "",
+ "name": "Pproduct",
+ "nullable": true,
+ "primaryKey": "",
+ "type": "VARCHAR"
+ },
+ {
+ "actions": "",
+ "defaultValue": "",
+ "length": "",
+ "name": "userID",
+ "nullable": "",
+ "primaryKey": "",
+ "type": "[[user]]"
+ }]
+ */
+
+ let tableDetailsData = [];
+
+ // Loop through the result and convert bigInt to number
+ for (let i = 0; i < getTableDetails.length; i++) {
+ const table = getTableDetails[i];
+
+ tableDetailsData.push({
+ name: table.COLUMN_NAME,
+ type: table.REFERENCED_TABLE_NAME
+ ? `[[${table.REFERENCED_TABLE_NAME}]]`
+ : table.DATA_TYPE.toUpperCase(),
+ length: bigIntToNumber(table.CHARACTER_MAXIMUM_LENGTH),
+ defaultValue: table.COLUMN_DEFAULT,
+ nullable: table.IS_NULLABLE === "YES",
+ primaryKey: table.COLUMN_KEY === "PRI",
+ actions: {},
+ });
+ }
+
+ return {
+ statusCode: 200,
+ message: "Success",
+ data: tableDetailsData,
+ };
+ } catch (error) {
+ console.log(error.message);
+ return {
+ statusCode: 500,
+ message: "Internal Server Error",
+ };
+ }
+});
+
+function bigIntToNumber(bigInt) {
+ if (bigInt === null) return null;
+ return Number(bigInt.toString());
+}
diff --git a/server/api/devtool/orm/table/modify/index.post.js b/server/api/devtool/orm/table/modify/index.post.js
new file mode 100644
index 0000000..81587f1
--- /dev/null
+++ b/server/api/devtool/orm/table/modify/index.post.js
@@ -0,0 +1,191 @@
+import { spawn } from "node:child_process";
+import { fileURLToPath } from "url";
+import { dirname, resolve } from "path";
+import os from "os";
+
+export default defineEventHandler(async (event) => {
+ try {
+ const { tableName, tableSchema, autoIncrementColumn } =
+ await readBody(event);
+
+ if (!tableName || !tableSchema) {
+ return {
+ statusCode: 400,
+ message: "Bad Request",
+ };
+ }
+
+ // Get existing table structure
+ const existingColumns = await prisma.$queryRaw`
+ SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_KEY
+ FROM INFORMATION_SCHEMA.COLUMNS
+ WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ${tableName}
+ `;
+
+ // Compare and modify table structure
+ for (const column of tableSchema) {
+ const existingColumn = existingColumns.find(
+ (c) => c.COLUMN_NAME === column.name
+ );
+
+ if (existingColumn) {
+ // Modify existing column
+ await modifyColumn(tableName, column, existingColumn);
+ } else {
+ // Add new column
+ await addColumn(tableName, column);
+ }
+ }
+
+ // Remove columns that are not in the new schema
+ for (const existingColumn of existingColumns) {
+ if (!tableSchema.find((c) => c.name === existingColumn.COLUMN_NAME)) {
+ await removeColumn(tableName, existingColumn.COLUMN_NAME);
+ }
+ }
+
+ // Update auto-increment column if necessary
+ if (autoIncrementColumn) {
+ await updateAutoIncrement(tableName, autoIncrementColumn);
+ }
+
+ // Run Prisma Command to update the schema
+ const isPrismaCommandRun = await runPrismaCommand();
+ if (!isPrismaCommandRun) {
+ return {
+ statusCode: 500,
+ message: "Prisma Command Failed",
+ };
+ }
+
+ return {
+ statusCode: 200,
+ message: "Table modified successfully",
+ };
+ } catch (error) {
+ console.error(error);
+ return {
+ statusCode: 500,
+ message: "Internal Server Error",
+ };
+ }
+});
+
+async function modifyColumn(tableName, newColumn, existingColumn) {
+ let alterStatement = `ALTER TABLE ${tableName} MODIFY COLUMN ${newColumn.name} ${newColumn.type}`;
+
+ if (newColumn.length) {
+ alterStatement += `(${newColumn.length})`;
+ }
+
+ alterStatement += newColumn.nullable ? " NULL" : " NOT NULL";
+
+ if (newColumn.defaultValue) {
+ alterStatement += ` DEFAULT ${newColumn.defaultValue}`;
+ }
+
+ await prisma.$executeRawUnsafe(alterStatement);
+}
+
+async function addColumn(tableName, column) {
+ let alterStatement = `ALTER TABLE ${tableName} ADD COLUMN ${column.name} ${column.type}`;
+
+ if (column.length) {
+ alterStatement += `(${column.length})`;
+ }
+
+ alterStatement += column.nullable ? " NULL" : " NOT NULL";
+
+ if (column.defaultValue) {
+ alterStatement += ` DEFAULT ${column.defaultValue}`;
+ }
+
+ await prisma.$executeRawUnsafe(alterStatement);
+}
+
+async function removeColumn(tableName, columnName) {
+ await prisma.$executeRawUnsafe(
+ `ALTER TABLE ${tableName} DROP COLUMN ${columnName}`
+ );
+}
+
+async function updateAutoIncrement(tableName, autoIncrementColumn) {
+ await prisma.$executeRawUnsafe(
+ `ALTER TABLE ${tableName} MODIFY ${autoIncrementColumn} INT AUTO_INCREMENT`
+ );
+}
+
+async function runPrismaCommand(retries = 3) {
+ try {
+ console.log("---------- Run Prisma Command ----------");
+
+ const __dirname = dirname(fileURLToPath(import.meta.url));
+ const directory = resolve(__dirname, "../..");
+
+ // Command to execute
+ const command = "npx prisma db pull && npx prisma generate";
+
+ // Determine the appropriate shell command based on the platform
+ let shellCommand;
+ let spawnOptions;
+ switch (os.platform()) {
+ case "win32":
+ shellCommand = `Start-Process cmd -ArgumentList '/c cd "${directory}" && ${command}' -Verb RunAs`;
+ spawnOptions = {
+ shell: "powershell.exe",
+ args: ["-Command", shellCommand],
+ };
+ break;
+ case "darwin":
+ case "linux":
+ shellCommand = `cd "${directory}" && ${command}`;
+ spawnOptions = {
+ shell: "sh",
+ args: ["-c", shellCommand],
+ };
+ break;
+ default:
+ console.error("Unsupported platform:", os.platform());
+ return false;
+ }
+
+ // Spawn child process using the appropriate shell command
+ const childProcess = spawn(spawnOptions.shell, spawnOptions.args, {
+ stdio: "inherit",
+ });
+
+ // Listen for child process events
+ return new Promise((resolve, reject) => {
+ childProcess.on("close", (code) => {
+ if (code === 0) {
+ console.log("Prisma commands executed successfully");
+ resolve(true);
+ } else {
+ console.error(`Child process exited with code ${code}`);
+ reject(new Error(`Child process exited with code ${code}`));
+ }
+ });
+ });
+ } catch (error) {
+ console.error("Error running Prisma commands:", error);
+ return false;
+ }
+}
+
+function spawnCommand(command, args, cwd) {
+ return new Promise((resolve, reject) => {
+ const process = spawn(command, args, {
+ cwd,
+ stdio: "inherit",
+ shell: true,
+ });
+
+ process.on("close", (code) => {
+ if (code === 0) {
+ resolve();
+ } else {
+ reject(new Error(`Command failed with exit code ${code}`));
+ }
+ });
+ });
+}
diff --git a/server/api/devtool/role/add.js b/server/api/devtool/role/add.js
index 6dd9932..b65d9e2 100644
--- a/server/api/devtool/role/add.js
+++ b/server/api/devtool/role/add.js
@@ -3,7 +3,11 @@ export default defineEventHandler(async (event) => {
try {
// Check if the role already exists
- const allRole = await prisma.role.findMany();
+ const allRole = await prisma.role.findMany({
+ where: {
+ roleStatus: "ACTIVE",
+ },
+ });
const roleExist = allRole.find((role) => {
return role?.roleName.toLowerCase() === body?.name.toLowerCase();
@@ -16,71 +20,63 @@ export default defineEventHandler(async (event) => {
};
}
- if (body.module == "user") {
- // add new role
- const role = await prisma.role.create({
- data: {
- roleName: body.name,
- roleDescription: body.description || "",
- roleStatus: "ACTIVE",
- roleCreatedDate: new Date(),
- },
- });
+ // add new role
+ const role = await prisma.role.create({
+ data: {
+ roleName: body.name,
+ roleDescription: body.description || "",
+ roleStatus: "ACTIVE",
+ roleCreatedDate: new Date(),
+ },
+ });
- if (role) {
- return {
- statusCode: 200,
- message: "Role successfully added!",
- };
- } else {
- return {
- statusCode: 500,
- message: "Something went wrong! Please contact your administrator.",
- };
- }
- } else if (body.module == "role") {
- // add new role
- const role = await prisma.role.create({
- data: {
- roleName: body.name,
- roleDescription: body.description || "",
- roleStatus: "ACTIVE",
- roleCreatedDate: new Date(),
- },
- });
+ if (role) {
+ // Add User to the role if users are provided
+ if (body.users && Array.isArray(body.users)) {
+ const userRoles = await Promise.all(
+ body.users.map(async (el) => {
+ const user = await prisma.user.findFirst({
+ where: {
+ userUsername: el.value,
+ },
+ });
- if (role) {
- // Add User to the role
- body.users.forEach(async (el) => {
- // Select user where username
- const user = await prisma.user.findFirst({
- where: {
- userUsername: el.value,
- },
- });
+ if (user) {
+ return prisma.userrole.create({
+ data: {
+ userRoleUserID: user.userID,
+ userRoleRoleID: role.roleID,
+ userRoleCreatedDate: new Date(),
+ },
+ });
+ }
+ return null;
+ })
+ );
- if (!user) return;
-
- // Add UserRole
- const userRole = await prisma.userrole.create({
- data: {
- userRoleUserID: user.userID,
- userRoleRoleID: role.roleID,
- userRoleCreatedDate: new Date(),
- },
- });
- });
+ const validUserRoles = userRoles.filter(Boolean);
return {
statusCode: 200,
message: "Role successfully added!",
- };
- } else {
- return {
- statusCode: 500,
- message: "Something went wrong! Please contact your administrator.",
+ data: {
+ role,
+ assignedUsers: validUserRoles.length,
+ totalUsers: body.users.length,
+ },
};
}
+
+ return {
+ statusCode: 200,
+ message: "Role successfully added!",
+ data: { role },
+ };
+ } else {
+ return {
+ statusCode: 500,
+ message: "Something went wrong! Please contact your administrator.",
+ };
}
} catch (error) {
return {
diff --git a/server/api/devtool/role/edit.js b/server/api/devtool/role/edit.js
index b317260..1f22e46 100644
--- a/server/api/devtool/role/edit.js
+++ b/server/api/devtool/role/edit.js
@@ -14,39 +14,53 @@ export default defineEventHandler(async (event) => {
});
if (role) {
- // Delete all user role
- const deleteUserRole = await prisma.userrole.deleteMany({
+ // Delete all user roles for this role
+ await prisma.userrole.deleteMany({
where: {
userRoleRoleID: body.id,
},
});
- if (deleteUserRole) {
- // Add User to the role
- body.users.forEach(async (el) => {
- // Select user where username
- const user = await prisma.user.findFirst({
- where: {
- userUsername: el.value,
- },
- });
+ // Add User to the role if users are provided
+ if (body.users && Array.isArray(body.users)) {
+ const userRoles = await Promise.all(
+ body.users.map(async (el) => {
+ const user = await prisma.user.findFirst({
+ where: {
+ userUsername: el.value,
+ },
+ });
- if (!user) return;
+ if (user) {
+ return prisma.userrole.create({
+ data: {
+ userRoleUserID: user.userID,
+ userRoleRoleID: body.id,
+ userRoleCreatedDate: new Date(),
+ },
+ });
+ }
+ return null;
+ })
+ );
- // Add UserRole
- const userRole = await prisma.userrole.create({
- data: {
- userRoleUserID: user.userID,
- userRoleRoleID: body.id,
- userRoleCreatedDate: new Date(),
- },
- });
- });
+ const validUserRoles = userRoles.filter(Boolean);
+
+ return {
+ statusCode: 200,
+ message: "Role successfully edited!",
+ data: {
+ role,
+ assignedUsers: validUserRoles.length,
+ totalUsers: body.users.length,
+ },
+ };
}
return {
statusCode: 200,
message: "Role successfully edited!",
+ data: { role },
};
} else {
return {
diff --git a/server/api/devtool/user/add.js b/server/api/devtool/user/add.js
index aba1297..9dc3c08 100644
--- a/server/api/devtool/user/add.js
+++ b/server/api/devtool/user/add.js
@@ -8,7 +8,11 @@ export default defineEventHandler(async (event) => {
try {
// Get user from database
- const allUser = await prisma.user.findMany();
+ const allUser = await prisma.user.findMany({
+ where: {
+ userStatus: "ACTIVE",
+ },
+ });
// Check if the user already exists
const userExist = allUser.find((user) => {
@@ -30,86 +34,67 @@ export default defineEventHandler(async (event) => {
})
);
- // If role is not empty
- if (body.module == "user") {
- if (body.role.length == 0) {
- return {
- statusCode: 400,
- message: "Please select at least one role",
- };
- }
+ // Add New User
+ const user = await prisma.user.create({
+ data: {
+ userSecretKey: secretKey,
+ userUsername: body.username,
+ userPassword: password,
+ userFullName: body?.fullname || "",
+ userEmail: body?.email || "",
+ userPhone: body?.phone || "",
+ userStatus: "ACTIVE",
+ userCreatedDate: new Date(),
+ },
+ });
- body.role.forEach((el) => {
- // Check if roleID is valid for each role
- if (!checkRoleID(el.value)) {
- return {
- statusCode: 400,
- message: "Role ID is not valid",
- };
- }
- });
+ if (user) {
+ // Add user roles if provided
+ if (body.role && Array.isArray(body.role)) {
+ const userRoles = await Promise.all(
+ body.role.map(async (role) => {
+ const existingRole = await prisma.role.findFirst({
+ where: {
+ roleID: role.value,
+ },
+ });
- // Add New User
- const user = await prisma.user.create({
- data: {
- userSecretKey: secretKey,
- userUsername: body.username,
- userPassword: password,
- userFullName: body?.fullname || "",
- userEmail: body?.email || "",
- userPhone: body?.phone || "",
- userStatus: "ACTIVE",
- userCreatedDate: new Date(),
- },
- });
+ if (existingRole) {
+ return prisma.userrole.create({
+ data: {
+ userRoleUserID: user.userID,
+ userRoleRoleID: role.value,
+ userRoleCreatedDate: new Date(),
+ },
+ });
+ }
+ return null;
+ })
+ );
- if (user) {
- // Add user role
- body.role.forEach(async (el) => {
- const userRole = await prisma.userrole.create({
- data: {
- userRoleUserID: user.userID,
- userRoleRoleID: el.value,
- userRoleCreatedDate: new Date(),
- },
- });
- });
+ const validUserRoles = userRoles.filter(Boolean);
return {
statusCode: 200,
message: "User successfully added!",
- };
- } else {
- return {
- statusCode: 500,
- message: "Something went wrong! Please contact your administrator.",
- };
- }
- } else if (body.module == "role") {
- // Add New User
- const user = await prisma.user.create({
- data: {
- userSecretKey: secretKey,
- userUsername: body.username,
- userPassword: password,
- userFullName: body?.fullname || "",
- userEmail: body?.email || "",
- userPhone: body?.phone || "",
- userStatus: "ACTIVE",
- userCreatedDate: new Date(),
- },
- });
- if (user) {
- return {
- statusCode: 200,
- message: "User successfully added!",
- };
- } else {
- return {
- statusCode: 500,
- message: "Something went wrong! Please contact your administrator.",
+ data: {
+ user,
+ assignedRoles: validUserRoles.length,
+ totalRoles: body.role.length,
+ },
};
}
+
+ return {
+ statusCode: 200,
+ message: "User successfully added!",
+ data: { user },
+ };
+ } else {
+ return {
+ statusCode: 500,
+ message: "Something went wrong! Please contact your administrator.",
+ };
}
} catch (error) {
return {
diff --git a/server/api/devtool/user/edit.js b/server/api/devtool/user/edit.js
index 389f579..7cfa985 100644
--- a/server/api/devtool/user/edit.js
+++ b/server/api/devtool/user/edit.js
@@ -16,7 +16,7 @@ export default defineEventHandler(async (event) => {
},
});
- if (user) {
+ if (user.count > 0) {
const getUserID = await prisma.user.findFirst({
where: {
userUsername: body.username,
@@ -24,34 +24,59 @@ export default defineEventHandler(async (event) => {
});
if (getUserID) {
- // Delete all user role
- const userRole = await prisma.userrole.deleteMany({
+ // Delete all user roles
+ await prisma.userrole.deleteMany({
where: {
userRoleUserID: getUserID.userID,
},
});
- if (userRole) {
- const userRoleList = body.role;
+ // Add new user roles
+ if (body.role && Array.isArray(body.role)) {
+ const userRoles = await Promise.all(
+ body.role.map(async (role) => {
+ const existingRole = await prisma.role.findFirst({
+ where: {
+ roleID: role.value,
+ },
+ });
- // Add new user role
- userRoleList.forEach(async (role) => {
- const userRole = await prisma.userrole.create({
- data: {
- userRoleUserID: getUserID.userID,
- userRoleRoleID: role.value,
- userRoleCreatedDate: new Date(),
- },
- });
- });
+ if (existingRole) {
+ return prisma.userrole.create({
+ data: {
+ userRoleUserID: getUserID.userID,
+ userRoleRoleID: role.value,
+ userRoleCreatedDate: new Date(),
+ },
+ });
+ }
+ return null;
+ })
+ );
+
+ const validUserRoles = userRoles.filter(Boolean);
return {
statusCode: 200,
message: "User updated successfully",
+ data: {
+ assignedRoles: validUserRoles.length,
+ totalRoles: body.role.length,
+ },
};
}
+
+ return {
+ statusCode: 200,
+ message: "User updated successfully",
+ };
}
}
+
+ return {
+ statusCode: 404,
+ message: "User not found",
+ };
} catch (error) {
return {
statusCode: 500,