This is an automated email from the ASF dual-hosted git repository.
nicholasjiang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-paimon-webui.git
The following commit(s) were added to refs/heads/main by this push:
new 2509c30 [Feature] Introduce context menu (#52)
2509c30 is described below
commit 2509c30345c57601f2bb3afc692f38c700ef4cdc
Author: labbomb <[email protected]>
AuthorDate: Sat Oct 14 15:16:19 2023 +0800
[Feature] Introduce context menu (#52)
---
.../context-menu/index.module.scss} | 22 +---
.../src/components/context-menu/index.tsx | 118 +++++++++++++++++++++
.../src/locales/en/modules/playground.ts | 8 ++
.../src/locales/zh/modules/playground.ts | 8 ++
.../components/query/components/tabs/index.tsx | 51 ++++++++-
.../workbench/components/menu-tree/index.tsx | 71 +++++++++----
.../components/workbench/components/tabs/index.tsx | 51 ++++++++-
7 files changed, 283 insertions(+), 46 deletions(-)
diff --git a/paimon-web-ui-new/src/locales/zh/modules/playground.ts
b/paimon-web-ui-new/src/components/context-menu/index.module.scss
similarity index 63%
copy from paimon-web-ui-new/src/locales/zh/modules/playground.ts
copy to paimon-web-ui-new/src/components/context-menu/index.module.scss
index 2787b5b..7d9d27b 100644
--- a/paimon-web-ui-new/src/locales/zh/modules/playground.ts
+++ b/paimon-web-ui-new/src/components/context-menu/index.module.scss
@@ -15,23 +15,7 @@ KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License. */
-export default {
- query: '查询',
- workbench: '工作台',
- task_operation_and_maintenance: '任务运维',
- settings: '设置',
- terminal: '终端',
- git_branch: 'Git 分支',
- data: '数据',
- saved_query: '已保存查询',
- query_record: '查询记录',
- search: '搜索',
- run: '运行',
- format: '格式化',
- save: '保存',
- clear: '清空',
- unfold: '展开',
- collapse: '折叠',
- logs: '日志',
- result: '结果',
+.context-menu {
+ width: 200px;
+ height: 100%;
}
diff --git a/paimon-web-ui-new/src/components/context-menu/index.tsx
b/paimon-web-ui-new/src/components/context-menu/index.tsx
new file mode 100644
index 0000000..718475e
--- /dev/null
+++ b/paimon-web-ui-new/src/components/context-menu/index.tsx
@@ -0,0 +1,118 @@
+/* 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 { TreeOption } from 'naive-ui'
+import styles from './index.module.scss'
+
+export default defineComponent({
+ name: 'ContextMenu',
+ props: {
+ x: {
+ type: Number as PropType<number>,
+ default: 0
+ },
+ y: {
+ type: Number as PropType<number>,
+ default: 0
+ },
+ visible: {
+ type: Boolean as PropType<boolean>,
+ default: false
+ },
+ type: {
+ type: Array as PropType<string[]>,
+ default: () => []
+ }
+ },
+ emits: ['update:visible', 'select'],
+ setup(props, { emit }) {
+ const { t } = useLocaleHooks()
+
+ const options = computed(() => ([
+ {
+ label: t('playground.new_folder'),
+ key: 'new_folder',
+ show: props.type.includes('folder')
+ },
+ {
+ label: t('playground.new_file'),
+ key: 'new_file',
+ show: props.type.includes('file')
+ },
+ {
+ label: t('playground.delete'),
+ key: 'delete',
+ show: props.type.includes('delete')
+ },
+ {
+ label: t('playground.rename'),
+ key: 'rename',
+ show: props.type.includes('rename')
+ },
+ {
+ label: t('playground.close_left'),
+ key: 'close_left',
+ show: props.type.includes('close_left')
+ },
+ {
+ label: t('playground.close_right'),
+ key: 'close_right',
+ show: props.type.includes('close_right')
+ },
+ {
+ label: t('playground.close_others'),
+ key: 'close_others',
+ show: props.type.includes('close_others')
+ },
+ {
+ label: t('playground.close_all'),
+ key: 'close_all',
+ show: props.type.includes('close_all')
+ }
+ ]))
+
+ const handleSelect = (keys: Array<string | number>, option:
Array<TreeOption | null>) => {
+ emit('select', keys, option)
+ }
+
+ const handleClickOutside = () => {
+ emit('update:visible', false)
+ }
+
+ return {
+ options,
+ handleSelect,
+ handleClickOutside
+ }
+ },
+ render() {
+ return (
+ <div class={styles['context-menu']}>
+ <n-dropdown
+ trigger="manual"
+ placement="bottom-start"
+ options={this.options}
+ show={this.visible}
+ x={this.x}
+ y={this.y}
+ on-select={this.handleSelect}
+ on-clickoutside={this.handleClickOutside}
+ />
+ </div>
+ )
+ }
+})
diff --git a/paimon-web-ui-new/src/locales/en/modules/playground.ts
b/paimon-web-ui-new/src/locales/en/modules/playground.ts
index 9babf17..c505377 100644
--- a/paimon-web-ui-new/src/locales/en/modules/playground.ts
+++ b/paimon-web-ui-new/src/locales/en/modules/playground.ts
@@ -34,4 +34,12 @@ export default {
collapse: 'Collapse',
logs: 'Logs',
result: 'Result',
+ new_folder: 'New Folder',
+ new_file: 'New File',
+ rename: 'Rename',
+ delete: 'Delete',
+ close_all: 'Close All',
+ close_others: 'Close Others',
+ close_right: 'Close Right',
+ close_left: 'Close Left',
}
diff --git a/paimon-web-ui-new/src/locales/zh/modules/playground.ts
b/paimon-web-ui-new/src/locales/zh/modules/playground.ts
index 2787b5b..7a52d1a 100644
--- a/paimon-web-ui-new/src/locales/zh/modules/playground.ts
+++ b/paimon-web-ui-new/src/locales/zh/modules/playground.ts
@@ -34,4 +34,12 @@ export default {
collapse: '折叠',
logs: '日志',
result: '结果',
+ new_folder: '新建文件夹',
+ new_file: '新建文件',
+ rename: '重命名',
+ delete: '删除',
+ close_all: '关闭所有',
+ close_others: '关闭其他',
+ close_right: '关闭右侧',
+ close_left: '关闭左侧',
}
diff --git
a/paimon-web-ui-new/src/views/playground/components/query/components/tabs/index.tsx
b/paimon-web-ui-new/src/views/playground/components/query/components/tabs/index.tsx
index 706953c..9d1f4aa 100644
---
a/paimon-web-ui-new/src/views/playground/components/query/components/tabs/index.tsx
+++
b/paimon-web-ui-new/src/views/playground/components/query/components/tabs/index.tsx
@@ -16,6 +16,7 @@ specific language governing permissions and limitations
under the License. */
import styles from './index.module.scss'
+import ContextMenu from '@/components/context-menu';
export default defineComponent({
name: 'EditorTabs',
@@ -25,6 +26,7 @@ export default defineComponent({
const tabVariables = reactive({
chooseTab: '',
panelsList: [] as any,
+ row: {} as any
})
const handleAdd = () => {
@@ -59,6 +61,40 @@ export default defineComponent({
treeData.value = data
})
+ const contextMenuVariables = reactive({
+ x: 0,
+ y: 0,
+ isShow: false
+ })
+
+ const openContextMenu = (e: MouseEvent, item: any) => {
+ e.preventDefault()
+ contextMenuVariables.x = e.pageX
+ contextMenuVariables.y = e.pageY
+ contextMenuVariables.isShow = true
+ tabVariables.row = item
+ tabVariables.chooseTab = tabVariables.row.key
+ }
+
+ const handleContextMenuSelect = (keys: string) => {
+ const index = tabVariables.panelsList.findIndex((item: any) => item.key
=== tabVariables.row.key)
+ switch (keys) {
+ case 'close_left':
+ tabVariables.panelsList.splice(0, index)
+ break;
+ case 'close_right':
+ tabVariables.panelsList.splice(index + 1)
+ break;
+ case 'close_others':
+ tabVariables.panelsList = [tabVariables.row]
+ break;
+ case 'close_all':
+ tabVariables.panelsList = []
+ break;
+ }
+ contextMenuVariables.isShow = false
+ }
+
onMounted(() => {
mittBus.emit('initTabData', tabVariables)
})
@@ -67,7 +103,10 @@ export default defineComponent({
...toRefs(tabVariables),
handleAdd,
handleClose,
- changeTreeChoose
+ changeTreeChoose,
+ openContextMenu,
+ ...toRefs(contextMenuVariables),
+ handleContextMenuSelect
}
},
render() {
@@ -92,7 +131,7 @@ export default defineComponent({
<n-tab-pane name={item.key}
v-slots={{
tab: () => (
- <div class={styles.tabs}>
+ <div class={styles.tabs} onContextmenu={(e: MouseEvent) =>
this.openContextMenu(e, item)}>
<div class={styles.dot}></div>
<div>{item.tableName}</div>
{!item.isSaved && <div class={styles.asterisk}>*</div>}
@@ -103,6 +142,14 @@ export default defineComponent({
))
}
</n-tabs>
+ <ContextMenu
+ x={this.x}
+ y={this.y}
+ visible={this.isShow}
+ type={['close_left', 'close_right', 'close_others', 'close_all']}
+ onUpdate:visible={() => this.isShow = false}
+ onSelect={this.handleContextMenuSelect}
+ />
</div>
);
}
diff --git
a/paimon-web-ui-new/src/views/playground/components/workbench/components/menu-tree/index.tsx
b/paimon-web-ui-new/src/views/playground/components/workbench/components/menu-tree/index.tsx
index 0cbc368..f1b581d 100644
---
a/paimon-web-ui-new/src/views/playground/components/workbench/components/menu-tree/index.tsx
+++
b/paimon-web-ui-new/src/views/playground/components/workbench/components/menu-tree/index.tsx
@@ -15,7 +15,7 @@ KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License. */
-import { CodeSlash, FileTrayFullOutline, Search, ServerOutline } from
'@vicons/ionicons5';
+import { FileTrayFullOutline, Search, FolderOpenOutline } from
'@vicons/ionicons5';
import styles from './index.module.scss'
import { NIcon, type TreeOption } from 'naive-ui';
@@ -29,22 +29,25 @@ export default defineComponent({
{
key: 'paimon2',
label: 'paimon2',
+ type: 'folder',
prefix: () =>
h(NIcon, null, {
- default: () => h(ServerOutline)
+ default: () => h(FolderOpenOutline)
}),
children: [
{
key: 'user',
label: 'user',
+ type: 'folder',
prefix: () =>
h(NIcon, null, {
- default: () => h(ServerOutline)
+ default: () => h(FolderOpenOutline)
}),
children: [
{
label: 'user_table',
key: '1',
+ type: 'file',
content: 'select * from abc where abc.a="abc";select * from
cba where cba.a="cba";',
prefix: () =>
h(NIcon, null, {
@@ -54,6 +57,7 @@ export default defineComponent({
{
label: 'people_table',
key: '2',
+ type: 'file',
content: 'select * from abc where abc.a="abc";',
prefix: () =>
h(NIcon, null, {
@@ -61,25 +65,6 @@ export default defineComponent({
})
}
]
- },
- {
- key: 'role',
- label: 'role',
- prefix: () =>
- h(NIcon, null, {
- default: () => h(ServerOutline)
- }),
- children: [
- {
- label: 'user_table',
- key: '3',
- content: 'select * from kkk;',
- prefix: () =>
- h(NIcon, null, {
- default: () => h(FileTrayFullOutline)
- })
- },
- ]
}
]
}
@@ -88,6 +73,22 @@ export default defineComponent({
selectedKeys: []
})
+ const contextMenuVariables = reactive({
+ x: 0,
+ y: 0,
+ isShow: false,
+ options: [
+ {
+ label: t('playground.new_folder'),
+ key: 'new_folder',
+ },
+ {
+ label: t('playground.new_file'),
+ key: 'new_file',
+ },
+ ]
+ })
+
const nodeProps = ({ option }: { option: TreeOption }) => {
return {
onClick () {
@@ -104,6 +105,12 @@ export default defineComponent({
})
tabData.value.chooseTab = option.key
},
+ onContextmenu (e: MouseEvent): void {
+ e.preventDefault()
+ contextMenuVariables.x = e.clientX
+ contextMenuVariables.y = e.clientY
+ contextMenuVariables.isShow = true
+ }
}
}
@@ -119,6 +126,12 @@ export default defineComponent({
tabData.value = data
})
+
+ const handleContextMenuSelect = () => {
+ contextMenuVariables.isShow = false
+ }
+
+
onMounted(() => {
mittBus.emit('initTreeData', treeVariables)
})
@@ -127,7 +140,9 @@ export default defineComponent({
t,
...toRefs(treeVariables),
nodeProps,
- handleTreeSelect
+ handleTreeSelect,
+ handleContextMenuSelect,
+ ...toRefs(contextMenuVariables),
}
},
render() {
@@ -151,6 +166,16 @@ export default defineComponent({
pattern={this.filterValue}
node-props={this.nodeProps}
/>
+ <n-dropdown
+ trigger="manual"
+ placement="bottom-start"
+ options={this.options}
+ show={this.isShow}
+ x={this.x}
+ y={this.y}
+ on-select={this.handleContextMenuSelect}
+ on-clickoutside={() => this.isShow = false}
+ />
</n-space>
</n-card>
</div>
diff --git
a/paimon-web-ui-new/src/views/playground/components/workbench/components/tabs/index.tsx
b/paimon-web-ui-new/src/views/playground/components/workbench/components/tabs/index.tsx
index 706953c..9d1f4aa 100644
---
a/paimon-web-ui-new/src/views/playground/components/workbench/components/tabs/index.tsx
+++
b/paimon-web-ui-new/src/views/playground/components/workbench/components/tabs/index.tsx
@@ -16,6 +16,7 @@ specific language governing permissions and limitations
under the License. */
import styles from './index.module.scss'
+import ContextMenu from '@/components/context-menu';
export default defineComponent({
name: 'EditorTabs',
@@ -25,6 +26,7 @@ export default defineComponent({
const tabVariables = reactive({
chooseTab: '',
panelsList: [] as any,
+ row: {} as any
})
const handleAdd = () => {
@@ -59,6 +61,40 @@ export default defineComponent({
treeData.value = data
})
+ const contextMenuVariables = reactive({
+ x: 0,
+ y: 0,
+ isShow: false
+ })
+
+ const openContextMenu = (e: MouseEvent, item: any) => {
+ e.preventDefault()
+ contextMenuVariables.x = e.pageX
+ contextMenuVariables.y = e.pageY
+ contextMenuVariables.isShow = true
+ tabVariables.row = item
+ tabVariables.chooseTab = tabVariables.row.key
+ }
+
+ const handleContextMenuSelect = (keys: string) => {
+ const index = tabVariables.panelsList.findIndex((item: any) => item.key
=== tabVariables.row.key)
+ switch (keys) {
+ case 'close_left':
+ tabVariables.panelsList.splice(0, index)
+ break;
+ case 'close_right':
+ tabVariables.panelsList.splice(index + 1)
+ break;
+ case 'close_others':
+ tabVariables.panelsList = [tabVariables.row]
+ break;
+ case 'close_all':
+ tabVariables.panelsList = []
+ break;
+ }
+ contextMenuVariables.isShow = false
+ }
+
onMounted(() => {
mittBus.emit('initTabData', tabVariables)
})
@@ -67,7 +103,10 @@ export default defineComponent({
...toRefs(tabVariables),
handleAdd,
handleClose,
- changeTreeChoose
+ changeTreeChoose,
+ openContextMenu,
+ ...toRefs(contextMenuVariables),
+ handleContextMenuSelect
}
},
render() {
@@ -92,7 +131,7 @@ export default defineComponent({
<n-tab-pane name={item.key}
v-slots={{
tab: () => (
- <div class={styles.tabs}>
+ <div class={styles.tabs} onContextmenu={(e: MouseEvent) =>
this.openContextMenu(e, item)}>
<div class={styles.dot}></div>
<div>{item.tableName}</div>
{!item.isSaved && <div class={styles.asterisk}>*</div>}
@@ -103,6 +142,14 @@ export default defineComponent({
))
}
</n-tabs>
+ <ContextMenu
+ x={this.x}
+ y={this.y}
+ visible={this.isShow}
+ type={['close_left', 'close_right', 'close_others', 'close_all']}
+ onUpdate:visible={() => this.isShow = false}
+ onSelect={this.handleContextMenuSelect}
+ />
</div>
);
}