[Feature] Add save interface. (#7)
* [Feature] Add save interface.
* [Fix] Revise ts.
diff --git a/studio/components/files/index.tsx b/studio/components/files/index.tsx
index c666390..c4a0eb0 100644
--- a/studio/components/files/index.tsx
+++ b/studio/components/files/index.tsx
@@ -52,8 +52,8 @@
expose({ refresh })
const renderLabel = (info: { option: TreeOption }): VNodeChild => {
- const { isCreate, label, type } = info.option as IFileRecord
- return !isCreate
+ const { isEditing, label, type } = info.option as IFileRecord
+ return !isEditing
? `${label}${type ? '.' + FILE_TYPES_SUFFIX[type] : ''}`
: h(
NInput,
@@ -63,7 +63,9 @@
onBlur: onBlur,
ref: props.inputRef
},
- { suffix: () => (type ? '.' + FILE_TYPES_SUFFIX[type] : '') }
+ {
+ suffix: () => (type ? '.' + FILE_TYPES_SUFFIX[type] : '')
+ }
)
}
return () => (
@@ -77,6 +79,8 @@
key={keyRef.value}
defaultExpandAll
expand-on-click
+ labelField='name'
+ keyField='id'
></NTree>
)
}
diff --git a/studio/components/studio-sider/helper.ts b/studio/components/studio-sider/helper.ts
new file mode 100644
index 0000000..443f6fc
--- /dev/null
+++ b/studio/components/studio-sider/helper.ts
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import type { IFileRecord } from './types'
+
+export const sameNameValidator = (
+ name: string,
+ list: IFileRecord[]
+): boolean => {
+ return list.some((record) => record.name === name)
+}
diff --git a/studio/components/studio-sider/use-file.ts b/studio/components/studio-sider/use-file.ts
index a4acb07..ee44e2b 100644
--- a/studio/components/studio-sider/use-file.ts
+++ b/studio/components/studio-sider/use-file.ts
@@ -15,15 +15,22 @@
* limitations under the License.
*/
import { reactive, Ref, nextTick } from 'vue'
+import { useMessage } from 'naive-ui'
+import { addFile } from '@/service/modules/file'
+import { useLocale } from '@/hooks'
+import { sameNameValidator } from './helper'
import type { IFileState, FileType, IFileRecord } from './types'
export const useFile = (inputRef: Ref, fileRef: Ref) => {
const state = reactive({
currentKey: 0,
- files: [],
+ files: [{ type: '', id: 1, name: '123', pid: 0 }],
isCreating: false
} as IFileState)
+ const message = useMessage()
+ const { t } = useLocale()
+
const filesCached = {} as { [key: number]: IFileRecord }
const freshFiles = () => {
@@ -33,52 +40,68 @@
const getCurrentFolderKey = (): number => {
if (state.currentKey === 0) return 0
const currentRecord = filesCached[state.currentKey]
- return currentRecord.type ? currentRecord.pid : currentRecord.key
+ return currentRecord.type ? currentRecord.pid : currentRecord.id
}
- const create = async (isFile: boolean, type?: FileType) => {
+ const create = async (isFile: boolean, type: FileType | '') => {
if (state.isCreating) return
state.isCreating = true
const currentFolderKey = getCurrentFolderKey()
const record = {
- isCreate: true,
- key: Date.now(),
- label: '',
+ isEditing: true,
+ id: Date.now(),
+ name: '',
pid: currentFolderKey
} as IFileRecord
- isFile ? (record.type = type) : (record.children = [])
+ record.type = type
+ !isFile && (record.children = [])
- filesCached[record.key] = record
+ filesCached[record.id] = record
if (currentFolderKey === 0) {
state.files.unshift(record)
} else {
- filesCached[currentFolderKey].children.unshift(record)
+ filesCached[currentFolderKey].children?.unshift(record)
}
- state.currentKey = record.key
+ state.currentKey = record.id
freshFiles()
await nextTick()
inputRef.value?.focus()
}
+ const save = async () => {
+ const currentRecord = filesCached[state.currentKey]
+ try {
+ const { id } = await addFile(currentRecord.pid, {
+ type: currentRecord.type || '',
+ name: currentRecord.name
+ })
+ message.success(t('saved_successfully'))
+ currentRecord.id = id
+ return true
+ } catch (err) {
+ return false
+ }
+ }
+
const onCreateFile = (type: FileType) => void create(true, type)
- const onCreateFolder = () => void create(false)
+ const onCreateFolder = () => void create(false, '')
const onSelectFile = (key: number) => {
state.currentKey = key
}
- const onInputBlur = (value: string) => {
+ const onInputBlur = async (value: string) => {
state.isCreating = false
if (!value) {
const currentFolderKey = getCurrentFolderKey()
currentFolderKey
- ? filesCached[currentFolderKey].children.shift()
+ ? filesCached[currentFolderKey].children?.shift()
: state.files.shift()
delete filesCached[state.currentKey]
@@ -88,9 +111,23 @@
freshFiles()
return
}
- filesCached[state.currentKey].isCreate = false
- filesCached[state.currentKey].label = value
- freshFiles()
+
+ const pid = filesCached[state.currentKey].pid
+ const isSame = sameNameValidator(
+ value,
+ pid ? filesCached[pid].children || [] : state.files
+ )
+ if (isSame) {
+ message.error(t('same_name_tips'))
+ return
+ }
+
+ const result = await save()
+ if (result) {
+ filesCached[state.currentKey].isEditing = false
+ filesCached[state.currentKey].name = value
+ freshFiles()
+ }
}
return { state, onCreateFile, onCreateFolder, onSelectFile, onInputBlur }
diff --git a/studio/locales/en_US.ts b/studio/locales/en_US.ts
index 6d2a562..2900b2b 100644
--- a/studio/locales/en_US.ts
+++ b/studio/locales/en_US.ts
@@ -16,7 +16,9 @@
*/
export const enUS = {
- test: 'Test'
+ success: 'Success',
+ saved_successfully: 'Saved successfully',
+ same_name_tips: 'Same name exits for files at the same level.'
}
export type Locale = typeof enUS
diff --git a/studio/locales/zh_CN.ts b/studio/locales/zh_CN.ts
index e451bcb..1822818 100644
--- a/studio/locales/zh_CN.ts
+++ b/studio/locales/zh_CN.ts
@@ -16,5 +16,7 @@
*/
export const zhCN = {
- test: '测试'
+ success: '成功',
+ saved_successfully: '保存成功',
+ same_name_tips: '同级文件存在相同名字'
}
diff --git a/studio/service/modules/file/index.ts b/studio/service/modules/file/index.ts
index 6c9f44e..3065801 100644
--- a/studio/service/modules/file/index.ts
+++ b/studio/service/modules/file/index.ts
@@ -16,7 +16,7 @@
*/
import { axios } from '@/service/service'
-import type { IFileContent } from './types'
+import type { IFileContent, IFileRecord, FileType } from './types'
export const getFileContent = (id: number): Promise<IFileContent> => {
return axios.get(`files/${id}`)
@@ -29,3 +29,12 @@
export const runFile = (id: number) => {
return axios.post(`files/${id}/run`)
}
+
+export const getFiles = (): Promise<IFileRecord[]> => axios.get('/files')
+
+export const addFile = (
+ pid: number,
+ data: { type: FileType | ''; name: string }
+): Promise<{ id: number }> => axios.put(`files/${pid}/add`, data)
+
+export const deleteFile = (id: number) => axios.delete(`/files/${id}`)
diff --git a/studio/service/modules/file/types.ts b/studio/service/modules/file/types.ts
index d4d66a0..755c6b3 100644
--- a/studio/service/modules/file/types.ts
+++ b/studio/service/modules/file/types.ts
@@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+export type { IFileRecord, FileType } from '@/types/file'
export interface IFileContent {
content: string
diff --git a/studio/types/file.ts b/studio/types/file.ts
index c8864d7..c46438f 100644
--- a/studio/types/file.ts
+++ b/studio/types/file.ts
@@ -29,11 +29,12 @@
}
export interface IFileRecord extends TreeOption {
- isCreate?: boolean
- type?: FileType
- key: number
- children: IFileRecord[]
+ isEditing?: boolean
+ type: FileType | ''
+ id: number
+ children?: IFileRecord[]
pid: number
+ name: string
}
export { TreeOption }