Lompat ke konten
dokumentasi.id
Commit b472665
v1
Star1,3 rb

10

Frontend Admin Panel

Admin panel Badaso adalah SPA Vue 2 yang tidak punya daftar route statis di sisi Laravel. Laravel hanya menyediakan satu catch-all route yang mengembalikan satu view blade, dan view itu memuat app.js sebagai entry point Vite. Semua komponen, route, modul API, dan modul store dirakit saat build lewat import.meta.globEager. Karena itu, menambah halaman berarti menambah berkas di direktori yang sudah di-glob, bukan menyunting satu berkas konfigurasi pusat.

Satu route Laravel, satu instance Vue

Route /$admin_panel_route_prefix/{any?} dengan where('any', '.*') menangkap seluruh path di bawah prefix admin panel dan selalu mengembalikan badaso::admin-panel.index src/Routes/web.php:19-22. View blade itu hanya berisi <div id="app"></div>, polyfill indexedDB, dan dua pemanggilan @vite untuk style.scss serta app.js src/resources/views/admin-panel/index.blade.php:29-37.

app.js mendaftarkan Vuesax, VueI18n, Datetime, dan Vuelidate, lalu mengimpor api, router, store, lang, excludedRouter, dan App.vue sebagai satu-satunya akar aplikasi src/resources/badaso/app.js:1-16. Instance Vue dibuat sekali dengan store, router, i18n, dan render: (h) => h(App), lalu di-mount ke #app src/resources/badaso/app.js:347-352.

graph TD
  blade["views/admin-panel/index.blade.php"] --> appjs["app.js"]
  appjs --> router["router/router.js"]
  appjs --> store["store/store.js"]
  appjs --> api["api/index.js"]
  appjs --> approot["apps/App.vue"]
  appjs --> exclude["router/excludeRouter.js"]
  router --> container["layout/admin/Container.vue"]
  container --> pages["pages/index.vue"]
  pages --> home["pages/home.vue"]
  store --> storemod["store/modules/badaso.js"]
  api --> apimods["api/modules/*.js"]
  api --> resource["api/resource.js"]
  style blade fill:#f59e0b,color:#000
  style resource fill:#336791,color:#fff
  style storemod fill:#8b5cf6,color:#fff
  style apimods fill:#8b5cf6,color:#fff
  style container fill:#2d7d46,color:#fff
%% fig: Ketergantungan modul entry point admin panel
%% desc: Satu berkas blade memuat app.js, yang merakit router, store, api, dan App.vue; router berujung di Container.vue dan pages/index.vue.
Fig. 1: Ketergantungan modul entry point admin panelSatu berkas blade memuat app.js, yang merakit router, store, api, dan App.vue; router berujung di Container.vue dan pages/index.vue.

Prefix route dan perakitan router

Prefix admin panel dibaca dari VITE_ADMIN_PANEL_ROUTE_PREFIX dan jatuh ke /badaso-dashboard bila variabel itu kosong src/resources/badaso/router/router.js:13-19. Prefix yang sama dipakai ulang oleh berkas route lain, misalnya admin-router.js yang mengarahkan prefix dan prefix + "/admin" ke prefix + "/home" src/resources/badaso/router/admin/admin-router.js:7-32.

router.js mengumpulkan route dari empat direktori lewat import.meta.globEager, yaitu ./auth/*.js, ./public/*.js, ./admin/*.js, dan ./others/*.js src/resources/badaso/router/router.js:31-52. Hasilnya disusun menjadi tiga route induk bernama Auth, Public, dan Admin, ditambah route Maintenance serta catch-all path: "*" yang me-redirect ke prefix + "/page-not-found" src/resources/badaso/router/router.js:135-191. Mode router adalah history, sehingga path seperti /badaso-dashboard/home tetap ditangani catch-all Laravel saat halaman dimuat ulang.

Route hasil CRUD generator memakai parameter :slug dan menumpang pada komponen Pages yang sama, misalnya prefix + "/:slug" untuk CrudGeneratedBrowse dan prefix + "/:slug/:id/edit" untuk CrudGeneratedEdit src/resources/badaso/router/admin/generated-router.js:11-59. Rincian pembentukan route per entitas dibahas di CRUD Generator dan Content Manager.

Guard navigasi dan pengecualian page tracker

router.beforeEach menulis document.title dari to.meta.title atau to.name, memanggil api.badasoMaintenance.maintenance({ path: to.path }), lalu memeriksa localStorage.getItem("token") src/resources/badaso/router/router.js:193-225. Route dengan meta.authenticatedUser diarahkan ke AuthLogin bila token tidak ada, sedangkan route dengan meta.guest diarahkan ke Home bila token justru ada src/resources/badaso/router/router.js:193-225. Mekanisme token dan otorisasi dibahas di Autentikasi dan Otorisasi.

⚠️ Pemanggilan maintenance bersifat asinkron, sedangkan cabang pemeriksaan token langsung memanggil next(). Pada route yang sudah punya token, navigasi tidak menunggu jawaban maintenance; perpindahan ke halaman Maintenance baru terjadi setelah promise selesai dan res.data.maintenance bernilai benar src/resources/badaso/router/router.js:193-225.

Daftar route yang dikecualikan dari page tracker disimpan sebagai array nama route, berisi antara lain Auth, Home, UserProfile, CrudManagementBrowse, dan DatabaseManagementBrowse src/resources/badaso/router/excludeRouter.js:1-43. Array itu diumpankan sebagai pageTrackerExcludedRoutes pada opsi VueGtag, bersama VITE_ANALYTICS_TRACKING_ID dan send_page_view: true src/resources/badaso/app.js:329-343. app.js juga menambahkan route pengecualian dari setiap plugin yang terdaftar di VITE_BADASO_PLUGINS src/resources/badaso/app.js:45-68; pola plugin itu dibahas di Kustomisasi dan Plugin.

sequenceDiagram
  participant B as Browser
  participant R as router
  participant M as api.badasoMaintenance
  participant C as AdminContainer
  participant P as pages/index.vue
  B->>R: navigasi ke route Admin
  R->>R: set document.title dari meta.title
  R->>M: maintenance path
  R->>R: cek localStorage token
  alt token kosong
    R-->>B: next nama AuthLogin
  else token ada
    R-->>B: next
    B->>C: render Container.vue
    C->>C: commit FETCH_COMPONENT, FETCH_CONFIGURATION_GROUPS, FETCH_USER
    C->>P: router-view dengan key route.path
    P->>P: pilih defaultComponent dari route.name
  end
%% fig: Siklus satu navigasi di admin panel
%% desc: Guard router menetapkan judul, memanggil endpoint maintenance, memeriksa token, lalu Container.vue memuat state dan pages/index.vue memilih komponen halaman.
Fig. 2: Siklus satu navigasi di admin panelGuard router menetapkan judul, memanggil endpoint maintenance, memeriksa token, lalu Container.vue memuat state dan pages/index.vue memilih komponen halaman.

Perakitan komponen, util, store, dan API saat build

app.js memindai ./components/*.vue, mengubah nama berkas kebab-case menjadi nama komponen, lalu mendaftarkannya dengan Vue.component src/resources/badaso/app.js:70-93. Pola yang sama dipakai untuk komponen custom di resources/js/badaso/components/*.vue src/resources/badaso/app.js:95-120, dan setiap berkas di ./utils/*.js dipasang sebagai properti prototipe $ + nama util src/resources/badaso/app.js:122-148.

Selain itu app.js menetapkan Vue.prototype.$api, $handleError, $resource, $constants (MOBILE dan DESKTOP), $loadingConfig, serta $baseUrl yang dibentuk dari prefix admin panel src/resources/badaso/app.js:232-249. Loader global dibuka dan ditutup lewat $openLoader, $closeLoader, dan $syncLoader yang memanggil anak pertama $root src/resources/badaso/app.js:251-273.

Sumber globYang dihasilkanRujukan
./components/*.vuekomponen global Badasosrc/resources/badaso/app.js:70-93
resources/js/badaso/components/*.vuekomponen custom proyeksrc/resources/badaso/app.js:95-120
./utils/*.jsVue.prototype.$<namaUtil>src/resources/badaso/app.js:122-148
./store/modules/*.jsmodul Vuex Badasosrc/resources/badaso/store/store.js:11-36
resources/js/badaso/stores/*.jsmodul Vuex customsrc/resources/badaso/store/store.js:38-65
./api/modules/*.jsproperti objek apisrc/resources/badaso/api/index.js:7-32
resources/js/badaso/api/*.jshelper API customsrc/resources/badaso/api/index.js:34-62

store.js mengekspor new Vuex.Store({ modules: exported }) setelah menggabungkan modul Badaso dan modul custom src/resources/badaso/store/store.js:84-88. Modul badaso sendiri namespaced, menyimpan isSidebarActive, reduceSidebar, menu, config, componentList, groupList, user, dan availableMimetypes, serta memasang createPersistedState() sebagai plugin src/resources/badaso/store/modules/badaso.js:6-37 src/resources/badaso/store/modules/badaso.js:164-194. Mutasi FETCH_COMPONENT, FETCH_CONFIGURATION_GROUPS, dan FETCH_USER mengambil data lewat api.badasoData dan api.badasoAuthUser src/resources/badaso/store/modules/badaso.js:115-134.

api/index.js merakit objek exported dari modul glob, dan setiap nama berkas diubah menjadi properti camelCase, misalnya badaso-dashboard.js menjadi badasoDashboard src/resources/badaso/api/index.js:7-32. Semua modul itu memakai instance axios dari resource.js, yang menyisipkan header Authorization: Bearer <token> dari localStorage pada request interceptor dan mengembalikan response.data pada response interceptor src/resources/badaso/api/resource.js:13-24. Contoh pemakaiannya ada di pages/home.vue, yang memanggil this.$api.badasoDashboard.index() dan mengubah col menjadi 3, 4, atau 6 sesuai jumlah widget src/resources/badaso/pages/home.vue:28-50; modul itu menembak apiPrefix + "/v1/dashboard" dengan apiPrefix default /badaso-api src/resources/badaso/api/modules/badaso-dashboard.js:5-14.

Container admin dan pemilihan halaman

Route induk Admin memakai AdminContainer dan memasang seluruh route admin sebagai children src/resources/badaso/router/router.js:135-191. Template Container.vue menyusun Navbar, SideBar, Footer, dan <router-view class="content" :key="$route.path">, sehingga setiap perubahan path memaksa render ulang komponen halaman src/resources/badaso/layout/admin/Container.vue:1-26. Saat mounted, container meng-commit badaso/FETCH_COMPONENT, badaso/FETCH_CONFIGURATION_GROUPS, dan badaso/FETCH_USER src/resources/badaso/layout/admin/Container.vue:91-100.

Warna header, logo, judul, dan konfigurasi logo dibaca dari getter badaso/getConfig dengan nilai cadangan #fff, #000, "Badaso", dan logo_and_text src/resources/badaso/layout/admin/Container.vue:1-26. Lebar jendela menentukan viewType: di bawah 768 piksel dipakai $constants.MOBILE, selain itu $constants.DESKTOP src/resources/badaso/layout/admin/Container.vue:136-142.

Setiap route admin memakai komponen Pages yang sama. pages/index.vue merender <component :is="..."> dan pada mounted menghitung nama komponen dari this.$caseConvert.kebab(this.$route.name) src/resources/badaso/pages/index.vue:123-167. Untuk route CrudGenerated*, nama itu diganti menjadi <slug>-browse, <slug>-read, <slug>-edit, <slug>-add, atau <slug>-sort bila komponen hasil generator tersedia src/resources/badaso/pages/index.vue:123-167. Penamaan dinamis inilah sebabnya route hasil generator bisa memakai satu berkas komponen per entitas.

Tabel server-side sebagai komponen bersama

Halaman browse memakai BadasoServerSideTable untuk daftar data dengan paging di sisi server. Komponen ini menerima props paginationData, data, description, descriptionItems (default [10, 50, 100, 200]), descriptionTitle (default Registries), dan descriptionConnector (default of) src/resources/badaso/components/BadasoServerSideTable.vue:75-141. Nilai totalItem dihitung sebagai Math.ceil(paginationData.total / limit), dan limit: 10, page: 1 menjadi keadaan awal src/resources/badaso/components/BadasoServerSideTable.vue:75-141.

Komponen ini tidak memanggil API sendiri. Ia hanya mengirim event changePage, changeLimit, select, search, dan sort, sehingga halaman pemanggil yang menentukan request ke backend src/resources/badaso/components/BadasoServerSideTable.vue:75-141. Pola yang sama dipakai halaman manajemen user, role, dan permission yang dibahas di Manajemen User, Role, dan Permission.