diff --git a/dolphinscheduler-ui-next/src/layouts/content/index.tsx b/dolphinscheduler-ui-next/src/layouts/content/index.tsx
index 402ce44614..88a740230d 100644
--- a/dolphinscheduler-ui-next/src/layouts/content/index.tsx
+++ b/dolphinscheduler-ui-next/src/layouts/content/index.tsx
@@ -93,7 +93,7 @@ const Content = defineComponent({
)}
-
+
diff --git a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
index 8216a03ea9..700d04ddf4 100644
--- a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
+++ b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
@@ -187,6 +187,34 @@ const resource = {
return: 'Return',
save: 'Save'
},
+ udf: {
+ udf_resources: 'UDF resources',
+ create_folder: 'Create Folder',
+ upload_udf_resources: 'Upload UDF Resources',
+ id: '#',
+ udf_source_name: 'UDF Resource Name',
+ whether_directory: 'Whether directory',
+ file_name: 'File Name',
+ file_size: 'File Size',
+ description: 'Description',
+ create_time: 'Create Time',
+ update_time: 'Update Time',
+ operation: 'Operation',
+ yes: 'Yes',
+ no: 'No',
+ edit: 'Edit',
+ download: 'Download',
+ delete: 'Delete',
+ delete_confirm: 'Delete?',
+ success: 'Success',
+ folder_name: 'Folder Name',
+ upload: 'Upload',
+ upload_files: 'Upload Files',
+ file_upload: 'File Upload',
+ enter_keyword_tips: 'Please enter keyword',
+ enter_name_tips: 'Please enter name',
+ enter_description_tips: 'Please enter description'
+ },
task_group_option: {
id: 'No.',
manage: 'Task group manage',
diff --git a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
index 2fc5a885bf..dfc5035fdd 100644
--- a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
+++ b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
@@ -189,6 +189,34 @@ const resource = {
return: '返回',
save: '保存'
},
+ udf: {
+ udf_resources: 'UDF资源',
+ create_folder: '创建文件夹',
+ upload_udf_resources: '上传UDF资源',
+ id: '编号',
+ udf_source_name: 'UDF资源名称',
+ whether_directory: '是否文件夹',
+ file_name: '文件名称',
+ file_size: '文件大小',
+ description: '描述',
+ create_time: '创建时间',
+ update_time: '更新时间',
+ operation: '操作',
+ yes: '是',
+ no: '否',
+ edit: '编辑',
+ download: '下载',
+ delete: '删除',
+ success: '成功',
+ folder_name: '文件夹名称',
+ upload: '上传',
+ upload_files: '上传文件',
+ file_upload: '文件上传',
+ delete_confirm: '确定删除吗?',
+ enter_keyword_tips: '请输入关键词',
+ enter_name_tips: '请输入名称',
+ enter_description_tips: '请输入描述'
+ },
task_group_option: {
id: '编号',
manage: '任务组管理',
diff --git a/dolphinscheduler-ui-next/src/router/modules/resources.ts b/dolphinscheduler-ui-next/src/router/modules/resources.ts
index d6e0f4b0c1..38147ade39 100644
--- a/dolphinscheduler-ui-next/src/router/modules/resources.ts
+++ b/dolphinscheduler-ui-next/src/router/modules/resources.ts
@@ -77,6 +77,22 @@ export default {
title: '文件创建'
}
},
+ {
+ path: '/resource/resource-manage',
+ name: 'resource-manage',
+ component: components['resource'],
+ meta: {
+ title: '资源管理'
+ }
+ },
+ {
+ path: '/resource/resource-manage/:id',
+ name: 'resource-sub-manage',
+ component: components['resource'],
+ meta: {
+ title: '资源管理'
+ }
+ },
{
path: '/resource/task-group',
name: 'task-group-manage',
diff --git a/dolphinscheduler-ui-next/src/service/modules/resources/index.ts b/dolphinscheduler-ui-next/src/service/modules/resources/index.ts
index c3f915f3de..c6f44f243b 100644
--- a/dolphinscheduler-ui-next/src/service/modules/resources/index.ts
+++ b/dolphinscheduler-ui-next/src/service/modules/resources/index.ts
@@ -45,6 +45,17 @@ export function queryResourceListPaging(
})
}
+export function queryResourceById(
+ params: ResourceTypeReq & FullNameReq & IdReq,
+ id: number
+): any {
+ return axios({
+ url: `/resources/${id}`,
+ method: 'get',
+ params
+ })
+}
+
export function createResource(
data: CreateReq & FileNameReq & NameReq & ResourceTypeReq
): any {
diff --git a/dolphinscheduler-ui-next/src/views/datasource/datasource-list/index.tsx b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/index.tsx
index 01d6d2e050..a59396b3cd 100644
--- a/dolphinscheduler-ui-next/src/views/datasource/datasource-list/index.tsx
+++ b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/index.tsx
@@ -36,8 +36,8 @@ const list = defineComponent({
name: 'list',
setup() {
const { t } = useI18n()
- let showDetailModal = ref(false)
- let selectId = ref()
+ const showDetailModal = ref(false)
+ const selectId = ref()
const { columnsRef } = useColumns((id: number, type: 'edit' | 'delete') => {
if (type === 'edit') {
diff --git a/dolphinscheduler-ui-next/src/views/datasource/datasource-list/json-highlight.tsx b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/json-highlight.tsx
index 162bcd67ff..c69cf0092e 100644
--- a/dolphinscheduler-ui-next/src/views/datasource/datasource-list/json-highlight.tsx
+++ b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/json-highlight.tsx
@@ -45,7 +45,7 @@ const syntaxHighlight = (json: string) => {
const entries = Object.entries(JSON.parse(json))
for (let i = 0, len = entries.length; i < len; i++) {
const [key, value] = entries[i]
- let type: string = ''
+ let type = ''
if (isBoolean(value) || value === null) {
type = 'info'
} else if (isNumber(value)) {
diff --git a/dolphinscheduler-ui-next/src/views/resource/udf/resource/components/folder-modal.tsx b/dolphinscheduler-ui-next/src/views/resource/udf/resource/components/folder-modal.tsx
new file mode 100644
index 0000000000..ef509cbe6c
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/resource/udf/resource/components/folder-modal.tsx
@@ -0,0 +1,106 @@
+/*
+ * 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 { defineComponent, toRefs, PropType, watch } from 'vue'
+import { NForm, NFormItem, NInput } from 'naive-ui'
+import { useI18n } from 'vue-i18n'
+import Modal from '@/components/modal'
+import { useForm } from './use-form'
+import { useModal } from './use-modal'
+import type { IUdf } from '../types'
+
+const props = {
+ row: {
+ type: Object as PropType,
+ default: {}
+ },
+ show: {
+ type: Boolean as PropType,
+ default: false
+ }
+}
+
+export default defineComponent({
+ name: 'ResourceFileFolder',
+ props,
+ emits: ['update:show', 'updateList'],
+ setup(props, ctx) {
+ const { folderState: state } = useForm()
+
+ const { handleCreateResource, handleRenameResource } = useModal(state, ctx)
+
+ const hideModal = () => {
+ ctx.emit('update:show')
+ }
+
+ const handleCreate = () => {
+ handleCreateResource()
+ }
+
+ const handleRename = () => {
+ handleRenameResource(props.row.id)
+ }
+
+ watch(
+ () => props.row,
+ () => {
+ state.folderForm.name = props.row.alias
+ state.folderForm.description = props.row.description
+ }
+ )
+
+ return {
+ hideModal,
+ handleCreate,
+ handleRename,
+ ...toRefs(state)
+ }
+ },
+ render() {
+ const { t } = useI18n()
+
+ return (
+
+
+
+
+
+
+
+
+
+
+ )
+ }
+})
diff --git a/dolphinscheduler-ui-next/src/views/resource/udf/resource/components/upload-modal.tsx b/dolphinscheduler-ui-next/src/views/resource/udf/resource/components/upload-modal.tsx
new file mode 100644
index 0000000000..1379970a2b
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/resource/udf/resource/components/upload-modal.tsx
@@ -0,0 +1,106 @@
+/*
+ * 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 { defineComponent, toRefs, PropType } from 'vue'
+import { NForm, NFormItem, NInput, NUpload, NButton, NIcon } from 'naive-ui'
+import { useI18n } from 'vue-i18n'
+import Modal from '@/components/modal'
+import { useForm } from './use-form'
+import { useModal } from './use-modal'
+import { CloudUploadOutlined } from '@vicons/antd'
+
+const props = {
+ show: {
+ type: Boolean as PropType,
+ default: false
+ }
+}
+
+export default defineComponent({
+ name: 'ResourceFileFolder',
+ props,
+ emits: ['update:show', 'updateList'],
+ setup(props, ctx) {
+ const { uploadState: state } = useForm()
+ const { handleUploadFile } = useModal(state, ctx)
+
+ const hideModal = () => {
+ ctx.emit('update:show')
+ }
+
+ const handleFolder = () => {
+ handleUploadFile()
+ }
+
+ const customRequest = ({ file }: any) => {
+ state.uploadForm.name = file.name
+ state.uploadForm.file = file.file
+ }
+
+ return {
+ hideModal,
+ handleFolder,
+ customRequest,
+ ...toRefs(state)
+ }
+ },
+ render() {
+ const { t } = useI18n()
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ {t('resource.udf.upload')}
+
+
+
+
+
+
+
+
+ )
+ }
+})
diff --git a/dolphinscheduler-ui-next/src/views/resource/udf/resource/components/use-form.ts b/dolphinscheduler-ui-next/src/views/resource/udf/resource/components/use-form.ts
new file mode 100644
index 0000000000..424152365c
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/resource/udf/resource/components/use-form.ts
@@ -0,0 +1,73 @@
+/*
+ * 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 { reactive, ref } from 'vue'
+import { useI18n } from 'vue-i18n'
+import type { FormRules } from 'naive-ui'
+
+export const useForm = () => {
+ const { t } = useI18n()
+
+ const folderState = reactive({
+ folderFormRef: ref(),
+ folderForm: {
+ pid: -1,
+ type: 'UDF',
+ name: '',
+ description: '',
+ currentDir: '/'
+ },
+ rules: {
+ name: {
+ required: true,
+ trigger: ['input', 'blur'],
+ validator() {
+ if (folderState.folderForm.name === '') {
+ return new Error(t('resource.udf.enter_name_tips'))
+ }
+ }
+ }
+ } as FormRules
+ })
+
+ const uploadState = reactive({
+ uploadFormRef: ref(),
+ uploadForm: {
+ name: '',
+ file: '',
+ description: '',
+ pid: -1,
+ currentDir: '/'
+ },
+ rules: {
+ name: {
+ required: true,
+ trigger: ['input', 'blur'],
+ validator() {
+ if (uploadState.uploadForm.name === '') {
+ return new Error(t('resource.udf.enter_name_tips'))
+ }
+ }
+ }
+ } as FormRules
+ })
+
+ return {
+ folderState,
+ uploadState
+ }
+}
diff --git a/dolphinscheduler-ui-next/src/views/resource/udf/resource/components/use-modal.ts b/dolphinscheduler-ui-next/src/views/resource/udf/resource/components/use-modal.ts
new file mode 100644
index 0000000000..c9210bdb78
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/resource/udf/resource/components/use-modal.ts
@@ -0,0 +1,114 @@
+/*
+ * 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 { SetupContext } from 'vue'
+import { useI18n } from 'vue-i18n'
+import { useRouter } from 'vue-router'
+import type { Router } from 'vue-router'
+import { useFileStore } from '@/store/file/file'
+import {
+ createDirectory,
+ createResource,
+ updateResource
+} from '@/service/modules/resources'
+
+export function useModal(
+ state: any,
+ ctx: SetupContext<('update:show' | 'updateList')[]>
+) {
+ const { t } = useI18n()
+ const router: Router = useRouter()
+ const fileStore = useFileStore()
+
+ const handleCreateResource = async () => {
+ const pid = router.currentRoute.value.params.id || -1
+ const currentDir = pid === -1 ? '/' : fileStore.getCurrentDir || '/'
+
+ submitRequest(
+ async () =>
+ await createDirectory({
+ ...state.folderForm,
+ ...{ pid, currentDir }
+ })
+ )
+ }
+
+ const handleRenameResource = async (id: number) => {
+ submitRequest(async () => {
+ await updateResource(
+ {
+ ...state.folderForm,
+ ...{ id }
+ },
+ id
+ )
+ })
+ }
+
+ const submitRequest = (serviceHandle: any) => {
+ state.folderFormRef.validate(async (valid: any) => {
+ if (!valid) {
+ try {
+ await serviceHandle()
+ window.$message.success(t('resource.udf.success'))
+ ctx.emit('updateList')
+ ctx.emit('update:show')
+ } catch (error: any) {
+ window.$message.error(error.message)
+ }
+ }
+ })
+ }
+
+ const resetUploadForm = () => {
+ state.uploadForm.name = ''
+ state.uploadForm.file = ''
+ state.uploadForm.description = ''
+ }
+
+ const handleUploadFile = () => {
+ state.uploadFormRef.validate(async (valid: any) => {
+ const pid = router.currentRoute.value.params.id || -1
+ const currentDir = pid === -1 ? '/' : fileStore.getCurrentDir || '/'
+ if (!valid) {
+ const formData = new FormData()
+ formData.append('file', state.uploadForm.file)
+ formData.append('type', 'UDF')
+ formData.append('name', state.uploadForm.name)
+ formData.append('pid', String(pid))
+ formData.append('currentDir', currentDir)
+ formData.append('description', state.uploadForm.description)
+
+ try {
+ await createResource(formData as any)
+ window.$message.success(t('resource.udf.success'))
+ ctx.emit('updateList')
+ ctx.emit('update:show')
+ resetUploadForm()
+ } catch (error: any) {
+ window.$message.error(error.message)
+ }
+ }
+ })
+ }
+
+ return {
+ handleCreateResource,
+ handleRenameResource,
+ handleUploadFile
+ }
+}
diff --git a/dolphinscheduler-ui-next/src/views/resource/udf/resource/index.module.scss b/dolphinscheduler-ui-next/src/views/resource/udf/resource/index.module.scss
new file mode 100644
index 0000000000..db594602ae
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/resource/udf/resource/index.module.scss
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+.content {
+ width: 100%;
+
+ .card {
+ margin-bottom: 8px;
+ }
+
+ .header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin: 10px 0;
+ .right {
+ > .search {
+ .list {
+ float: right;
+ margin: 3px 0 3px 4px;
+ }
+ }
+ }
+ }
+
+ .table {
+ table {
+ width: 100%;
+ tr {
+ height: 40px;
+ font-size: 12px;
+ th,td{
+ &:nth-child(1) {
+ width: 50px;
+ text-align: center;
+ }
+ }
+ th {
+ &:nth-child(1) {
+ width: 60px;
+ text-align: center;
+ }
+ >span {
+ font-size: 12px;
+ color: #555;
+ }
+ }
+ }
+ }
+ }
+
+ .pagination {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin-top: 20px;
+ }
+
+ .links {
+ color: #2080f0;
+ text-decoration: none;
+ &:hover {
+ text-decoration: underline;
+ }
+ }
+}
+
diff --git a/dolphinscheduler-ui-next/src/views/resource/udf/resource/index.tsx b/dolphinscheduler-ui-next/src/views/resource/udf/resource/index.tsx
new file mode 100644
index 0000000000..bed26cc56e
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/resource/udf/resource/index.tsx
@@ -0,0 +1,197 @@
+/*
+ * 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 { defineComponent, Ref, toRefs, onMounted, toRef } from 'vue'
+import {
+ NIcon,
+ NSpace,
+ NDataTable,
+ NButton,
+ NPagination,
+ NInput,
+ NBreadcrumb,
+ NBreadcrumbItem
+} from 'naive-ui'
+import { useI18n } from 'vue-i18n'
+import { SearchOutlined } from '@vicons/antd'
+import Card from '@/components/card'
+import FolderModal from './components/folder-modal'
+import UploadModal from './components/upload-modal'
+import { useTable } from './use-table'
+import styles from './index.module.scss'
+
+export default defineComponent({
+ name: 'resource-manage',
+ setup() {
+ const { variables, getTableData, goUdfManage, goBread } = useTable()
+
+ const requestData = () => {
+ getTableData({
+ id: variables.id,
+ pageSize: variables.pageSize,
+ pageNo: variables.page,
+ searchVal: variables.searchVal
+ })
+ }
+
+ const handleUpdateList = () => {
+ requestData()
+ }
+
+ const handleChangePageSize = () => {
+ variables.page = 1
+ requestData()
+ }
+
+ const handleSearch = () => {
+ variables.page = 1
+ requestData()
+ }
+
+ const handleShowModal = (showRef: Ref) => {
+ showRef.value = true
+ }
+
+ const handleCreateFolder = () => {
+ variables.row = {}
+ handleShowModal(toRef(variables, 'folderShowRef'))
+ }
+
+ const handleUploadFile = () => {
+ handleShowModal(toRef(variables, 'uploadShowRef'))
+ }
+
+ const handleBread = (index: number) => {
+ let breadName = ''
+ variables.breadList.forEach((item, i) => {
+ if (i <= index) {
+ breadName = breadName + '/' + item
+ }
+ })
+ goBread(breadName)
+ }
+
+ onMounted(() => {
+ requestData()
+ })
+
+ return {
+ goUdfManage,
+ handleBread,
+ requestData,
+ handleSearch,
+ handleUpdateList,
+ handleCreateFolder,
+ handleUploadFile,
+ handleChangePageSize,
+ ...toRefs(variables)
+ }
+ },
+ render() {
+ const { t } = useI18n()
+
+ return (
+
+
+
+
+
+ {{
+ default: () => (
+
+
+
+
+ ),
+ header: () => (
+
+
+ this.goUdfManage()}>
+ {t('resource.udf.udf_resources')}
+
+
+ {this.breadList.map((item, index) => (
+
+ this.handleBread(index)}
+ >
+ {item}
+
+
+ ))}
+
+ )
+ }}
+
+
+
+
+ )
+ }
+})
diff --git a/dolphinscheduler-ui-next/src/views/resource/udf/resource/types.ts b/dolphinscheduler-ui-next/src/views/resource/udf/resource/types.ts
new file mode 100644
index 0000000000..b2cfbe57c5
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/resource/udf/resource/types.ts
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+export interface IUdfResourceParam {
+ id: number
+ pageSize: number
+ pageNo: number
+ searchVal: string | undefined
+}
+
+export interface IUdf {
+ id: number
+ pid: number
+ userId: number
+ fileName: string
+ fullName: string
+ alias: string
+ directory: boolean
+ size: number
+ type: 'UDF'
+ description: string
+ createTime: string
+ updateTime: string
+}
diff --git a/dolphinscheduler-ui-next/src/views/resource/udf/resource/use-table.ts b/dolphinscheduler-ui-next/src/views/resource/udf/resource/use-table.ts
new file mode 100644
index 0000000000..b7f724303d
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/resource/udf/resource/use-table.ts
@@ -0,0 +1,279 @@
+/*
+ * 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 { h, ref, reactive } from 'vue'
+import { useI18n } from 'vue-i18n'
+import { useRouter } from 'vue-router'
+import { bytesToSize } from '@/utils/common'
+import { useFileStore } from '@/store/file/file'
+import type { Router } from 'vue-router'
+import type { TableColumns } from 'naive-ui/es/data-table/src/interface'
+import { NSpace, NTooltip, NButton, NPopconfirm } from 'naive-ui'
+import { EditOutlined, DeleteOutlined, DownloadOutlined } from '@vicons/antd'
+import { useAsyncState } from '@vueuse/core'
+import {
+ queryResourceListPaging,
+ downloadResource,
+ deleteResource,
+ queryResourceById
+} from '@/service/modules/resources'
+import { IUdfResourceParam } from './types'
+import styles from './index.module.scss'
+
+const goSubFolder = (router: Router, item: any) => {
+ const fileStore = useFileStore()
+ fileStore.setFileInfo(`${item.alias}|${item.size}`)
+
+ if (item.directory) {
+ fileStore.setCurrentDir(`${item.fullName}`)
+ router.push({ name: 'resource-sub-manage', params: { id: item.id } })
+ }
+}
+
+export function useTable() {
+ const { t } = useI18n()
+ const router: Router = useRouter()
+ const fileStore = useFileStore()
+
+ const columns: TableColumns = [
+ {
+ title: t('resource.udf.id'),
+ key: 'id',
+ width: 50,
+ render: (_row, index) => index + 1
+ },
+ {
+ title: t('resource.udf.udf_source_name'),
+ key: 'alias',
+ render: (row) => {
+ if (!row.directory) {
+ return row.alias
+ } else {
+ return h(
+ 'a',
+ {
+ href: 'javascript:',
+ class: styles.links,
+ onClick: () => goSubFolder(router, row)
+ },
+ {
+ default: () => {
+ return row.alias
+ }
+ }
+ )
+ }
+ }
+ },
+ {
+ title: t('resource.udf.whether_directory'),
+ key: 'whether_directory',
+ render: (row) =>
+ row.directory ? t('resource.file.yes') : t('resource.file.no')
+ },
+ {
+ title: t('resource.udf.file_name'),
+ key: 'fileName'
+ },
+ {
+ title: t('resource.udf.file_size'),
+ key: 'size',
+ render: (row) => bytesToSize(row.size)
+ },
+ {
+ title: t('resource.udf.description'),
+ key: 'description'
+ },
+ {
+ title: t('resource.udf.create_time'),
+ key: 'createTime'
+ },
+ {
+ title: t('resource.udf.update_time'),
+ key: 'updateTime'
+ },
+ {
+ title: t('resource.udf.operation'),
+ key: 'operation',
+ render: (row) => {
+ return h(NSpace, null, {
+ default: () => [
+ h(
+ NTooltip,
+ {},
+ {
+ trigger: () =>
+ h(
+ NButton,
+ {
+ circle: true,
+ type: 'info',
+ size: 'tiny',
+ onClick: () => {
+ handleEdit(row)
+ }
+ },
+ {
+ icon: () => h(EditOutlined)
+ }
+ ),
+ default: () => t('resource.udf.edit')
+ }
+ ),
+ h(
+ NTooltip,
+ {},
+ {
+ trigger: () =>
+ h(
+ NButton,
+ {
+ circle: true,
+ type: 'info',
+ size: 'tiny',
+ disabled: row?.directory ? true : false,
+ onClick: () => downloadResource(row.id)
+ },
+ {
+ icon: () => h(DownloadOutlined)
+ }
+ ),
+ default: () => t('resource.udf.download')
+ }
+ ),
+ h(
+ NPopconfirm,
+ {
+ onPositiveClick: () => {
+ handleDelete(row.id)
+ }
+ },
+ {
+ trigger: () =>
+ h(
+ NTooltip,
+ {},
+ {
+ trigger: () =>
+ h(
+ NButton,
+ {
+ circle: true,
+ type: 'error',
+ size: 'tiny'
+ },
+ {
+ icon: () => h(DeleteOutlined)
+ }
+ ),
+ default: () => t('resource.udf.delete')
+ }
+ ),
+ default: () => t('resource.udf.delete_confirm')
+ }
+ )
+ ]
+ })
+ }
+ }
+ ]
+
+ const variables = reactive({
+ columns,
+ row: {},
+ tableData: [],
+ breadList: [],
+ id: ref(Number(router.currentRoute.value.params.id) || -1),
+ page: ref(1),
+ pageSize: ref(10),
+ searchVal: ref(),
+ totalPage: ref(1),
+ folderShowRef: ref(false),
+ uploadShowRef: ref(false)
+ })
+
+ const getTableData = (params: IUdfResourceParam) => {
+ const { state } = useAsyncState(
+ queryResourceListPaging({ ...params, type: 'UDF' }).then((res: any) => {
+ const breadList =
+ variables.id === -1
+ ? []
+ : (fileStore.getCurrentDir.split('/') as Array)
+ breadList.shift()
+
+ variables.breadList = breadList
+ variables.totalPage = res.totalPage
+ variables.tableData = res.totalList.map((item: any) => {
+ return { ...item }
+ })
+ }),
+ { total: 0, table: [] }
+ )
+ return state
+ }
+
+ const handleEdit = (row: any) => {
+ variables.folderShowRef = true
+ variables.row = row
+ }
+
+ const handleDelete = (id: number) => {
+ /* after deleting data from the current page, you need to jump forward when the page is empty. */
+ if (variables.tableData.length === 1 && variables.page > 1) {
+ variables.page -= 1
+ }
+
+ deleteResource(id).then(() =>
+ getTableData({
+ id: variables.id,
+ pageSize: variables.pageSize,
+ pageNo: variables.page,
+ searchVal: variables.searchVal
+ })
+ )
+ }
+
+ const goUdfManage = () => {
+ router.push({ name: 'resource-manage' })
+ }
+
+ const goBread = (fullName: string) => {
+ const { id } = variables
+ queryResourceById(
+ {
+ id,
+ type: 'UDF',
+ fullName
+ },
+ id
+ )
+ .then((res: any) => {
+ fileStore.setCurrentDir(res.fullName)
+ router.push({ name: 'resource-sub-manage', params: { id: res.id } })
+ })
+ .catch((error: any) => {
+ window.$message.error(error.message)
+ })
+ }
+
+ return {
+ variables,
+ getTableData,
+ goUdfManage,
+ goBread
+ }
+}