feat(editor): apply word wrap to config editors
This commit is contained in:
13 files changed
+48
-12
No files matched your search
@@ -4,6 +4,7 @@ import { useI18n } from "vue-i18n";
|
||||
import { Pane, Splitpanes } from "splitpanes";
|
||||
import "splitpanes/dist/splitpanes.css";
|
||||
import { useConnectionStore } from "@/stores/connectionStore";
|
||||
import { useSettingsStore } from "@/stores/settingsStore";
|
||||
import { Activity, Check, ChevronDown, ChevronRight, Clock3, Copy, Download, FolderClosed, FolderOpen, KeyRound, Loader2, LockKeyhole, Pencil, Plus, RefreshCw, Search, Square, Trash2 } from "@lucide/vue";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
@@ -237,6 +238,7 @@ const emit = defineEmits<{
|
||||
const { t } = useI18n();
|
||||
const { toast } = useToast();
|
||||
const connectionStore = useConnectionStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
const searchInputRef = ref<HTMLInputElement>();
|
||||
const prefix = ref("");
|
||||
const keySuggestionOpen = ref(false);
|
||||
@@ -2024,7 +2026,8 @@ defineExpose({
|
||||
</Button>
|
||||
<pre
|
||||
data-native-clipboard
|
||||
class="dbx-editor-font-family m-0 max-h-[40vh] min-h-32 overflow-auto rounded-md border bg-muted/20 whitespace-pre-wrap break-words p-3 pr-12 text-sm"
|
||||
class="dbx-editor-font-family m-0 max-h-[40vh] min-h-32 overflow-auto rounded-md border bg-muted/20 p-3 pr-12 text-sm"
|
||||
:class="settingsStore.editorSettings.wordWrap ? 'whitespace-pre-wrap break-words' : 'whitespace-pre'"
|
||||
><template v-for="(segment, index) in selectedValueHighlightSegments" :key="index"><mark v-if="segment.matched" class="rounded-sm bg-amber-300/80 px-0.5 text-foreground dark:bg-amber-500/40">{{ segment.text }}</mark><span v-else>{{ segment.text }}</span></template></pre>
|
||||
</div>
|
||||
<div v-if="selectedValueCanPrettyJson" class="mt-2 flex justify-end">
|
||||
|
||||
@@ -13,6 +13,7 @@ import { properties } from "@codemirror/legacy-modes/mode/properties";
|
||||
import { shell } from "@codemirror/legacy-modes/mode/shell";
|
||||
import { onBeforeUnmount, onMounted, ref, watch } from "vue";
|
||||
import type { KvValueFormat } from "@/lib/kv/kvValueFormat";
|
||||
import { useSettingsStore } from "@/stores/settingsStore";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
@@ -28,8 +29,10 @@ const props = withDefaults(
|
||||
|
||||
const emit = defineEmits<{ "update:modelValue": [value: string] }>();
|
||||
const host = ref<HTMLElement>();
|
||||
const settingsStore = useSettingsStore();
|
||||
const languageCompartment = new Compartment();
|
||||
const readOnlyCompartment = new Compartment();
|
||||
const wordWrapCompartment = new Compartment();
|
||||
let view: EditorView | null = null;
|
||||
|
||||
function languageExtension(format: KvValueFormat) {
|
||||
@@ -48,6 +51,10 @@ function readOnlyExtensions(readOnly: boolean) {
|
||||
return [EditorState.readOnly.of(readOnly), EditorView.editable.of(!readOnly)];
|
||||
}
|
||||
|
||||
function wordWrapExtension(wordWrap = settingsStore.editorSettings.wordWrap) {
|
||||
return wordWrap ? EditorView.lineWrapping : [];
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (!host.value) return;
|
||||
view = new EditorView({
|
||||
@@ -58,7 +65,7 @@ onMounted(() => {
|
||||
basicSetup,
|
||||
languageCompartment.of(languageExtension(props.format)),
|
||||
readOnlyCompartment.of(readOnlyExtensions(props.readOnly)),
|
||||
EditorView.lineWrapping,
|
||||
wordWrapCompartment.of(wordWrapExtension()),
|
||||
EditorView.theme({
|
||||
"&": { height: "100%", fontSize: "13px", backgroundColor: "transparent" },
|
||||
".cm-scroller": { fontFamily: "var(--dbx-editor-font-family, ui-monospace)", overflow: "auto" },
|
||||
@@ -91,6 +98,11 @@ watch(
|
||||
(readOnly) => view?.dispatch({ effects: readOnlyCompartment.reconfigure(readOnlyExtensions(readOnly)) }),
|
||||
);
|
||||
|
||||
watch(
|
||||
() => settingsStore.editorSettings.wordWrap,
|
||||
(wordWrap) => view?.dispatch({ effects: wordWrapCompartment.reconfigure(wordWrapExtension(wordWrap)) }),
|
||||
);
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
view?.destroy();
|
||||
view = null;
|
||||
|
||||
@@ -2,6 +2,7 @@ import { readFileSync } from "node:fs";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
const browserSource = readFileSync(new URL("../KvKeyBrowser.vue", import.meta.url), "utf8");
|
||||
const valueEditorSource = readFileSync(new URL("../KvValueEditor.vue", import.meta.url), "utf8");
|
||||
|
||||
describe("KvKeyBrowser edit dialog layout", () => {
|
||||
it("keeps the value format label and selector together in the editor toolbar", () => {
|
||||
@@ -28,4 +29,16 @@ describe("KvKeyBrowser edit dialog layout", () => {
|
||||
expect(browserSource).toContain('<Copy v-else class="h-4 w-4" />');
|
||||
expect(browserSource).toMatch(/<pre\s+data-native-clipboard/);
|
||||
});
|
||||
|
||||
it("keeps the selected value preview word wrapping aligned with the global editor setting", () => {
|
||||
expect(browserSource).toContain(":class=\"settingsStore.editorSettings.wordWrap ? 'whitespace-pre-wrap break-words' : 'whitespace-pre'\"");
|
||||
expect(browserSource).not.toContain("bg-muted/20 whitespace-pre-wrap break-words p-3");
|
||||
});
|
||||
|
||||
it("keeps shared KV value editor word wrapping aligned with the global editor setting", () => {
|
||||
expect(valueEditorSource).toContain("const wordWrapCompartment = new Compartment()");
|
||||
expect(valueEditorSource).toContain("wordWrapCompartment.of(wordWrapExtension())");
|
||||
expect(valueEditorSource).toContain("wordWrapCompartment.reconfigure(wordWrapExtension(wordWrap))");
|
||||
expect(valueEditorSource).not.toContain("\n EditorView.lineWrapping,\n");
|
||||
});
|
||||
});
|
||||
@@ -197,6 +197,7 @@ const importSource = shallowRef<string | File | null>(null);
|
||||
const importSourceName = ref("");
|
||||
const configEditorTheme = new Compartment();
|
||||
const configEditorFontTheme = new Compartment();
|
||||
const configEditorWordWrap = new Compartment();
|
||||
const configEditorLanguage = new Compartment();
|
||||
const configListRequestGuard = createNacosLatestRequestGuard();
|
||||
const configDetailRequestGuard = createNacosLatestRequestGuard();
|
||||
@@ -553,7 +554,7 @@ async function mountConfigEditor() {
|
||||
configEditorLanguage.of(language),
|
||||
configEditorTheme.of(theme),
|
||||
configEditorFontTheme.of(editorFontTheme(EditorView, editorSettings.fontSize, editorSettings.fontFamily, { fixedHeight: true, scrollable: true })),
|
||||
EditorView.lineWrapping,
|
||||
configEditorWordWrap.of(editorSettings.wordWrap ? EditorView.lineWrapping : []),
|
||||
EditorState.readOnly.of(!!props.readOnly),
|
||||
EditorView.editable.of(!props.readOnly),
|
||||
EditorView.updateListener.of((update) => {
|
||||
@@ -2314,7 +2315,7 @@ watch(
|
||||
if (configEditorView.value !== view) return;
|
||||
configEditorFontSize.value = clampEditorFontSize(settings.fontSize);
|
||||
view.dispatch({
|
||||
effects: [configEditorTheme.reconfigure(theme), configEditorFontTheme.reconfigure(editorFontTheme(EditorView, settings.fontSize, settings.fontFamily, { fixedHeight: true, scrollable: true }))],
|
||||
effects: [configEditorTheme.reconfigure(theme), configEditorFontTheme.reconfigure(editorFontTheme(EditorView, settings.fontSize, settings.fontFamily, { fixedHeight: true, scrollable: true })), configEditorWordWrap.reconfigure(settings.wordWrap ? EditorView.lineWrapping : [])],
|
||||
});
|
||||
},
|
||||
{ deep: true },
|
||||
|
||||
@@ -123,6 +123,13 @@ describe("NacosAdminConsole config workbench layout", () => {
|
||||
expect(source).toContain("configEditorZoomCommitScheduler.dispose()");
|
||||
});
|
||||
|
||||
it("keeps the configuration editor word wrapping aligned with the global editor setting", () => {
|
||||
expect(source).toContain("const configEditorWordWrap = new Compartment()");
|
||||
expect(source).toContain("configEditorWordWrap.of(editorSettings.wordWrap ? EditorView.lineWrapping : [])");
|
||||
expect(source).toContain("configEditorWordWrap.reconfigure(settings.wordWrap ? EditorView.lineWrapping : [])");
|
||||
expect(source).not.toContain("\n EditorView.lineWrapping,\n");
|
||||
});
|
||||
|
||||
it("allows optional configuration columns to be hidden without hiding the data ID", () => {
|
||||
const configListHeader = source.indexOf('class="sticky top-0 z-20 grid border-b bg-muted');
|
||||
const columnVisibility = source.indexOf("nacos.visibleColumns");
|
||||
|
||||
@@ -5780,7 +5780,7 @@ export default {
|
||||
showInsertValueHintsDescription: "When enabled, the SQL editor shows column-name hints next to each value in INSERT ... VALUES clauses.",
|
||||
previewStatementRunButton: "Preview statement run button",
|
||||
wordWrap: "Word wrap",
|
||||
wordWrapDescription: "Wrap long SQL lines within the editor width",
|
||||
wordWrapDescription: "Wrap long lines within the editor width",
|
||||
vimMode: "Vim mode",
|
||||
vimModeDescription: "Use Vim-style modal editing in the SQL editor",
|
||||
autoCloseBrackets: "Auto-close brackets",
|
||||
|
||||
@@ -5505,7 +5505,7 @@ export default withEnglishFallback({
|
||||
showInsertValueHintsDescription: "Al activarlo, el editor SQL muestra el nombre de columna junto a cada valor en cláusulas INSERT ... VALUES.",
|
||||
previewStatementRunButton: "Botón de ejecución de sentencia en vista previa",
|
||||
wordWrap: "Ajuste de línea",
|
||||
wordWrapDescription: "Ajustar las líneas largas de SQL al ancho del editor",
|
||||
wordWrapDescription: "Ajustar las líneas largas al ancho del editor",
|
||||
vimMode: "Modo Vim",
|
||||
vimModeDescription: "Usar edición modal estilo Vim en el editor SQL",
|
||||
autoCloseBrackets: "Cerrar paréntesis automáticamente",
|
||||
|
||||
@@ -5505,7 +5505,7 @@ export default withEnglishFallback({
|
||||
showInsertValueHintsDescription: "Se attivo, l'editor SQL mostra il nome della colonna accanto a ogni valore nelle clausole INSERT ... VALUES.",
|
||||
previewStatementRunButton: "Pulsante di esecuzione istruzione in anteprima",
|
||||
wordWrap: "A capo automatico",
|
||||
wordWrapDescription: "Incolonna le righe SQL lunghe entro la larghezza dell'editor",
|
||||
wordWrapDescription: "Manda a capo le righe lunghe entro la larghezza dell'editor",
|
||||
vimMode: "Modalita Vim",
|
||||
vimModeDescription: "Usa la modifica modale in stile Vim nell'editor SQL",
|
||||
autoCloseBrackets: "Chiusura automatica parentesi",
|
||||
|
||||
@@ -5534,7 +5534,7 @@ export default withEnglishFallback({
|
||||
showInsertValueHintsDescription: "有効にすると、INSERT ... VALUES 句の各値の横に対応する列名ヒントを表示します。",
|
||||
previewStatementRunButton: "文の実行ボタンのプレビュー",
|
||||
wordWrap: "折り返し",
|
||||
wordWrapDescription: "長いSQL行をエディタ幅内で折り返します",
|
||||
wordWrapDescription: "長い行をエディタ幅内で折り返します",
|
||||
vimMode: "Vimモード",
|
||||
vimModeDescription: "SQLエディタでVim形式のモーダル編集を使用します",
|
||||
autoCloseBrackets: "自動括弧補完",
|
||||
|
||||
@@ -5266,7 +5266,7 @@ export default withEnglishFallback({
|
||||
showInsertValueHintsDescription: "활성화하면 SQL 편집기가 INSERT ... VALUES 절의 각 값 옆에 컬럼 이름 힌트를 표시합니다.",
|
||||
previewStatementRunButton: "구문 실행 버튼 미리보기",
|
||||
wordWrap: "자동 줄바꿈",
|
||||
wordWrapDescription: "편집기 너비 내에서 긴 SQL 줄을 줄바꿈합니다",
|
||||
wordWrapDescription: "편집기 너비 내에서 긴 줄을 줄바꿈합니다",
|
||||
vimMode: "Vim 모드",
|
||||
vimModeDescription: "SQL 편집기에서 Vim 스타일의 모달 편집을 사용합니다",
|
||||
autoCloseBrackets: "괄호 자동 닫기",
|
||||
|
||||
@@ -5507,7 +5507,7 @@ export default withEnglishFallback({
|
||||
showInsertValueHintsDescription: "Quando ativado, o editor SQL mostra o nome da coluna ao lado de cada valor em cláusulas INSERT ... VALUES.",
|
||||
previewStatementRunButton: "Botão de execução de instrução na prévia",
|
||||
wordWrap: "Quebra de linha",
|
||||
wordWrapDescription: "Quebrar linhas SQL longas dentro da largura do editor",
|
||||
wordWrapDescription: "Quebrar linhas longas dentro da largura do editor",
|
||||
vimMode: "Modo Vim",
|
||||
vimModeDescription: "Usar edição modal no estilo Vim no editor SQL",
|
||||
autoCloseBrackets: "Fechar parênteses automaticamente",
|
||||
|
||||
@@ -5701,7 +5701,7 @@ export default withEnglishFallback({
|
||||
showInsertValueHintsDescription: "开启后,在 INSERT ... VALUES 子句的每个值旁显示对应列名提示。",
|
||||
previewStatementRunButton: "预览语句执行按钮",
|
||||
wordWrap: "自动换行",
|
||||
wordWrapDescription: "长 SQL 在编辑器宽度内自动折行显示",
|
||||
wordWrapDescription: "长内容在编辑器宽度内自动折行显示",
|
||||
vimMode: "Vim 模式",
|
||||
vimModeDescription: "在 SQL 编辑器中使用 Vim 风格的模态编辑",
|
||||
autoCloseBrackets: "自动成对补全",
|
||||
|
||||
@@ -4844,7 +4844,7 @@ export default withEnglishFallback({
|
||||
showInsertValueHintsDescription: "啟用後,在 INSERT ... VALUES 子句的每個值旁顯示對應欄位名稱提示。",
|
||||
previewStatementRunButton: "預覽語句執行按鈕",
|
||||
wordWrap: "自動換行",
|
||||
wordWrapDescription: "長 SQL 在編輯器寬度內自動折行顯示",
|
||||
wordWrapDescription: "長內容在編輯器寬度內自動折行顯示",
|
||||
vimMode: "Vim 模式",
|
||||
vimModeDescription: "在 SQL 編輯器中使用 Vim 風格的模態編輯",
|
||||
autoCloseBrackets: "自動成對補全",
|
||||
|
||||
Reference in new issue
Block a user