From 8f84f2677c87d794f1057f42df226c12639b77bd Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Mon, 13 Mar 2023 12:36:56 +0530 Subject: [PATCH] incr: add template select and save menu items - add shortcut for view hints, show shortcut to apply changes - update shortcut helper ui --- reports/GoodsAndServiceTax/gstExporter.ts | 2 +- reports/commonExporter.ts | 11 +- src/components/ShortcutKeys.vue | 39 ++++++ src/components/ShortcutsHelper.vue | 108 ++++------------- src/pages/ImportWizard.vue | 23 +--- src/pages/TemplateBuilder/TemplateBuilder.vue | 113 +++++++++++++++++- src/utils/ui.ts | 65 ++++++++++ 7 files changed, 248 insertions(+), 113 deletions(-) create mode 100644 src/components/ShortcutKeys.vue diff --git a/reports/GoodsAndServiceTax/gstExporter.ts b/reports/GoodsAndServiceTax/gstExporter.ts index 01849fdd..f0d55f55 100644 --- a/reports/GoodsAndServiceTax/gstExporter.ts +++ b/reports/GoodsAndServiceTax/gstExporter.ts @@ -162,7 +162,7 @@ async function exportReport(extention: ExportExtention, report: BaseGSTR) { return; } - await saveExportData(data, filePath, report.fyo); + await saveExportData(data, filePath); report.fyo.telemetry.log(Verb.Exported, report.reportName, { extention }); } diff --git a/reports/commonExporter.ts b/reports/commonExporter.ts index e8001e54..d4cdcdc5 100644 --- a/reports/commonExporter.ts +++ b/reports/commonExporter.ts @@ -52,7 +52,7 @@ async function exportReport(extention: ExportExtention, report: Report) { return; } - await saveExportData(data, filePath, report.fyo); + await saveExportData(data, filePath); report.fyo.telemetry.log(Verb.Exported, report.reportName, { extention }); } @@ -178,7 +178,12 @@ function getValueFromCell(cell: ReportCell, displayPrecision: number) { return rawValue; } -export async function saveExportData(data: string, filePath: string, fyo: Fyo) { +export async function saveExportData( + data: string, + filePath: string, + message?: string +) { await saveData(data, filePath); - showExportInFolder(fyo.t`Export Successful`, filePath); + message ??= t`Export Successful`; + showExportInFolder(message, filePath); } diff --git a/src/components/ShortcutKeys.vue b/src/components/ShortcutKeys.vue new file mode 100644 index 00000000..3507ceda --- /dev/null +++ b/src/components/ShortcutKeys.vue @@ -0,0 +1,39 @@ + + + diff --git a/src/components/ShortcutsHelper.vue b/src/components/ShortcutsHelper.vue index 5f79cb4f..a1132041 100644 --- a/src/components/ShortcutsHelper.vue +++ b/src/components/ShortcutsHelper.vue @@ -22,29 +22,7 @@ class="grid gap-4 items-start" style="grid-template-columns: 6rem auto" > - -
- {{ k }} -
+
{{ s.description }}
@@ -63,8 +41,10 @@ diff --git a/src/pages/ImportWizard.vue b/src/pages/ImportWizard.vue index 084a4545..a7980ded 100644 --- a/src/pages/ImportWizard.vue +++ b/src/pages/ImportWizard.vue @@ -386,7 +386,7 @@ import { fyo } from 'src/initFyo'; import { getSavePath, saveData, selectFile } from 'src/utils/ipcCalls'; import { docsPathMap } from 'src/utils/misc'; import { docsPathRef } from 'src/utils/refs'; -import { showMessageDialog } from 'src/utils/ui'; +import { selectTextFile, showMessageDialog } from 'src/utils/ui'; import { defineComponent } from 'vue'; import Loading from '../components/Loading.vue'; @@ -906,27 +906,14 @@ export default defineComponent({ : ''; }, async selectFile(): Promise { - const options = { - title: this.t`Select File`, - filters: [{ name: 'CSV', extensions: ['csv'] }], - }; + const { text, name, filePath } = await selectTextFile([ + { name: 'CSV', extensions: ['csv'] }, + ]); - const { success, canceled, filePath, data, name } = await selectFile( - options - ); - - if (!success && !canceled) { - await showMessageDialog({ - message: this.t`File selection failed.`, - }); + if (!text) { return; } - if (!success || canceled) { - return; - } - - const text = new TextDecoder().decode(data); const isValid = this.importer.selectFile(text); if (!isValid) { await showMessageDialog({ diff --git a/src/pages/TemplateBuilder/TemplateBuilder.vue b/src/pages/TemplateBuilder/TemplateBuilder.vue index 24dfde4f..b9754dae 100644 --- a/src/pages/TemplateBuilder/TemplateBuilder.vue +++ b/src/pages/TemplateBuilder/TemplateBuilder.vue @@ -25,7 +25,7 @@ > - + @@ -124,10 +124,10 @@ @@ -145,12 +145,24 @@ :initial-value="doc.template" :disabled="!doc.isCustom" :hints="hints" + @input="() => (templateChanged = true)" @blur="(value: string) => setTemplate(value)" /> +
+ + {{ t` to apply changes` }} +
-
+

- {{ t`Value Keys` }} + {{ t`Key Hints` }}

this.setScale(this.scale + 0.1)); this.shortcuts.ctrl.set(['Minus'], () => this.setScale(this.scale - 0.1)); }, @@ -298,6 +319,7 @@ export default defineComponent({ } this.shortcuts.ctrl.delete(['Enter']); this.shortcuts.ctrl.delete(['KeyE']); + this.shortcuts.ctrl.delete(['KeyH']); this.shortcuts.ctrl.delete(['Equal']); this.shortcuts.ctrl.delete(['Minus']); }, @@ -312,6 +334,7 @@ export default defineComponent({ return this.view.state.doc.toString(); }, async setTemplate(value?: string) { + this.templateChanged = false; if (!this.doc?.isCustom) { return; } @@ -329,6 +352,9 @@ export default defineComponent({ this.scale = Math.max(Math.min(value, 10), 0.15); }, + toggleShowHints() { + this.showHints = !this.showHints; + }, async toggleEditMode() { if (!this.doc?.isCustom) { return; @@ -455,8 +481,69 @@ export default defineComponent({ this.values = await getPrintTemplatePropValues(displayDoc); this.displayDoc = displayDoc; }, + async selectFile() { + const { name: fileName, text } = await selectTextFile([ + { name: 'Template', extensions: ['template.html', 'html'] }, + ]); + + if (!text) { + return; + } + + await this.doc?.set('template', text); + this.view?.dispatch({ + changes: { from: 0, to: this.view.state.doc.length, insert: text }, + }); + + if (this.doc?.inserted) { + return; + } + + let name: string | null = null; + if (fileName.endsWith('.template.html')) { + name = fileName.split('.template.html')[0]; + } + + if (!name && fileName.endsWith('.html')) { + name = fileName.split('.html')[0]; + } + + if (!name) { + return; + } + + await this.doc?.set('name', name); + }, + async saveFile() { + const name = this.doc?.name; + const template = this.getTemplateEditorState(); + + if (!name) { + return await showToast({ + type: 'warning', + message: this.t`Print Template Name not set`, + }); + } + + if (!template) { + return await showToast({ + type: 'warning', + message: this.t`Print Template is empty`, + }); + } + + const { canceled, filePath } = await getSavePath(name, 'template.html'); + if (canceled || !filePath) { + return; + } + + await saveExportData(template, filePath, this.t`Template file saved`); + }, }, computed: { + applyChangesShortcut() { + return [ShortcutKey.ctrl, ShortcutKey.enter]; + }, view(): EditorView | null { // @ts-ignore const { view } = this.$refs.templateEditor ?? {}; @@ -489,11 +576,25 @@ export default defineComponent({ actions.push({ label: this.t`Print Settings`, group: this.t`View`, - async action() { + action: async () => { await openSettings(ModelNameEnum.PrintSettings); }, }); + if (this.doc.isCustom) { + actions.push({ + label: this.t`Select Template File`, + group: this.t`Action`, + action: this.selectFile, + }); + } + + actions.push({ + label: this.t`Save Template File`, + group: this.t`Action`, + action: this.saveFile, + }); + return actions; }, fields(): Record { diff --git a/src/utils/ui.ts b/src/utils/ui.ts index 671bbda2..91cd3d1b 100644 --- a/src/utils/ui.ts +++ b/src/utils/ui.ts @@ -14,10 +14,12 @@ import { handleErrorWithDialog } from 'src/errorHandling'; import { fyo } from 'src/initFyo'; import router from 'src/router'; import { IPC_ACTIONS } from 'utils/messages'; +import { SelectFileOptions } from 'utils/types'; import { App, createApp, h } from 'vue'; import { RouteLocationRaw } from 'vue-router'; import { stringifyCircular } from './'; import { evaluateHidden } from './doc'; +import { selectFile } from './ipcCalls'; import { showSidebar } from './refs'; import { ActionGroup, @@ -506,3 +508,66 @@ export function focusOrSelectFormControl( doc.name = ''; } + +export async function selectTextFile(filters?: SelectFileOptions['filters']) { + const options = { + title: t`Select File`, + filters, + }; + const { success, canceled, filePath, data, name } = await selectFile(options); + + if (canceled || !success) { + await showToast({ + type: 'error', + message: t`File selection failed`, + }); + return {}; + } + + const text = new TextDecoder().decode(data); + if (!text) { + await showToast({ + type: 'error', + message: t`Empty file selected`, + }); + + return {}; + } + + return { text, filePath, name }; +} + +export enum ShortcutKey { + enter = 'enter', + ctrl = 'ctrl', + pmod = 'pmod', + shift = 'shift', + alt = 'alt', + delete = 'delete', + esc = 'esc', +} + +export function getShortcutKeyMap( + platform: string +): Record { + if (platform === 'Mac') { + return { + [ShortcutKey.alt]: '⌥', + [ShortcutKey.ctrl]: '⌃', + [ShortcutKey.pmod]: '⌘', + [ShortcutKey.shift]: 'shift', + [ShortcutKey.delete]: 'delete', + [ShortcutKey.esc]: 'esc', + [ShortcutKey.enter]: 'return', + }; + } + return { + [ShortcutKey.alt]: 'Alt', + [ShortcutKey.ctrl]: 'Ctrl', + [ShortcutKey.pmod]: 'Ctrl', + [ShortcutKey.shift]: '⇧', + [ShortcutKey.delete]: 'Backspace', + [ShortcutKey.esc]: 'Esc', + [ShortcutKey.enter]: 'Enter', + }; +}