mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2025-05-10 18:05:48 +02:00
feat(config): use encode/decode to handle url #249
This commit is contained in:
parent
4b8d26cf5b
commit
191ddea309
19 changed files with 235 additions and 82 deletions
|
@ -2,6 +2,7 @@ package config
|
|||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
@ -28,8 +29,22 @@ func AddConfig(c *gin.Context) {
|
|||
|
||||
name := json.Name
|
||||
content := json.Content
|
||||
dir := nginx.GetConfPath(json.BaseDir)
|
||||
path := filepath.Join(dir, json.Name)
|
||||
|
||||
// Decode paths from URL encoding
|
||||
decodedBaseDir, err := url.QueryUnescape(json.BaseDir)
|
||||
if err != nil {
|
||||
cosy.ErrHandler(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
decodedName, err := url.QueryUnescape(name)
|
||||
if err != nil {
|
||||
cosy.ErrHandler(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
dir := nginx.GetConfPath(decodedBaseDir)
|
||||
path := filepath.Join(dir, decodedName)
|
||||
if !helper.IsUnderDirectory(path, nginx.GetConfPath()) {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"message": "filepath is not under the nginx conf path",
|
||||
|
@ -53,7 +68,7 @@ func AddConfig(c *gin.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
err := os.WriteFile(path, []byte(content), 0644)
|
||||
err = os.WriteFile(path, []byte(content), 0644)
|
||||
if err != nil {
|
||||
cosy.ErrHandler(c, err)
|
||||
return
|
||||
|
|
|
@ -2,6 +2,7 @@ package config
|
|||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
|
@ -23,6 +24,19 @@ type APIConfigResp struct {
|
|||
func GetConfig(c *gin.Context) {
|
||||
relativePath := c.Param("path")
|
||||
|
||||
// Ensure the path is correctly decoded - handle cases where it might be encoded multiple times
|
||||
decodedPath := relativePath
|
||||
var err error
|
||||
// Try decoding until the path no longer changes
|
||||
for {
|
||||
newDecodedPath, decodeErr := url.PathUnescape(decodedPath)
|
||||
if decodeErr != nil || newDecodedPath == decodedPath {
|
||||
break
|
||||
}
|
||||
decodedPath = newDecodedPath
|
||||
}
|
||||
relativePath = decodedPath
|
||||
|
||||
absPath := nginx.GetConfPath(relativePath)
|
||||
if !helper.IsUnderDirectory(absPath, nginx.GetConfPath()) {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
|
|
|
@ -2,6 +2,7 @@ package config
|
|||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
|
@ -16,7 +17,31 @@ func GetConfigs(c *gin.Context) {
|
|||
name := c.Query("name")
|
||||
sortBy := c.Query("sort_by")
|
||||
order := c.DefaultQuery("order", "desc")
|
||||
dir := c.DefaultQuery("dir", "/")
|
||||
|
||||
// Get directory parameter
|
||||
encodedDir := c.DefaultQuery("dir", "/")
|
||||
|
||||
// Handle cases where the path might be encoded multiple times
|
||||
dir := encodedDir
|
||||
// Try decoding until the path no longer changes
|
||||
for {
|
||||
newDecodedDir, decodeErr := url.QueryUnescape(dir)
|
||||
if decodeErr != nil {
|
||||
cosy.ErrHandler(c, decodeErr)
|
||||
return
|
||||
}
|
||||
|
||||
if newDecodedDir == dir {
|
||||
break
|
||||
}
|
||||
dir = newDecodedDir
|
||||
}
|
||||
|
||||
// Ensure the directory path format is correct
|
||||
dir = strings.TrimSpace(dir)
|
||||
if dir != "/" && strings.HasSuffix(dir, "/") {
|
||||
dir = strings.TrimSuffix(dir, "/")
|
||||
}
|
||||
|
||||
configFiles, err := os.ReadDir(nginx.GetConfPath(dir))
|
||||
if err != nil {
|
||||
|
|
|
@ -2,6 +2,7 @@ package config
|
|||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"github.com/0xJacky/Nginx-UI/internal/helper"
|
||||
|
@ -18,7 +19,21 @@ func Mkdir(c *gin.Context) {
|
|||
if !cosy.BindAndValid(c, &json) {
|
||||
return
|
||||
}
|
||||
fullPath := nginx.GetConfPath(json.BasePath, json.FolderName)
|
||||
|
||||
// Ensure paths are properly URL unescaped
|
||||
decodedBasePath, err := url.QueryUnescape(json.BasePath)
|
||||
if err != nil {
|
||||
cosy.ErrHandler(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
decodedFolderName, err := url.QueryUnescape(json.FolderName)
|
||||
if err != nil {
|
||||
cosy.ErrHandler(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
fullPath := nginx.GetConfPath(decodedBasePath, decodedFolderName)
|
||||
if !helper.IsUnderDirectory(fullPath, nginx.GetConfPath()) {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"message": "You are not allowed to create a folder " +
|
||||
|
@ -26,7 +41,7 @@ func Mkdir(c *gin.Context) {
|
|||
})
|
||||
return
|
||||
}
|
||||
err := os.Mkdir(fullPath, 0755)
|
||||
err = os.Mkdir(fullPath, 0755)
|
||||
if err != nil {
|
||||
cosy.ErrHandler(c, err)
|
||||
return
|
||||
|
|
|
@ -2,6 +2,7 @@ package config
|
|||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
@ -23,6 +24,20 @@ type EditConfigJson struct {
|
|||
|
||||
func EditConfig(c *gin.Context) {
|
||||
relativePath := c.Param("path")
|
||||
|
||||
// Ensure the path is correctly decoded - handle cases where it might be encoded multiple times
|
||||
decodedPath := relativePath
|
||||
var err error
|
||||
// Try decoding until the path no longer changes
|
||||
for {
|
||||
newDecodedPath, decodeErr := url.PathUnescape(decodedPath)
|
||||
if decodeErr != nil || newDecodedPath == decodedPath {
|
||||
break
|
||||
}
|
||||
decodedPath = newDecodedPath
|
||||
}
|
||||
relativePath = decodedPath
|
||||
|
||||
var json struct {
|
||||
Content string `json:"content"`
|
||||
SyncOverwrite bool `json:"sync_overwrite"`
|
||||
|
|
|
@ -2,6 +2,7 @@ package config
|
|||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
@ -32,8 +33,28 @@ func Rename(c *gin.Context) {
|
|||
})
|
||||
return
|
||||
}
|
||||
origFullPath := nginx.GetConfPath(json.BasePath, json.OrigName)
|
||||
newFullPath := nginx.GetConfPath(json.BasePath, json.NewName)
|
||||
|
||||
// Decode paths from URL encoding
|
||||
decodedBasePath, err := url.QueryUnescape(json.BasePath)
|
||||
if err != nil {
|
||||
cosy.ErrHandler(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
decodedOrigName, err := url.QueryUnescape(json.OrigName)
|
||||
if err != nil {
|
||||
cosy.ErrHandler(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
decodedNewName, err := url.QueryUnescape(json.NewName)
|
||||
if err != nil {
|
||||
cosy.ErrHandler(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
origFullPath := nginx.GetConfPath(decodedBasePath, decodedOrigName)
|
||||
newFullPath := nginx.GetConfPath(decodedBasePath, decodedNewName)
|
||||
if !helper.IsUnderDirectory(origFullPath, nginx.GetConfPath()) ||
|
||||
!helper.IsUnderDirectory(newFullPath, nginx.GetConfPath()) {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
|
|
|
@ -44,12 +44,12 @@ class Curd<T> {
|
|||
|
||||
// eslint-disable-next-line ts/no-explicit-any
|
||||
_get(id: any = null, params: any = {}): Promise<T> {
|
||||
return http.get(this.baseUrl + (id ? `/${id}` : ''), { params })
|
||||
return http.get(this.baseUrl + (id ? `/${encodeURIComponent(id)}` : ''), { params })
|
||||
}
|
||||
|
||||
// eslint-disable-next-line ts/no-explicit-any
|
||||
_save(id: any = null, data: any = {}, config: any = undefined): Promise<T> {
|
||||
return http.post(this.baseUrl + (id ? `/${id}` : ''), data, config)
|
||||
return http.post(this.baseUrl + (id ? `/${encodeURIComponent(id)}` : ''), data, config)
|
||||
}
|
||||
|
||||
// eslint-disable-next-line ts/no-explicit-any
|
||||
|
@ -69,12 +69,12 @@ class Curd<T> {
|
|||
|
||||
// eslint-disable-next-line ts/no-explicit-any
|
||||
_destroy(id: any = null, params: any = {}) {
|
||||
return http.delete(`${this.baseUrl}/${id}`, { params })
|
||||
return http.delete(`${this.baseUrl}/${encodeURIComponent(id)}`, { params })
|
||||
}
|
||||
|
||||
// eslint-disable-next-line ts/no-explicit-any
|
||||
_recover(id: any = null) {
|
||||
return http.patch(`${this.baseUrl}/${id}`)
|
||||
return http.patch(`${this.baseUrl}/${encodeURIComponent(id)}`)
|
||||
}
|
||||
|
||||
_update_order(data: { target_id: number, direction: number, affected_ids: number[] }) {
|
||||
|
|
|
@ -35,7 +35,7 @@ export interface AutoCertRequest {
|
|||
class SiteCurd extends Curd<Site> {
|
||||
// eslint-disable-next-line ts/no-explicit-any
|
||||
enable(name: string, config?: any) {
|
||||
return http.post(`${this.baseUrl}/${name}/enable`, undefined, config)
|
||||
return http.post(`${this.baseUrl}/${encodeURIComponent(name)}/enable`, undefined, config)
|
||||
}
|
||||
|
||||
disable(name: string) {
|
||||
|
@ -43,7 +43,7 @@ class SiteCurd extends Curd<Site> {
|
|||
}
|
||||
|
||||
rename(oldName: string, newName: string) {
|
||||
return http.post(`${this.baseUrl}/${oldName}/rename`, { new_name: newName })
|
||||
return http.post(`${this.baseUrl}/${encodeURIComponent(oldName)}/rename`, { new_name: newName })
|
||||
}
|
||||
|
||||
get_default_template() {
|
||||
|
@ -51,19 +51,19 @@ class SiteCurd extends Curd<Site> {
|
|||
}
|
||||
|
||||
add_auto_cert(domain: string, data: AutoCertRequest) {
|
||||
return http.post(`auto_cert/${domain}`, data)
|
||||
return http.post(`auto_cert/${encodeURIComponent(domain)}`, data)
|
||||
}
|
||||
|
||||
remove_auto_cert(domain: string) {
|
||||
return http.delete(`auto_cert/${domain}`)
|
||||
return http.delete(`auto_cert/${encodeURIComponent(domain)}`)
|
||||
}
|
||||
|
||||
duplicate(name: string, data: { name: string }): Promise<{ dst: string }> {
|
||||
return http.post(`${this.baseUrl}/${name}/duplicate`, data)
|
||||
return http.post(`${this.baseUrl}/${encodeURIComponent(name)}/duplicate`, data)
|
||||
}
|
||||
|
||||
advance_mode(name: string, data: { advanced: boolean }) {
|
||||
return http.post(`${this.baseUrl}/${name}/advance`, data)
|
||||
return http.post(`${this.baseUrl}/${encodeURIComponent(name)}/advance`, data)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,23 +21,23 @@ export interface Stream {
|
|||
class StreamCurd extends Curd<Stream> {
|
||||
// eslint-disable-next-line ts/no-explicit-any
|
||||
enable(name: string, config?: any) {
|
||||
return http.post(`${this.baseUrl}/${name}/enable`, undefined, config)
|
||||
return http.post(`${this.baseUrl}/${encodeURIComponent(name)}/enable`, undefined, config)
|
||||
}
|
||||
|
||||
disable(name: string) {
|
||||
return http.post(`${this.baseUrl}/${name}/disable`)
|
||||
return http.post(`${this.baseUrl}/${encodeURIComponent(name)}/disable`)
|
||||
}
|
||||
|
||||
duplicate(name: string, data: { name: string }): Promise<{ dst: string }> {
|
||||
return http.post(`${this.baseUrl}/${name}/duplicate`, data)
|
||||
return http.post(`${this.baseUrl}/${encodeURIComponent(name)}/duplicate`, data)
|
||||
}
|
||||
|
||||
advance_mode(name: string, data: { advanced: boolean }) {
|
||||
return http.post(`${this.baseUrl}/${name}/advance`, data)
|
||||
return http.post(`${this.baseUrl}/${encodeURIComponent(name)}/advance`, data)
|
||||
}
|
||||
|
||||
rename(name: string, newName: string) {
|
||||
return http.post(`${this.baseUrl}/${name}/rename`, { new_name: newName })
|
||||
return http.post(`${this.baseUrl}/${encodeURIComponent(name)}/rename`, { new_name: newName })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,10 +24,8 @@ const router = useRouter()
|
|||
|
||||
// eslint-disable-next-line vue/require-typed-ref
|
||||
const refForm = ref()
|
||||
const refInspectConfig = useTemplateRef('refInspectConfig')
|
||||
const origName = ref('')
|
||||
const addMode = computed(() => !route.params.name)
|
||||
const errors = ref({})
|
||||
|
||||
const showHistory = ref(false)
|
||||
const basePath = computed(() => {
|
||||
|
@ -52,11 +50,15 @@ const activeKey = ref(['basic', 'deploy', 'chatgpt'])
|
|||
const modifiedAt = ref('')
|
||||
const nginxConfigBase = ref('')
|
||||
|
||||
const newPath = computed(() => [nginxConfigBase.value, basePath.value, data.value.name]
|
||||
.filter(v => v)
|
||||
.join('/'))
|
||||
const newPath = computed(() => {
|
||||
// 组合路径后解码显示
|
||||
const path = [nginxConfigBase.value, basePath.value, data.value.name]
|
||||
.filter(v => v)
|
||||
.join('/')
|
||||
return path
|
||||
})
|
||||
|
||||
const relativePath = computed(() => (route.params.name as string[]).join('/'))
|
||||
const relativePath = computed(() => (basePath.value ? `${basePath.value}/${route.params.name}` : route.params.name) as string)
|
||||
const breadcrumbs = useBreadcrumbs()
|
||||
|
||||
async function init() {
|
||||
|
@ -75,20 +77,26 @@ async function init() {
|
|||
.split('/')
|
||||
.filter(v => v)
|
||||
|
||||
const path = filteredPath.map((v, k) => {
|
||||
let dir = v
|
||||
// Build accumulated path to maintain original encoding state
|
||||
let accumulatedPath = ''
|
||||
const path = filteredPath.map((segment, index) => {
|
||||
// Decode for display
|
||||
const decodedSegment = decodeURIComponent(segment)
|
||||
|
||||
if (k > 0) {
|
||||
dir = filteredPath.slice(0, k).join('/')
|
||||
dir += `/${v}`
|
||||
// Accumulated path keeps original encoding state
|
||||
if (index === 0) {
|
||||
accumulatedPath = segment
|
||||
}
|
||||
else {
|
||||
accumulatedPath = `${accumulatedPath}/${segment}`
|
||||
}
|
||||
|
||||
return {
|
||||
name: 'Manage Configs',
|
||||
translatedName: () => v,
|
||||
translatedName: () => decodedSegment,
|
||||
path: '/config',
|
||||
query: {
|
||||
dir,
|
||||
dir: accumulatedPath,
|
||||
},
|
||||
hasChildren: false,
|
||||
}
|
||||
|
@ -116,20 +124,34 @@ async function init() {
|
|||
historyChatgptRecord.value = []
|
||||
data.value.filepath = ''
|
||||
|
||||
const path = basePath.value
|
||||
const pathSegments = basePath.value
|
||||
.split('/')
|
||||
.filter(v => v)
|
||||
.map(v => {
|
||||
return {
|
||||
name: 'Manage Configs',
|
||||
translatedName: () => v,
|
||||
path: '/config',
|
||||
query: {
|
||||
dir: v,
|
||||
},
|
||||
hasChildren: false,
|
||||
}
|
||||
})
|
||||
|
||||
// Build accumulated path
|
||||
let accumulatedPath = ''
|
||||
const path = pathSegments.map((segment, index) => {
|
||||
// Decode for display
|
||||
const decodedSegment = decodeURIComponent(segment)
|
||||
|
||||
// Accumulated path keeps original encoding state
|
||||
if (index === 0) {
|
||||
accumulatedPath = segment
|
||||
}
|
||||
else {
|
||||
accumulatedPath = `${accumulatedPath}/${segment}`
|
||||
}
|
||||
|
||||
return {
|
||||
name: 'Manage Configs',
|
||||
translatedName: () => decodedSegment,
|
||||
path: '/config',
|
||||
query: {
|
||||
dir: accumulatedPath,
|
||||
},
|
||||
hasChildren: false,
|
||||
}
|
||||
})
|
||||
|
||||
breadcrumbs.value = [{
|
||||
name: 'Dashboard',
|
||||
|
@ -167,12 +189,18 @@ function save() {
|
|||
}).then(r => {
|
||||
data.value.content = r.content
|
||||
message.success($gettext('Saved successfully'))
|
||||
router.push(`/config/${r.filepath.replaceAll(`${nginxConfigBase.value}/`, '')}/edit`)
|
||||
}).catch(e => {
|
||||
errors.value = e.errors
|
||||
message.error($gettext('Save error %{msg}', { msg: e.message ?? '' }))
|
||||
}).finally(() => {
|
||||
refInspectConfig.value?.test()
|
||||
|
||||
if (addMode.value) {
|
||||
router.push({
|
||||
path: `/config/${data.value.name}/edit`,
|
||||
query: {
|
||||
basePath: basePath.value,
|
||||
},
|
||||
})
|
||||
}
|
||||
else {
|
||||
data.value = r
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -187,10 +215,13 @@ function formatCode() {
|
|||
}
|
||||
|
||||
function goBack() {
|
||||
// Keep original path with encoding state
|
||||
const encodedPath = basePath.value || ''
|
||||
|
||||
router.push({
|
||||
path: '/config',
|
||||
query: {
|
||||
dir: basePath.value || undefined,
|
||||
dir: encodedPath || undefined,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -223,7 +254,6 @@ function openHistory() {
|
|||
|
||||
<InspectConfig
|
||||
v-show="!addMode"
|
||||
ref="refInspectConfig"
|
||||
/>
|
||||
<CodeEditor v-model:content="data.content" />
|
||||
<FooterToolBar>
|
||||
|
@ -281,14 +311,14 @@ function openHistory() {
|
|||
v-if="!addMode"
|
||||
:label="$gettext('Path')"
|
||||
>
|
||||
{{ data.filepath }}
|
||||
{{ decodeURIComponent(data.filepath) }}
|
||||
</AFormItem>
|
||||
<AFormItem
|
||||
v-show="data.name !== origName"
|
||||
:label="addMode ? $gettext('New Path') : $gettext('Changed Path')"
|
||||
required
|
||||
>
|
||||
{{ newPath }}
|
||||
{{ decodeURIComponent(newPath) }}
|
||||
</AFormItem>
|
||||
<AFormItem
|
||||
v-if="!addMode"
|
||||
|
|
|
@ -40,20 +40,23 @@ function updateBreadcrumbs() {
|
|||
.split('/')
|
||||
.filter(v => v)
|
||||
|
||||
const path = filteredPath.map((v, k) => {
|
||||
let dir = v
|
||||
let accumulatedPath = ''
|
||||
const path = filteredPath.map((segment, index) => {
|
||||
const decodedSegment = decodeURIComponent(segment)
|
||||
|
||||
if (k > 0) {
|
||||
dir = filteredPath.slice(0, k).join('/')
|
||||
dir += `/${v}`
|
||||
if (index === 0) {
|
||||
accumulatedPath = segment
|
||||
}
|
||||
else {
|
||||
accumulatedPath = `${accumulatedPath}/${segment}`
|
||||
}
|
||||
|
||||
return {
|
||||
name: 'Manage Configs',
|
||||
translatedName: () => v,
|
||||
translatedName: () => decodedSegment,
|
||||
path: '/config',
|
||||
query: {
|
||||
dir,
|
||||
dir: accumulatedPath,
|
||||
},
|
||||
hasChildren: false,
|
||||
}
|
||||
|
@ -82,10 +85,13 @@ watch(route, () => {
|
|||
})
|
||||
|
||||
function goBack() {
|
||||
const pathSegments = basePath.value.split('/').slice(0, -2)
|
||||
const encodedPath = pathSegments.length > 0 ? pathSegments.join('/') : ''
|
||||
|
||||
router.push({
|
||||
path: '/config',
|
||||
query: {
|
||||
dir: `${basePath.value.split('/').slice(0, -2).join('/')}` || undefined,
|
||||
dir: encodedPath || undefined,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -144,13 +150,22 @@ const refRename = useTemplateRef('refRename')
|
|||
@click="() => {
|
||||
if (!record.is_dir) {
|
||||
router.push({
|
||||
path: `/config/${basePath}${record.name}/edit`,
|
||||
path: `/config/${encodeURIComponent(record.name)}/edit`,
|
||||
query: {
|
||||
basePath,
|
||||
},
|
||||
})
|
||||
}
|
||||
else {
|
||||
let encodedPath = '';
|
||||
if (basePath) {
|
||||
encodedPath = basePath;
|
||||
}
|
||||
encodedPath += encodeURIComponent(record.name);
|
||||
|
||||
router.push({
|
||||
query: {
|
||||
dir: basePath + record.name,
|
||||
dir: encodedPath,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
@ -29,7 +29,10 @@ function save() {
|
|||
modify.value = false
|
||||
message.success($gettext('Renamed successfully'))
|
||||
router.push({
|
||||
path: `/config/${r.path}/edit`,
|
||||
path: `/config/${encodeURIComponent(buffer.value)}/edit`,
|
||||
query: {
|
||||
basePath: encodeURIComponent(props.dir!),
|
||||
},
|
||||
})
|
||||
}).finally(() => {
|
||||
loading.value = false
|
||||
|
|
|
@ -37,9 +37,11 @@ function ok() {
|
|||
const otpModal = use2FAModal()
|
||||
|
||||
otpModal.open().then(() => {
|
||||
config.rename(basePath, orig_name, new_name, sync_node_ids).then(() => {
|
||||
// Note: API will handle URL encoding of path segments
|
||||
config.rename(basePath, orig_name, new_name, sync_node_ids).then(r => {
|
||||
visible.value = false
|
||||
message.success($gettext('Rename successfully'))
|
||||
|
||||
emit('renamed')
|
||||
})
|
||||
})
|
||||
|
|
|
@ -22,10 +22,12 @@ const configColumns = [{
|
|||
)
|
||||
}
|
||||
|
||||
const displayName = args.text || ''
|
||||
|
||||
return (
|
||||
<div class="flex">
|
||||
{renderIcon(args.record.is_dir)}
|
||||
{args.text}
|
||||
{displayName}
|
||||
</div>
|
||||
)
|
||||
},
|
||||
|
|
|
@ -19,7 +19,7 @@ import { message } from 'ant-design-vue'
|
|||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const name = computed(() => route.params?.name?.toString() ?? '')
|
||||
const name = computed(() => decodeURIComponent(route.params?.name?.toString() ?? ''))
|
||||
|
||||
const ngx_config: NgxConfig = reactive({
|
||||
name: '',
|
||||
|
@ -151,7 +151,7 @@ async function save() {
|
|||
}).then(r => {
|
||||
handleResponse(r)
|
||||
router.push({
|
||||
path: `/sites/${filename.value}`,
|
||||
path: `/sites/${encodeURIComponent(filename.value)}`,
|
||||
query: route.query,
|
||||
})
|
||||
message.success($gettext('Saved successfully'))
|
||||
|
|
|
@ -26,7 +26,7 @@ function save() {
|
|||
modify.value = false
|
||||
message.success($gettext('Renamed successfully'))
|
||||
router.push({
|
||||
path: `/sites/${buffer.value}`,
|
||||
path: `/sites/${encodeURIComponent(buffer.value)}`,
|
||||
})
|
||||
}).finally(() => {
|
||||
loading.value = false
|
||||
|
|
|
@ -166,7 +166,7 @@ function handleBatchUpdated() {
|
|||
}"
|
||||
:scroll-x="1600"
|
||||
@click-edit="(r: string) => router.push({
|
||||
path: `/sites/${r}`,
|
||||
path: `/sites/${encodeURIComponent(r)}`,
|
||||
})"
|
||||
@click-batch-modify="handleClickBatchEdit"
|
||||
>
|
||||
|
|
|
@ -19,11 +19,7 @@ import { message } from 'ant-design-vue'
|
|||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const name = ref(route.params.name.toString())
|
||||
|
||||
watch(route, () => {
|
||||
name.value = route.params?.name?.toString() ?? ''
|
||||
})
|
||||
const name = computed(() => decodeURIComponent(route.params?.name?.toString() ?? ''))
|
||||
|
||||
const ngxConfig: NgxConfig = reactive({
|
||||
name: '',
|
||||
|
@ -139,7 +135,7 @@ async function save() {
|
|||
}).then(r => {
|
||||
handleResponse(r)
|
||||
router.push({
|
||||
path: `/streams/${filename.value}`,
|
||||
path: `/streams/${encodeURIComponent(filename.value)}`,
|
||||
query: route.query,
|
||||
})
|
||||
message.success($gettext('Saved successfully'))
|
||||
|
|
|
@ -26,7 +26,7 @@ function save() {
|
|||
modify.value = false
|
||||
message.success($gettext('Renamed successfully'))
|
||||
router.push({
|
||||
path: `/streams/${buffer.value}`,
|
||||
path: `/streams/${encodeURIComponent(buffer.value)}`,
|
||||
})
|
||||
}).finally(() => {
|
||||
loading.value = false
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue