diff --git a/paimon-web-ui-new/package.json b/paimon-web-ui-new/package.json
index e3443bbd8..6fb7ba914 100644
--- a/paimon-web-ui-new/package.json
+++ b/paimon-web-ui-new/package.json
@@ -13,11 +13,13 @@
},
"dependencies": {
"dart-sass": "^1.25.0",
+ "mitt": "^3.0.1",
"monaco-editor": "^0.43.0",
"pinia": "^2.1.6",
"pinia-plugin-persistedstate": "^3.2.0",
"sass": "^1.66.1",
"sass-loader": "^13.3.2",
+ "sql-formatter": "^13.0.0",
"vue": "^3.3.4",
"vue-i18n": "^9.4.0",
"vue-router": "^4.2.4"
diff --git a/paimon-web-ui-new/pnpm-lock.yaml b/paimon-web-ui-new/pnpm-lock.yaml
index 17b654a3a..eb3e50d76 100644
--- a/paimon-web-ui-new/pnpm-lock.yaml
+++ b/paimon-web-ui-new/pnpm-lock.yaml
@@ -23,6 +23,9 @@ dependencies:
dart-sass:
specifier: ^1.25.0
version: 1.25.0
+ mitt:
+ specifier: ^3.0.1
+ version: 3.0.1
monaco-editor:
specifier: ^0.43.0
version: 0.43.0
@@ -38,6 +41,9 @@ dependencies:
sass-loader:
specifier: ^13.3.2
version: 13.3.2(sass@1.66.1)(webpack@5.88.2)
+ sql-formatter:
+ specifier: ^13.0.0
+ version: 13.0.0
vue:
specifier: ^3.3.4
version: 3.3.4
@@ -1393,7 +1399,6 @@ packages:
/argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
- dev: true
/array-buffer-byte-length@1.0.0:
resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==}
@@ -1756,6 +1761,10 @@ packages:
path-type: 4.0.0
dev: true
+ /discontinuous-range@1.0.0:
+ resolution: {integrity: sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==}
+ dev: false
+
/doctrine@3.0.0:
resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
engines: {node: '>=6.0.0'}
@@ -2224,6 +2233,11 @@ packages:
has-symbols: 1.0.3
dev: true
+ /get-stdin@8.0.0:
+ resolution: {integrity: sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==}
+ engines: {node: '>=10'}
+ dev: false
+
/get-stream@6.0.1:
resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
engines: {node: '>=10'}
@@ -2770,6 +2784,10 @@ packages:
brace-expansion: 2.0.1
dev: true
+ /mitt@3.0.1:
+ resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
+ dev: false
+
/mlly@1.4.2:
resolution: {integrity: sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==}
dependencies:
@@ -2783,6 +2801,10 @@ packages:
resolution: {integrity: sha512-cnoqwQi/9fml2Szamv1XbSJieGJ1Dc8tENVMD26Kcfl7xGQWp7OBKMjlwKVGYFJ3/AXJjSOGvcqK7Ry/j9BM1Q==}
dev: false
+ /moo@0.5.2:
+ resolution: {integrity: sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==}
+ dev: false
+
/ms@2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
dev: true
@@ -2830,6 +2852,16 @@ packages:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
dev: true
+ /nearley@2.20.1:
+ resolution: {integrity: sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==}
+ hasBin: true
+ dependencies:
+ commander: 2.20.3
+ moo: 0.5.2
+ railroad-diagrams: 1.0.0
+ randexp: 0.4.6
+ dev: false
+
/neo-async@2.6.2:
resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
dev: false
@@ -3139,6 +3171,18 @@ packages:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
dev: true
+ /railroad-diagrams@1.0.0:
+ resolution: {integrity: sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==}
+ dev: false
+
+ /randexp@0.4.6:
+ resolution: {integrity: sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==}
+ engines: {node: '>=0.12'}
+ dependencies:
+ discontinuous-range: 1.0.0
+ ret: 0.1.15
+ dev: false
+
/randombytes@2.1.0:
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
dependencies:
@@ -3187,6 +3231,11 @@ packages:
supports-preserve-symlinks-flag: 1.0.0
dev: true
+ /ret@0.1.15:
+ resolution: {integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==}
+ engines: {node: '>=0.12'}
+ dev: false
+
/reusify@1.0.4:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
@@ -3407,6 +3456,15 @@ packages:
resolution: {integrity: sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==}
dev: true
+ /sql-formatter@13.0.0:
+ resolution: {integrity: sha512-V21cVvge4rhn9Fa7K/fTKcmPM+x1yee6Vhq8ZwgaWh3VPBqApgsaoFB5kLAhiqRo5AmSaRyLU7LIdgnNwH01/w==}
+ hasBin: true
+ dependencies:
+ argparse: 2.0.1
+ get-stdin: 8.0.0
+ nearley: 2.20.1
+ dev: false
+
/string.prototype.padend@3.1.5:
resolution: {integrity: sha512-DOB27b/2UTTD+4myKUFh+/fXWcu/UDyASIXfg+7VzoCNNGOfWvoyU/x5pvVHr++ztyt/oSYI1BcWBBG/hmlNjA==}
engines: {node: '>= 0.4'}
diff --git a/paimon-web-ui-new/src/App.tsx b/paimon-web-ui-new/src/App.tsx
index 96768c73c..90b23e0e5 100644
--- a/paimon-web-ui-new/src/App.tsx
+++ b/paimon-web-ui-new/src/App.tsx
@@ -47,7 +47,9 @@ export default defineComponent({
date-locale={this.locale === 'en' ? dateEnUS : dateZhCN}
style={{ width: '100%', height: '100vh' }}
>
-
+
+
+
}
})
diff --git a/paimon-web-ui-new/src/components/monaco-editor/index.tsx b/paimon-web-ui-new/src/components/monaco-editor/index.tsx
index 5bf54afe1..55a917dfa 100644
--- a/paimon-web-ui-new/src/components/monaco-editor/index.tsx
+++ b/paimon-web-ui-new/src/components/monaco-editor/index.tsx
@@ -23,6 +23,7 @@ import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'
import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
import { editorProps } from './type'
import { useConfigStore } from '@/store/config'
+import { format } from 'sql-formatter'
// @ts-ignore: worker
self.MonacoEnvironment = {
@@ -46,7 +47,7 @@ self.MonacoEnvironment = {
export default defineComponent({
name: 'MonacoEditor',
props: editorProps,
- emits: ['update:modelValue', 'change', 'EditorMounted'],
+ emits: ['update:modelValue', 'change', 'EditorMounted', 'EditorSave'],
setup(props, { emit }) {
const configStore = useConfigStore()
const monacoEditorThemeRef = ref(configStore.getCurrentTheme === 'dark' ? 'vs-dark' : 'vs')
@@ -61,12 +62,45 @@ export default defineComponent({
target: monaco.languages.typescript.ScriptTarget.ES2020,
allowNonTsExtensions: true
})
+ monaco.languages.registerCompletionItemProvider('sql', {
+ provideCompletionItems: function(model, position) {
+ const word = model.getWordUntilPosition(position);
+ const range = {
+ startLineNumber: position.lineNumber,
+ endLineNumber: position.lineNumber,
+ startColumn: word.startColumn,
+ endColumn: word.endColumn
+ };
+ const suggestions = [];
+ const sqlStr = ['select','from','where','and','or','limit','order by','group by'];
+ for(const i in sqlStr){
+ suggestions.push({
+ label: sqlStr[i],
+ kind: monaco.languages.CompletionItemKind['Function'],
+ insertText: sqlStr[i],
+ detail: '',
+ range:range
+ });
+ }
+ return {
+ suggestions: suggestions
+ };
+ },
+ });
+
editor = monaco.editor.create(codeEditBox.value, {
value: props.modelValue,
language: props.language,
theme: monacoEditorThemeRef.value,
...props.options
})
+
+ editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, function () {
+ emit('EditorSave')
+ })
+
+ editor.setValue(format(toRaw(editor).getValue()))
+
editor.onDidChangeModelContent(() => {
const value = editor.getValue()
emit('update:modelValue', value)
@@ -81,6 +115,7 @@ export default defineComponent({
const value = editor.getValue()
if (newValue !== value) {
editor.setValue(newValue)
+ editor.setValue(format(toRaw(editor).getValue()))
}
}
}
@@ -106,6 +141,7 @@ export default defineComponent({
init()
}
)
+
onBeforeUnmount(() => {
editor.dispose()
})
diff --git a/paimon-web-ui-new/src/components/monaco-editor/type.ts b/paimon-web-ui-new/src/components/monaco-editor/type.ts
index a611096da..abfd5c171 100644
--- a/paimon-web-ui-new/src/components/monaco-editor/type.ts
+++ b/paimon-web-ui-new/src/components/monaco-editor/type.ts
@@ -66,12 +66,12 @@ export const editorProps = {
renderLineHighlight: 'line',
selectOnLineNumbers: true,
minimap: {
- enabled: true
+ enabled: false
},
readOnly: false,
contextmenu: true,
fontSize: 16,
- scrollBeyondLastLine: false,
+ scrollBeyondLastLine: true,
overviewRulerBorder: false
}
}
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 feedda3e8..9babf1786 100644
--- a/paimon-web-ui-new/src/locales/en/modules/playground.ts
+++ b/paimon-web-ui-new/src/locales/en/modules/playground.ts
@@ -16,6 +16,22 @@ specific language governing permissions and limitations
under the License. */
export default {
- select_catalog: 'Select Catalog',
- search: 'Search'
+ query: 'Query',
+ workbench: 'Workbench',
+ task_operation_and_maintenance: 'Task Operation and Maintenance',
+ settings: 'Settings',
+ terminal: 'Terminal',
+ git_branch: 'Git Branch',
+ data: 'Data',
+ saved_query: 'Saved Query',
+ query_record: 'Query Record',
+ search: 'Search',
+ run: 'Run',
+ format: 'Format',
+ save: 'Save',
+ clear: 'Clear',
+ unfold: 'Unfold',
+ collapse: 'Collapse',
+ logs: 'Logs',
+ result: 'Result',
}
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 e9350cb32..2787b5b2e 100644
--- a/paimon-web-ui-new/src/locales/zh/modules/playground.ts
+++ b/paimon-web-ui-new/src/locales/zh/modules/playground.ts
@@ -16,6 +16,22 @@ specific language governing permissions and limitations
under the License. */
export default {
- select_catalog: '选择 Catalog',
- search: '搜索'
+ 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: '结果',
}
diff --git a/paimon-web-ui-new/src/main.ts b/paimon-web-ui-new/src/main.ts
index 82a46d970..303ab837e 100644
--- a/paimon-web-ui-new/src/main.ts
+++ b/paimon-web-ui-new/src/main.ts
@@ -24,6 +24,7 @@ import naive from 'naive-ui'
import i18n from './locales'
import { Setting } from './config'
import '@/assets/styles/main.scss'
+import mitt from 'mitt'
const app = createApp(App)
const pinia = createPinia()
@@ -33,6 +34,7 @@ app.use(pinia)
pinia.use(piniaPluginPersistedstate)
app.use(router)
app.use(naive)
+app.config.globalProperties.mittBus = mitt()
app.mount('#app')
diff --git a/paimon-web-ui-new/src/router/modules/playground.ts b/paimon-web-ui-new/src/router/modules/playground.ts
index b8333c1c6..07863afe2 100644
--- a/paimon-web-ui-new/src/router/modules/playground.ts
+++ b/paimon-web-ui-new/src/router/modules/playground.ts
@@ -27,7 +27,22 @@ export default [
path: '/playground',
name: 'playground',
meta: { title: '查询控制台' },
- component: () => import('@/views/playground')
+ redirect: { name: 'playground-query' },
+ component: () => import('@/views/playground'),
+ children: [
+ {
+ path: '/playground/query',
+ name: 'playground-query',
+ meta: { title: '查询' },
+ component: () => import('@/views/playground/components/query')
+ },
+ {
+ path: '/playground/workbench',
+ name: 'playground-workbench',
+ meta: { title: '工作台' },
+ component: () => import('@/views/playground/components/workbench')
+ },
+ ]
},
]
}
diff --git a/paimon-web-ui-new/src/views/playground/components/catalog/index.tsx b/paimon-web-ui-new/src/views/playground/components/catalog/index.tsx
deleted file mode 100644
index ea44e8c56..000000000
--- a/paimon-web-ui-new/src/views/playground/components/catalog/index.tsx
+++ /dev/null
@@ -1,88 +0,0 @@
-/* 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 i18n from "@/locales"
-import type { TreeOption } from "naive-ui";
-import styles from './index.module.scss'
-
-export default defineComponent({
- name: 'CataLogPage',
- setup() {
- const selectedValue= ref(null)
-
- const options= [
- {
- label: 'catalog1',
- value: 'catalog1'
- },
- {
- label: 'catalog2',
- value: 'catalog2'
- }
- ]
-
- const searchVal = ref('')
-
- const treeData: TreeOption[] = [
- {
- label: 'paimon',
- key: 'paimon',
- children: [
- {
- label: 'paimon-table-01',
- key: 'paimon-table-01',
- children: [
- { label: 'id', key: 'id' },
- { label: 'name', key: 'name' }
- ]
- },
- {
- label: 'paimon-table-02',
- key: 'paimon-table-02',
- children: [
- { label: 'Osaka', key: 'Osaka' },
- ]
- }
- ]
- }
- ]
-
- return { selectedValue, options, searchVal, treeData }
- },
- render() {
- return (
-
- );
- },
-});
diff --git a/paimon-web-ui-new/src/views/playground/components/query/components/console/index.module.scss b/paimon-web-ui-new/src/views/playground/components/query/components/console/index.module.scss
new file mode 100644
index 000000000..626d6f8b2
--- /dev/null
+++ b/paimon-web-ui-new/src/views/playground/components/query/components/console/index.module.scss
@@ -0,0 +1,29 @@
+/* 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. */
+
+
+.editor-console {
+ width: 100%;
+ height: 100%;
+ position: relative;
+
+ .operations {
+ position: absolute;
+ top: 17px;
+ right: 20px;
+ }
+}
diff --git a/paimon-web-ui-new/src/views/playground/components/query/components/console/index.tsx b/paimon-web-ui-new/src/views/playground/components/query/components/console/index.tsx
new file mode 100644
index 000000000..4ecf92a78
--- /dev/null
+++ b/paimon-web-ui-new/src/views/playground/components/query/components/console/index.tsx
@@ -0,0 +1,109 @@
+/* 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 { ChevronDown, ChevronUp, TrashOutline } from '@vicons/ionicons5'
+import styles from './index.module.scss'
+
+export default defineComponent({
+ name: 'EditorConsole',
+ emits: ['ConsoleUp', 'ConsoleDown'],
+ setup(props, { emit }) {
+ const { t } = useLocaleHooks()
+
+ const handleUp = () => {
+ emit('ConsoleUp', 'up')
+ }
+
+ const handleDown = () => {
+ emit('ConsoleDown', 'down')
+ }
+
+ return {
+ t,
+ handleUp,
+ handleDown
+ }
+ },
+ render() {
+ return (
+
+
+
+ {this.t('playground.logs')}
+
+
+ {this.t('playground.result')}
+
+
+
+
+ (
+
+ }}
+ >
+
+ )
+ }}>
+ {this.t('playground.clear')}
+
+ (
+
+ }}
+ >
+
+ )
+ }}>
+ {this.t('playground.unfold')}
+
+ (
+
+ }}
+ >
+
+ )
+ }}>
+ {this.t('playground.collapse')}
+
+
+
+
+ )
+ }
+})
diff --git a/paimon-web-ui-new/src/views/playground/components/query/components/debugger/index.module.scss b/paimon-web-ui-new/src/views/playground/components/query/components/debugger/index.module.scss
new file mode 100644
index 000000000..0ab88421f
--- /dev/null
+++ b/paimon-web-ui-new/src/views/playground/components/query/components/debugger/index.module.scss
@@ -0,0 +1,34 @@
+/* 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. */
+
+
+.container {
+ display: flex;
+ align-items: center;
+ width: 100%;
+ height: 100%;
+
+ .run {
+ display: flex;
+ }
+
+ .operations {
+ display: flex;
+ flex: 1;
+ justify-content: flex-end;
+ }
+}
diff --git a/paimon-web-ui-new/src/views/playground/components/query/components/debugger/index.tsx b/paimon-web-ui-new/src/views/playground/components/query/components/debugger/index.tsx
new file mode 100644
index 000000000..044317272
--- /dev/null
+++ b/paimon-web-ui-new/src/views/playground/components/query/components/debugger/index.tsx
@@ -0,0 +1,139 @@
+/* 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 { Play, ChevronDown, ReaderOutline, Save } from '@vicons/ionicons5';
+import styles from './index.module.scss'
+
+export default defineComponent({
+ name: 'EditorDebugger',
+ emits: ['handleFormat', 'handleSave'],
+ setup(props, { emit }) {
+ const { t } = useLocaleHooks()
+
+ const debuggerVariables = reactive({
+ operatingConditionOptions: [
+ {
+ label: 'Limit 100 items',
+ key: "100"
+ },
+ {
+ label: 'Limit 1000 items',
+ key: "1000"
+ },
+ ],
+ conditionValue: 'Flink',
+ bigDataOptions: [
+ {
+ label: 'Flink',
+ value: "Flink"
+ },
+ {
+ label: 'Spark',
+ value: "Spark"
+ },
+ ],
+ conditionValue2: 'test1',
+ clusterOptions: [
+ {
+ label: 'test1',
+ value: "test1"
+ },
+ {
+ label: 'test2',
+ value: "test2"
+ },
+ ]
+ })
+
+ const handleSelect = (key: string) => {
+ console.log(key)
+ }
+
+ const handleFormat = () => {
+ emit('handleFormat')
+ }
+
+ const handleSave = () => {
+ emit('handleSave')
+ }
+
+ return {
+ t,
+ ...toRefs(debuggerVariables),
+ handleSelect,
+ handleFormat,
+ handleSave
+ }
+ },
+ render() {
+ return (
+
+
+ ,
+ default: () => {
+ return
+ {this.t('playground.run')}
+
+
+
+
+
+ }
+ }}
+ >
+
+
+
+
+
+ (
+
+ }}
+ >
+
+ )
+ }}>
+ {this.t('playground.format')}
+
+ (
+
+ }}
+ >
+
+ )
+ }}>
+ {this.t('playground.save')}
+
+
+
+
+ );
+ }
+});
diff --git a/paimon-web-ui-new/src/views/playground/components/catalog/index.module.scss b/paimon-web-ui-new/src/views/playground/components/query/components/menu-tree/index.module.scss
similarity index 86%
rename from paimon-web-ui-new/src/views/playground/components/catalog/index.module.scss
rename to paimon-web-ui-new/src/views/playground/components/query/components/menu-tree/index.module.scss
index e32b957e6..536333ae0 100644
--- a/paimon-web-ui-new/src/views/playground/components/catalog/index.module.scss
+++ b/paimon-web-ui-new/src/views/playground/components/query/components/menu-tree/index.module.scss
@@ -17,8 +17,17 @@ under the License. */
.container {
width: 100%;
+ height: 100%;
- .select-catalog {
- padding-bottom: 10px;
+ .card {
+ height: 100%;
+
+ .search {
+ display: flex;
+ }
+
+ .icon {
+ display: flex;
+ }
}
}
diff --git a/paimon-web-ui-new/src/views/playground/components/query/components/menu-tree/index.tsx b/paimon-web-ui-new/src/views/playground/components/query/components/menu-tree/index.tsx
new file mode 100644
index 000000000..552a78baa
--- /dev/null
+++ b/paimon-web-ui-new/src/views/playground/components/query/components/menu-tree/index.tsx
@@ -0,0 +1,247 @@
+/* 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 { CodeSlash, FileTrayFullOutline, Search, ServerOutline } from '@vicons/ionicons5';
+import styles from './index.module.scss'
+import { NIcon, type TreeOption } from 'naive-ui';
+
+export default defineComponent({
+ name: 'MenuTree',
+ setup() {
+ const { t } = useLocaleHooks()
+
+ const treeVariables = reactive({
+ treeData: [
+ {
+ key: 'paimon',
+ label: 'paimon',
+ prefix: () =>
+ h(NIcon, null, {
+ default: () => h(ServerOutline)
+ }),
+ children: [
+ {
+ key: 'user',
+ label: 'user',
+ prefix: () =>
+ h(NIcon, null, {
+ default: () => h(ServerOutline)
+ }),
+ children: [
+ {
+ label: 'user_table',
+ key: '1',
+ content: 'select * from abc where abc.a="abc";select * from cba where cba.a="cba";',
+ prefix: () =>
+ h(NIcon, null, {
+ default: () => h(FileTrayFullOutline)
+ })
+ },
+ {
+ label: 'people_table',
+ key: '2',
+ content: 'select * from abc where abc.a="abc";',
+ prefix: () =>
+ h(NIcon, null, {
+ default: () => h(FileTrayFullOutline)
+ })
+ }
+ ]
+ },
+ {
+ 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)
+ })
+ },
+ ]
+ }
+ ]
+ }
+ ],
+ filterValue: '',
+ selectedKeys: []
+ })
+
+ const nodeProps = ({ option }: { option: TreeOption }) => {
+ return {
+ onClick () {
+ if (option.children) return
+ if (tabData.value.panelsList?.some((item: any) => item.key === option.key)) {
+ tabData.value.chooseTab = option.key
+ return
+ }
+ tabData.value.panelsList.push({
+ tableName: option.label,
+ key: option.key,
+ isSaved: false,
+ content: option.content
+ })
+ tabData.value.chooseTab = option.key
+ },
+ }
+ }
+
+ const handleTreeSelect = (value: never[], option: { children: any; }[]) => {
+ if (option[0]?.children) return
+ treeVariables.selectedKeys = value
+ }
+
+ // mitt - handle tab choose
+ const tabData = ref({}) as any
+ const { mittBus } = getCurrentInstance()!.appContext.config.globalProperties
+ mittBus.on('initTabData', (data: any) => {
+ tabData.value = data
+ })
+
+ const savedQueryList = ref([
+ {
+ key: 1,
+ label: 'test1',
+ prefix: () =>
+ h(NIcon, {color: '#0066FF'}, {
+ default: () => h(CodeSlash)
+ }),
+ content: ''
+ },
+ {
+ key: 2,
+ label: 'test2',
+ prefix: () =>
+ h(NIcon, {color: '#0066FF'}, {
+ default: () => h(CodeSlash)
+ }),
+ content: ''
+ }
+ ]) as any
+
+ const recordList = ref([
+ {
+ key: 3,
+ label: 'test3',
+ prefix: () =>
+ h(NIcon, {color: '#0066FF'}, {
+ default: () => h(CodeSlash)
+ }),
+ content: ''
+ },
+ {
+ key: 4,
+ label: 'test4',
+ prefix: () =>
+ h(NIcon, {color: '#0066FF'}, {
+ default: () => h(CodeSlash)
+ }),
+ content: ''
+ }
+ ]) as any
+
+ onMounted(() => {
+ mittBus.emit('initTreeData', treeVariables)
+ })
+
+ return {
+ t,
+ ...toRefs(treeVariables),
+ nodeProps,
+ handleTreeSelect,
+ savedQueryList,
+ recordList
+ }
+ },
+ render() {
+ return (
+
+
+
+
+
+
+ }}
+ >
+
+
+
+
+
+
+
+ }}
+ >
+
+
+
+
+
+
+
+ }}
+ >
+
+
+
+
+
+
+
+ );
+ }
+});
diff --git a/paimon-web-ui-new/src/views/playground/components/query/components/tabs/index.module.scss b/paimon-web-ui-new/src/views/playground/components/query/components/tabs/index.module.scss
new file mode 100644
index 000000000..9b67bd79a
--- /dev/null
+++ b/paimon-web-ui-new/src/views/playground/components/query/components/tabs/index.module.scss
@@ -0,0 +1,35 @@
+/* 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. */
+
+
+.tabs {
+ display: flex;
+ align-items: center;
+
+ .dot {
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background-color: #33994A;
+ margin-right: 8px;
+ }
+
+ .asterisk {
+ color: #C82E2E;
+ padding-left: 10px;
+ }
+}
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
new file mode 100644
index 000000000..706953cf7
--- /dev/null
+++ b/paimon-web-ui-new/src/views/playground/components/query/components/tabs/index.tsx
@@ -0,0 +1,109 @@
+/* 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 styles from './index.module.scss'
+
+export default defineComponent({
+ name: 'EditorTabs',
+ setup() {
+ const { mittBus } = getCurrentInstance()!.appContext.config.globalProperties
+
+ const tabVariables = reactive({
+ chooseTab: '',
+ panelsList: [] as any,
+ })
+
+ const handleAdd = () => {
+ tabVariables.panelsList.push({
+ tableName: 'test' + (tabVariables.panelsList.length + 1),
+ key: 'test' + (tabVariables.panelsList.length + 1),
+ isSaved: false,
+ content: ''
+ })
+ tabVariables.chooseTab = 'test' + tabVariables.panelsList.length
+ }
+
+ const handleClose = (key: any) => {
+ const index = tabVariables.panelsList.findIndex((item: any) => item.key === key)
+ tabVariables.panelsList.splice(index, 1)
+ if (key === tabVariables.chooseTab) {
+ if (tabVariables.panelsList[index - 1]) {
+ tabVariables.chooseTab = tabVariables.panelsList[index - 1].key
+ } else {
+ tabVariables.chooseTab = tabVariables.panelsList[index]?.key || ''
+ }
+ }
+ }
+
+ // mitt - handle tree choose
+ const treeData = ref({}) as any
+ const changeTreeChoose = (value: string) => {
+ treeData.value.selectedKeys = [value]
+ tabVariables.chooseTab = value
+ }
+ mittBus.on('initTreeData', (data: any) => {
+ treeData.value = data
+ })
+
+ onMounted(() => {
+ mittBus.emit('initTabData', tabVariables)
+ })
+
+ return {
+ ...toRefs(tabVariables),
+ handleAdd,
+ handleClose,
+ changeTreeChoose
+ }
+ },
+ render() {
+ return (
+
+
'',
+ suffix: () => ''
+ }}
+ >
+ {
+ this.panelsList.map((item: any) => (
+ (
+
+
+
{item.tableName}
+ {!item.isSaved &&
*
}
+
+ )
+ }}
+ >
+ ))
+ }
+
+
+ );
+ }
+});
diff --git a/paimon-web-ui-new/src/views/playground/components/query/index.module.scss b/paimon-web-ui-new/src/views/playground/components/query/index.module.scss
new file mode 100644
index 000000000..369f097e4
--- /dev/null
+++ b/paimon-web-ui-new/src/views/playground/components/query/index.module.scss
@@ -0,0 +1,59 @@
+/* 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. */
+
+.query {
+ display: flex;
+ width: 100%;
+ height: 100%;
+
+ .menu-tree {
+ width: 20%;
+ height: 100%;
+ }
+
+ .editor-area {
+ width: 80%;
+ height: 100%;
+
+ :global {
+ .n-card {
+ height: 100%;
+ }
+ }
+
+ .tabs {
+ display: flex;
+ height: 41px;
+ width: 100%;
+ }
+
+ .debugger {
+ display: flex;
+ height: 64px;
+ }
+
+ .editor {
+ height: 60%;
+ overflow-y: scroll;
+ }
+
+ .console {
+ height: 40%;
+ overflow-y: scroll;
+ }
+ }
+}
diff --git a/paimon-web-ui-new/src/views/playground/components/query/index.tsx b/paimon-web-ui-new/src/views/playground/components/query/index.tsx
new file mode 100644
index 000000000..2a2ee2d50
--- /dev/null
+++ b/paimon-web-ui-new/src/views/playground/components/query/index.tsx
@@ -0,0 +1,138 @@
+/* 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 styles from './index.module.scss'
+import MenuTree from './components/menu-tree';
+import EditorTabs from './components/tabs';
+import EditorDebugger from './components/debugger';
+import * as monaco from 'monaco-editor'
+import MonacoEditor from '@/components/monaco-editor';
+import EditorConsole from './components/console';
+import { format } from 'sql-formatter';
+import { useMessage } from 'naive-ui'
+
+export default defineComponent({
+ name: 'QueryPage',
+ setup() {
+ const message = useMessage()
+
+ const editorVariables = reactive({
+ editor: {} as any,
+ language: 'sql'
+ })
+
+ const editorMounted = (editor: monaco.editor.IStandaloneCodeEditor) => {
+ editorVariables.editor = editor
+ }
+
+ const handleFormat = () => {
+ toRaw(editorVariables.editor).setValue(format(toRaw(editorVariables.editor).getValue()))
+ }
+
+ const editorSave = () => {
+ message.success('Save success')
+ tabData.value.panelsList.find((item: any) => item.key === tabData.value.chooseTab).content = toRaw(editorVariables.editor).getValue()
+ handleFormat()
+ tabData.value.panelsList.find((item: any) => item.key === tabData.value.chooseTab).isSaved = true
+ }
+
+ const handleContentChange = (value: string) => {
+ tabData.value.panelsList.find((item: any) => item.key === tabData.value.chooseTab).content = value
+ tabData.value.panelsList.find((item: any) => item.key === tabData.value.chooseTab).isSaved = false
+ }
+
+ const consoleHeightType = ref('down')
+
+ const handleConsoleUp = (type: string) => {
+ consoleHeightType.value = type
+ }
+
+ const handleConsoleDown = (type: string) => {
+ consoleHeightType.value = type
+ }
+
+
+ watch(
+ () => consoleHeightType.value,
+ () => {
+ if (tabData.value.panelsList?.length > 0) {
+ editorVariables.editor?.layout()
+ }
+ }
+ )
+
+ // mitt - handle tab choose
+ const tabData = ref({}) as any
+ const { mittBus } = getCurrentInstance()!.appContext.config.globalProperties
+ mittBus.on('initTabData', (data: any) => {
+ tabData.value = data
+ })
+
+ return {
+ ...toRefs(editorVariables),
+ editorMounted,
+ editorSave,
+ handleContentChange,
+ handleFormat,
+ tabData,
+ handleConsoleUp,
+ handleConsoleDown,
+ consoleHeightType
+ }
+ },
+ render() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ {
+ this.tabData.panelsList?.length > 0 &&
+
+ item.key === this.tabData.chooseTab).content}
+ language={this.language}
+ onEditorMounted={this.editorMounted}
+ onEditorSave={this.editorSave}
+ onChange={this.handleContentChange}
+ />
+
+ }
+
+
+ {
+ this.tabData.panelsList?.length > 0 &&
+
+
+
+ }
+
+
+
+
+ );
+ }
+});
diff --git a/paimon-web-ui-new/src/views/playground/components/slider/index.module.scss b/paimon-web-ui-new/src/views/playground/components/slider/index.module.scss
new file mode 100644
index 000000000..2fdba5bef
--- /dev/null
+++ b/paimon-web-ui-new/src/views/playground/components/slider/index.module.scss
@@ -0,0 +1,50 @@
+/* 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. */
+
+.slider {
+ display: flex;
+ flex-wrap: wrap;
+ flex-direction: column;
+ width: 60px;
+ height: 100%;
+ padding: 20px 0;
+ box-sizing: border-box;
+ background-color: var(--n-color);
+
+ .workspace {
+ display: flex;
+ flex: 1;
+ justify-content: center;
+ width: 100%;
+ }
+
+ .functional-domain {
+ display: flex;
+ justify-content: center;
+ align-items: flex-end;
+ width: 100%;
+ height: 200px;
+ }
+}
+
+.light {
+ background-color: #fff;
+}
+
+.dark {
+ background-color: #18181c;
+}
diff --git a/paimon-web-ui-new/src/views/playground/components/slider/index.tsx b/paimon-web-ui-new/src/views/playground/components/slider/index.tsx
new file mode 100644
index 000000000..819476945
--- /dev/null
+++ b/paimon-web-ui-new/src/views/playground/components/slider/index.tsx
@@ -0,0 +1,143 @@
+/* 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 styles from './index.module.scss'
+import { Layers, CodeSlashSharp, Settings, Terminal, GitBranch } from '@vicons/ionicons5';
+import { useConfigStore } from '@/store/config'
+import { NIcon } from 'naive-ui';
+
+export default defineComponent({
+ name: 'SliderPage',
+ setup() {
+ const configStore = useConfigStore()
+ const { t } = useLocaleHooks()
+ const router = useRouter()
+
+ const renderIcon = (icon: any) => {
+ return () => h(NIcon, { size: 24 }, { default: () => h(icon) })
+ }
+
+ const sliderVariables = reactive({
+ workspaceList: [
+ {
+ icon: renderIcon(Layers),
+ title: 'Layers',
+ description: computed(() => (t('playground.query'))),
+ isClick: true,
+ path: '/playground/query'
+ },
+ {
+ icon: renderIcon(CodeSlashSharp),
+ title: 'Code',
+ description: computed(() => (t('playground.workbench'))),
+ isClick: false,
+ path: '/playground/workbench'
+ },
+ ],
+ domainList: [
+ {
+ icon: renderIcon(Settings),
+ title: 'Settings',
+ description: computed(() => (t('playground.settings')))
+ },
+ {
+ icon: renderIcon(Terminal),
+ title: 'Terminal',
+ description: computed(() => (t('playground.terminal')))
+ },
+ {
+ icon: renderIcon(GitBranch),
+ title: 'GitBranch',
+ description: computed(() => (t('playground.git_branch'))),
+ }
+ ],
+ })
+
+ const handleClick = (index: number, type: string) => {
+ if (type === 'workspace') {
+ for (const i in sliderVariables.workspaceList) {
+ sliderVariables.workspaceList[i].isClick = false
+ }
+ sliderVariables.workspaceList[index].isClick = true
+ router.push(sliderVariables.workspaceList[index].path)
+ }
+ }
+
+ return {
+ configStore,
+ handleClick,
+ ...toRefs(sliderVariables)
+ }
+ },
+ render() {
+ return (
+
+
+
+ {
+ this.workspaceList.map((item: any, index: number) => {
+ return (
+ (
+ this.handleClick(index, 'workspace')}
+ v-slots={{
+ icon: () => item.icon()
+ }}
+ >
+
+ )
+ }}>
+ {item.description}
+
+ )
+ })
+ }
+
+
+
+
+ {
+ this.domainList.map((item: any, index: number) => {
+ return (
+ (
+ this.handleClick(index, 'domain')}
+ v-slots={{
+ icon: () => item.icon()
+ }}
+ >
+
+ )
+ }}>
+ {item.description}
+
+ )
+ })
+ }
+
+
+
+ );
+ },
+});
diff --git a/paimon-web-ui-new/src/views/playground/components/workbench/components/console/index.module.scss b/paimon-web-ui-new/src/views/playground/components/workbench/components/console/index.module.scss
new file mode 100644
index 000000000..626d6f8b2
--- /dev/null
+++ b/paimon-web-ui-new/src/views/playground/components/workbench/components/console/index.module.scss
@@ -0,0 +1,29 @@
+/* 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. */
+
+
+.editor-console {
+ width: 100%;
+ height: 100%;
+ position: relative;
+
+ .operations {
+ position: absolute;
+ top: 17px;
+ right: 20px;
+ }
+}
diff --git a/paimon-web-ui-new/src/views/playground/components/workbench/components/console/index.tsx b/paimon-web-ui-new/src/views/playground/components/workbench/components/console/index.tsx
new file mode 100644
index 000000000..4ecf92a78
--- /dev/null
+++ b/paimon-web-ui-new/src/views/playground/components/workbench/components/console/index.tsx
@@ -0,0 +1,109 @@
+/* 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 { ChevronDown, ChevronUp, TrashOutline } from '@vicons/ionicons5'
+import styles from './index.module.scss'
+
+export default defineComponent({
+ name: 'EditorConsole',
+ emits: ['ConsoleUp', 'ConsoleDown'],
+ setup(props, { emit }) {
+ const { t } = useLocaleHooks()
+
+ const handleUp = () => {
+ emit('ConsoleUp', 'up')
+ }
+
+ const handleDown = () => {
+ emit('ConsoleDown', 'down')
+ }
+
+ return {
+ t,
+ handleUp,
+ handleDown
+ }
+ },
+ render() {
+ return (
+
+
+
+ {this.t('playground.logs')}
+
+
+ {this.t('playground.result')}
+
+
+
+
+ (
+
+ }}
+ >
+
+ )
+ }}>
+ {this.t('playground.clear')}
+
+ (
+
+ }}
+ >
+
+ )
+ }}>
+ {this.t('playground.unfold')}
+
+ (
+
+ }}
+ >
+
+ )
+ }}>
+ {this.t('playground.collapse')}
+
+
+
+
+ )
+ }
+})
diff --git a/paimon-web-ui-new/src/views/playground/components/workbench/components/debugger/index.module.scss b/paimon-web-ui-new/src/views/playground/components/workbench/components/debugger/index.module.scss
new file mode 100644
index 000000000..0ab88421f
--- /dev/null
+++ b/paimon-web-ui-new/src/views/playground/components/workbench/components/debugger/index.module.scss
@@ -0,0 +1,34 @@
+/* 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. */
+
+
+.container {
+ display: flex;
+ align-items: center;
+ width: 100%;
+ height: 100%;
+
+ .run {
+ display: flex;
+ }
+
+ .operations {
+ display: flex;
+ flex: 1;
+ justify-content: flex-end;
+ }
+}
diff --git a/paimon-web-ui-new/src/views/playground/components/workbench/components/debugger/index.tsx b/paimon-web-ui-new/src/views/playground/components/workbench/components/debugger/index.tsx
new file mode 100644
index 000000000..044317272
--- /dev/null
+++ b/paimon-web-ui-new/src/views/playground/components/workbench/components/debugger/index.tsx
@@ -0,0 +1,139 @@
+/* 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 { Play, ChevronDown, ReaderOutline, Save } from '@vicons/ionicons5';
+import styles from './index.module.scss'
+
+export default defineComponent({
+ name: 'EditorDebugger',
+ emits: ['handleFormat', 'handleSave'],
+ setup(props, { emit }) {
+ const { t } = useLocaleHooks()
+
+ const debuggerVariables = reactive({
+ operatingConditionOptions: [
+ {
+ label: 'Limit 100 items',
+ key: "100"
+ },
+ {
+ label: 'Limit 1000 items',
+ key: "1000"
+ },
+ ],
+ conditionValue: 'Flink',
+ bigDataOptions: [
+ {
+ label: 'Flink',
+ value: "Flink"
+ },
+ {
+ label: 'Spark',
+ value: "Spark"
+ },
+ ],
+ conditionValue2: 'test1',
+ clusterOptions: [
+ {
+ label: 'test1',
+ value: "test1"
+ },
+ {
+ label: 'test2',
+ value: "test2"
+ },
+ ]
+ })
+
+ const handleSelect = (key: string) => {
+ console.log(key)
+ }
+
+ const handleFormat = () => {
+ emit('handleFormat')
+ }
+
+ const handleSave = () => {
+ emit('handleSave')
+ }
+
+ return {
+ t,
+ ...toRefs(debuggerVariables),
+ handleSelect,
+ handleFormat,
+ handleSave
+ }
+ },
+ render() {
+ return (
+
+
+ ,
+ default: () => {
+ return
+ {this.t('playground.run')}
+
+
+
+
+
+ }
+ }}
+ >
+
+
+
+
+
+ (
+
+ }}
+ >
+
+ )
+ }}>
+ {this.t('playground.format')}
+
+ (
+
+ }}
+ >
+
+ )
+ }}>
+ {this.t('playground.save')}
+
+
+
+
+ );
+ }
+});
diff --git a/paimon-web-ui-new/src/views/playground/components/workbench/components/menu-tree/index.module.scss b/paimon-web-ui-new/src/views/playground/components/workbench/components/menu-tree/index.module.scss
new file mode 100644
index 000000000..536333ae0
--- /dev/null
+++ b/paimon-web-ui-new/src/views/playground/components/workbench/components/menu-tree/index.module.scss
@@ -0,0 +1,33 @@
+/* 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. */
+
+.container {
+ width: 100%;
+ height: 100%;
+
+ .card {
+ height: 100%;
+
+ .search {
+ display: flex;
+ }
+
+ .icon {
+ display: flex;
+ }
+ }
+}
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
new file mode 100644
index 000000000..0cbc3688a
--- /dev/null
+++ b/paimon-web-ui-new/src/views/playground/components/workbench/components/menu-tree/index.tsx
@@ -0,0 +1,159 @@
+/* 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 { CodeSlash, FileTrayFullOutline, Search, ServerOutline } from '@vicons/ionicons5';
+import styles from './index.module.scss'
+import { NIcon, type TreeOption } from 'naive-ui';
+
+export default defineComponent({
+ name: 'MenuTree',
+ setup() {
+ const { t } = useLocaleHooks()
+
+ const treeVariables = reactive({
+ treeData: [
+ {
+ key: 'paimon2',
+ label: 'paimon2',
+ prefix: () =>
+ h(NIcon, null, {
+ default: () => h(ServerOutline)
+ }),
+ children: [
+ {
+ key: 'user',
+ label: 'user',
+ prefix: () =>
+ h(NIcon, null, {
+ default: () => h(ServerOutline)
+ }),
+ children: [
+ {
+ label: 'user_table',
+ key: '1',
+ content: 'select * from abc where abc.a="abc";select * from cba where cba.a="cba";',
+ prefix: () =>
+ h(NIcon, null, {
+ default: () => h(FileTrayFullOutline)
+ })
+ },
+ {
+ label: 'people_table',
+ key: '2',
+ content: 'select * from abc where abc.a="abc";',
+ prefix: () =>
+ h(NIcon, null, {
+ default: () => h(FileTrayFullOutline)
+ })
+ }
+ ]
+ },
+ {
+ 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)
+ })
+ },
+ ]
+ }
+ ]
+ }
+ ],
+ filterValue: '',
+ selectedKeys: []
+ })
+
+ const nodeProps = ({ option }: { option: TreeOption }) => {
+ return {
+ onClick () {
+ if (option.children) return
+ if (tabData.value.panelsList?.some((item: any) => item.key === option.key)) {
+ tabData.value.chooseTab = option.key
+ return
+ }
+ tabData.value.panelsList.push({
+ tableName: option.label,
+ key: option.key,
+ isSaved: false,
+ content: option.content
+ })
+ tabData.value.chooseTab = option.key
+ },
+ }
+ }
+
+ const handleTreeSelect = (value: never[], option: { children: any; }[]) => {
+ if (option[0]?.children) return
+ treeVariables.selectedKeys = value
+ }
+
+ // mitt - handle tab choose
+ const tabData = ref({}) as any
+ const { mittBus } = getCurrentInstance()!.appContext.config.globalProperties
+ mittBus.on('initTabData', (data: any) => {
+ tabData.value = data
+ })
+
+ onMounted(() => {
+ mittBus.emit('initTreeData', treeVariables)
+ })
+
+ return {
+ t,
+ ...toRefs(treeVariables),
+ nodeProps,
+ handleTreeSelect
+ }
+ },
+ render() {
+ return (
+
+
+
+
+ }}
+ >
+
+
+
+
+
+ );
+ }
+});
diff --git a/paimon-web-ui-new/src/views/playground/components/workbench/components/tabs/index.module.scss b/paimon-web-ui-new/src/views/playground/components/workbench/components/tabs/index.module.scss
new file mode 100644
index 000000000..9b67bd79a
--- /dev/null
+++ b/paimon-web-ui-new/src/views/playground/components/workbench/components/tabs/index.module.scss
@@ -0,0 +1,35 @@
+/* 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. */
+
+
+.tabs {
+ display: flex;
+ align-items: center;
+
+ .dot {
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background-color: #33994A;
+ margin-right: 8px;
+ }
+
+ .asterisk {
+ color: #C82E2E;
+ padding-left: 10px;
+ }
+}
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
new file mode 100644
index 000000000..706953cf7
--- /dev/null
+++ b/paimon-web-ui-new/src/views/playground/components/workbench/components/tabs/index.tsx
@@ -0,0 +1,109 @@
+/* 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 styles from './index.module.scss'
+
+export default defineComponent({
+ name: 'EditorTabs',
+ setup() {
+ const { mittBus } = getCurrentInstance()!.appContext.config.globalProperties
+
+ const tabVariables = reactive({
+ chooseTab: '',
+ panelsList: [] as any,
+ })
+
+ const handleAdd = () => {
+ tabVariables.panelsList.push({
+ tableName: 'test' + (tabVariables.panelsList.length + 1),
+ key: 'test' + (tabVariables.panelsList.length + 1),
+ isSaved: false,
+ content: ''
+ })
+ tabVariables.chooseTab = 'test' + tabVariables.panelsList.length
+ }
+
+ const handleClose = (key: any) => {
+ const index = tabVariables.panelsList.findIndex((item: any) => item.key === key)
+ tabVariables.panelsList.splice(index, 1)
+ if (key === tabVariables.chooseTab) {
+ if (tabVariables.panelsList[index - 1]) {
+ tabVariables.chooseTab = tabVariables.panelsList[index - 1].key
+ } else {
+ tabVariables.chooseTab = tabVariables.panelsList[index]?.key || ''
+ }
+ }
+ }
+
+ // mitt - handle tree choose
+ const treeData = ref({}) as any
+ const changeTreeChoose = (value: string) => {
+ treeData.value.selectedKeys = [value]
+ tabVariables.chooseTab = value
+ }
+ mittBus.on('initTreeData', (data: any) => {
+ treeData.value = data
+ })
+
+ onMounted(() => {
+ mittBus.emit('initTabData', tabVariables)
+ })
+
+ return {
+ ...toRefs(tabVariables),
+ handleAdd,
+ handleClose,
+ changeTreeChoose
+ }
+ },
+ render() {
+ return (
+
+
'',
+ suffix: () => ''
+ }}
+ >
+ {
+ this.panelsList.map((item: any) => (
+ (
+
+
+
{item.tableName}
+ {!item.isSaved &&
*
}
+
+ )
+ }}
+ >
+ ))
+ }
+
+
+ );
+ }
+});
diff --git a/paimon-web-ui-new/src/views/playground/components/workbench/index.module.scss b/paimon-web-ui-new/src/views/playground/components/workbench/index.module.scss
new file mode 100644
index 000000000..d77f10b4a
--- /dev/null
+++ b/paimon-web-ui-new/src/views/playground/components/workbench/index.module.scss
@@ -0,0 +1,59 @@
+/* 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. */
+
+.workbench {
+ display: flex;
+ width: 100%;
+ height: 100%;
+
+ .menu-tree {
+ width: 20%;
+ height: 100%;
+ }
+
+ .editor-area {
+ width: 80%;
+ height: 100%;
+
+ :global {
+ .n-card {
+ height: 100%;
+ }
+ }
+
+ .tabs {
+ display: flex;
+ height: 41px;
+ width: 100%;
+ }
+
+ .debugger {
+ display: flex;
+ height: 64px;
+ }
+
+ .editor {
+ height: 60%;
+ overflow-y: scroll;
+ }
+
+ .console {
+ height: 40%;
+ overflow-y: scroll;
+ }
+ }
+}
diff --git a/paimon-web-ui-new/src/views/playground/components/workbench/index.tsx b/paimon-web-ui-new/src/views/playground/components/workbench/index.tsx
new file mode 100644
index 000000000..602436970
--- /dev/null
+++ b/paimon-web-ui-new/src/views/playground/components/workbench/index.tsx
@@ -0,0 +1,138 @@
+/* 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 styles from './index.module.scss'
+import MenuTree from './components/menu-tree';
+import EditorTabs from './components/tabs';
+import EditorDebugger from './components/debugger';
+import * as monaco from 'monaco-editor'
+import MonacoEditor from '@/components/monaco-editor';
+import EditorConsole from './components/console';
+import { format } from 'sql-formatter';
+import { useMessage } from 'naive-ui'
+
+export default defineComponent({
+ name: 'WorkbenchPage',
+ setup() {
+ const message = useMessage()
+
+ const editorVariables = reactive({
+ editor: {} as any,
+ language: 'sql'
+ })
+
+ const editorMounted = (editor: monaco.editor.IStandaloneCodeEditor) => {
+ editorVariables.editor = editor
+ }
+
+ const handleFormat = () => {
+ toRaw(editorVariables.editor).setValue(format(toRaw(editorVariables.editor).getValue()))
+ }
+
+ const editorSave = () => {
+ message.success('Save success')
+ tabData.value.panelsList.find((item: any) => item.key === tabData.value.chooseTab).content = toRaw(editorVariables.editor).getValue()
+ handleFormat()
+ tabData.value.panelsList.find((item: any) => item.key === tabData.value.chooseTab).isSaved = true
+ }
+
+ const handleContentChange = (value: string) => {
+ tabData.value.panelsList.find((item: any) => item.key === tabData.value.chooseTab).content = value
+ tabData.value.panelsList.find((item: any) => item.key === tabData.value.chooseTab).isSaved = false
+ }
+
+ const consoleHeightType = ref('down')
+
+ const handleConsoleUp = (type: string) => {
+ consoleHeightType.value = type
+ }
+
+ const handleConsoleDown = (type: string) => {
+ consoleHeightType.value = type
+ }
+
+
+ watch(
+ () => consoleHeightType.value,
+ () => {
+ if (tabData.value.panelsList?.length > 0) {
+ editorVariables.editor?.layout()
+ }
+ }
+ )
+
+ // mitt - handle tab choose
+ const tabData = ref({}) as any
+ const { mittBus } = getCurrentInstance()!.appContext.config.globalProperties
+ mittBus.on('initTabData', (data: any) => {
+ tabData.value = data
+ })
+
+ return {
+ ...toRefs(editorVariables),
+ editorMounted,
+ editorSave,
+ handleContentChange,
+ handleFormat,
+ tabData,
+ handleConsoleUp,
+ handleConsoleDown,
+ consoleHeightType
+ }
+ },
+ render() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ {
+ this.tabData.panelsList?.length > 0 &&
+
+ item.key === this.tabData.chooseTab).content}
+ language={this.language}
+ onEditorMounted={this.editorMounted}
+ onEditorSave={this.editorSave}
+ onChange={this.handleContentChange}
+ />
+
+ }
+
+
+ {
+ this.tabData.panelsList?.length > 0 &&
+
+
+
+ }
+
+
+
+
+ );
+ }
+});
diff --git a/paimon-web-ui-new/src/views/playground/index.module.scss b/paimon-web-ui-new/src/views/playground/index.module.scss
index 839bb211e..fe437d971 100644
--- a/paimon-web-ui-new/src/views/playground/index.module.scss
+++ b/paimon-web-ui-new/src/views/playground/index.module.scss
@@ -16,31 +16,13 @@ specific language governing permissions and limitations
under the License. */
.container {
- height: 100%;
+ display: flex;
width: 100%;
-
- :global {
- .n-tabs {
- height: 100%;
- }
- }
+ height: 100%;
.content {
display: flex;
+ width: calc(100% - 60px);
height: 100%;
-
- .catalog {
- width: 350px;
- height: 100%;
- padding: 10px;
- box-sizing: border-box;
- }
-
- .editor {
- height: 100%;
- flex: 1;
- padding: 10px;
- box-sizing: border-box;
- }
}
}
diff --git a/paimon-web-ui-new/src/views/playground/index.tsx b/paimon-web-ui-new/src/views/playground/index.tsx
index 448b0de6e..1d133cfbe 100644
--- a/paimon-web-ui-new/src/views/playground/index.tsx
+++ b/paimon-web-ui-new/src/views/playground/index.tsx
@@ -16,85 +16,18 @@ specific language governing permissions and limitations
under the License. */
import styles from './index.module.scss';
-import type { TabsProps } from 'naive-ui';
-import { Layers, CodeSlashSharp, SyncCircleOutline } from '@vicons/ionicons5';
-import CataLog from './components/catalog';
-import * as monaco from 'monaco-editor'
-import MonacoEditor from '@/components/monaco-editor';
-
+import Slider from './components/slider';
export default defineComponent({
name: 'PlaygroundPage',
- setup() {
- const type = ref('bar')
-
- const content = ref('')
- const language = ref('javascript')
- const editorMounted = (editor: monaco.editor.IStandaloneCodeEditor) => {
- console.log('Loaded editor instance.', editor)
- }
-
- return {
- type,
- content,
- language,
- editorMounted
- }
- },
+ setup() {},
render() {
return (
-
- (
-
-
-
- )
- }}
- >
-
-
- (
-
-
-
- )
- }}
- >
- Saved Queries
-
- (
-
-
-
- )
- }}
- >
- History
-
-
+
+
+
+
);
},