Kaynağa Gözat

feat: better breadcrumbs for config list and editor; add filename filter for configurations list.

Jacky 9 ay önce
ebeveyn
işleme
5dd2c8f931

+ 6 - 0
api/config/list.go

@@ -8,9 +8,11 @@ import (
 	"github.com/gin-gonic/gin"
 	"net/http"
 	"os"
+	"strings"
 )
 
 func GetConfigs(c *gin.Context) {
+	name := c.Query("name")
 	orderBy := c.Query("order_by")
 	sort := c.DefaultQuery("sort", "desc")
 	dir := c.DefaultQuery("dir", "/")
@@ -28,6 +30,10 @@ func GetConfigs(c *gin.Context) {
 		file := configFiles[i]
 		fileInfo, _ := file.Info()
 
+		if name != "" && !strings.Contains(file.Name(), name) {
+			continue
+		}
+
 		switch mode := fileInfo.Mode(); {
 		case mode.IsRegular(): // regular file, not a hidden file
 			if "." == file.Name()[0:1] {

+ 15 - 9
app/src/components/Breadcrumb/Breadcrumb.vue

@@ -1,17 +1,13 @@
 <script setup lang="ts">
-interface bread {
-  name: string
-  translatedName: () => string
-  path: string
-  hasChildren?: boolean
-}
+import type { Bread } from '@/components/Breadcrumb/types'
+import { useBreadcrumbs } from '@/composables/useBreadcrumbs'
 
 const name = ref()
 const route = useRoute()
 const router = useRouter()
 
-const breadList = computed(() => {
-  const result: bread[] = []
+const computedBreadList = computed(() => {
+  const result: Bread[] = []
 
   name.value = route.meta.name
 
@@ -36,6 +32,16 @@ const breadList = computed(() => {
 
   return result
 })
+
+const breadList = useBreadcrumbs()
+
+onMounted(() => {
+  breadList.value = computedBreadList.value
+})
+
+watch(route, () => {
+  breadList.value = computedBreadList.value
+})
 </script>
 
 <template>
@@ -46,7 +52,7 @@ const breadList = computed(() => {
     >
       <RouterLink
         v-if="index === 0 || !item.hasChildren && index !== breadList.length - 1"
-        :to="{ path: item.path === '' ? '/' : item.path }"
+        :to="{ path: item.path === '' ? '/' : item.path, query: item.query }"
       >
         {{ item.translatedName() }}
       </RouterLink>

+ 9 - 0
app/src/components/Breadcrumb/types.d.ts

@@ -0,0 +1,9 @@
+import {LocationQueryRaw} from "vue-router";
+
+export interface Bread {
+  name: string
+  translatedName: () => string
+  path?: string
+  query?: LocationQueryRaw
+  hasChildren?: boolean
+}

+ 5 - 0
app/src/composables/useBreadcrumbs.ts

@@ -0,0 +1,5 @@
+import type { Bread } from '@/components/Breadcrumb/types'
+
+export const useBreadcrumbs = () => {
+  return inject('breadList') as Ref<Bread[]>
+}

+ 4 - 0
app/src/layouts/BaseLayout.vue

@@ -28,6 +28,10 @@ const { server_name } = storeToRefs(useSettingsStore())
 settings.get_server_name().then(r => {
   server_name.value = r.name
 })
+
+const breadList = ref([])
+
+provide('breadList', breadList)
 </script>
 
 <template>

+ 37 - 2
app/src/views/config/Config.vue

@@ -1,9 +1,10 @@
 <script setup lang="ts">
 import StdTable from '@/components/StdDesign/StdDataDisplay/StdTable.vue'
 import config from '@/api/config'
-import configColumns from '@/views/config/config'
+import configColumns from '@/views/config/configColumns'
 import FooterToolBar from '@/components/FooterToolbar/FooterToolBar.vue'
 import InspectConfig from '@/views/config/InspectConfig.vue'
+import { useBreadcrumbs } from '@/composables/useBreadcrumbs'
 
 const table = ref()
 const route = useRoute()
@@ -30,9 +31,44 @@ watch(getParams, () => {
 })
 
 const refInspectConfig = ref()
+const breadcrumbs = useBreadcrumbs()
+
+function updateBreadcrumbs() {
+  const path = basePath.value
+    .split('/')
+    .filter(v => v)
+    .map(v => {
+      return {
+        name: 'Manage Configs',
+        translatedName: () => v,
+        path: '/config',
+        query: {
+          dir: v,
+        },
+        hasChildren: false,
+      }
+    })
+
+  breadcrumbs.value = [{
+    name: 'Dashboard',
+    translatedName: () => $gettext('Dashboard'),
+    path: '/dashboard',
+    hasChildren: false,
+  }, {
+    name: 'Manage Configs',
+    translatedName: () => $gettext('Manage Configs'),
+    path: '/config',
+    hasChildren: false,
+  }, ...path]
+}
+
+onMounted(() => {
+  updateBreadcrumbs()
+})
 
 watch(route, () => {
   refInspectConfig.value?.test()
+  updateBreadcrumbs()
 })
 
 function goBack() {
@@ -62,7 +98,6 @@ function goBack() {
       :api="config"
       :columns="configColumns"
       disable-delete
-      disable-search
       disable-view
       row-key="name"
       :get-params="getParams"

+ 67 - 1
app/src/views/config/ConfigEditor.vue

@@ -9,6 +9,7 @@ import ngx from '@/api/ngx'
 import InspectConfig from '@/views/config/InspectConfig.vue'
 import ChatGPT from '@/components/ChatGPT/ChatGPT.vue'
 import type { ChatComplicationMessage } from '@/api/openai'
+import { useBreadcrumbs } from '@/composables/useBreadcrumbs'
 
 const route = useRoute()
 const router = useRouter()
@@ -43,17 +44,51 @@ const newPath = computed(() => [nginxConfigBase.value, basePath.value, data.valu
   .join('/'))
 
 const relativePath = computed(() => (route.params.name as string[]).join('/'))
+const breadcrumbs = useBreadcrumbs()
 
 async function init() {
   const { name } = route.params
 
   data.value.name = name?.[name?.length - 1] ?? ''
   origName.value = data.value.name
-  if (data.value.name) {
+  if (!addMode.value) {
     config.get(relativePath.value).then(r => {
       data.value = r
       historyChatgptRecord.value = r.chatgpt_messages
       modifiedAt.value = r.modified_at
+
+      const path = data.value.filepath
+        .replaceAll(`${nginxConfigBase.value}/`, '')
+        .replaceAll(data.value.name, '')
+        .split('/')
+        .filter(v => v)
+        .map(v => {
+          return {
+            name: 'Manage Configs',
+            translatedName: () => v,
+            path: '/config',
+            query: {
+              dir: v,
+            },
+            hasChildren: false,
+          }
+        })
+
+      breadcrumbs.value = [{
+        name: 'Dashboard',
+        translatedName: () => $gettext('Dashboard'),
+        path: '/dashboard',
+        hasChildren: false,
+      }, {
+        name: 'Manage Configs',
+        translatedName: () => $gettext('Manage Configs'),
+        path: '/config',
+        hasChildren: false,
+      }, ...path, {
+        name: 'Edit Config',
+        translatedName: () => origName.value,
+        hasChildren: false,
+      }]
     }).catch(r => {
       message.error(r.message ?? $gettext('Server error'))
     })
@@ -62,6 +97,37 @@ async function init() {
     data.value.content = ''
     historyChatgptRecord.value = []
     data.value.filepath = ''
+
+    const path = basePath.value
+      .split('/')
+      .filter(v => v)
+      .map(v => {
+        return {
+          name: 'Manage Configs',
+          translatedName: () => v,
+          path: '/config',
+          query: {
+            dir: v,
+          },
+          hasChildren: false,
+        }
+      })
+
+    breadcrumbs.value = [{
+      name: 'Dashboard',
+      translatedName: () => $gettext('Dashboard'),
+      path: '/dashboard',
+      hasChildren: false,
+    }, {
+      name: 'Manage Configs',
+      translatedName: () => $gettext('Manage Configs'),
+      path: '/config',
+      hasChildren: false,
+    }, ...path, {
+      name: 'Add Config',
+      translatedName: () => $gettext('Add Configuration'),
+      hasChildren: false,
+    }]
   }
 }
 

+ 4 - 0
app/src/views/config/config.ts → app/src/views/config/configColumns.ts

@@ -2,12 +2,16 @@ import { h } from 'vue'
 import type { customRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
 import { datetime } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
 import type { JSXElements } from '@/components/StdDesign/types'
+import { input } from '@/components/StdDesign/StdDataEntry'
 
 const configColumns = [{
   title: () => $gettext('Name'),
   dataIndex: 'name',
   sorter: true,
   pithy: true,
+  search: {
+    type: input,
+  },
 }, {
   title: () => $gettext('Type'),
   dataIndex: 'is_dir',