2
0
mirror of https://github.com/frappe/books.git synced 2024-11-10 07:40:55 +00:00

Merge pull request #255 from 18alantom/fixing-settings-popup

fix(ux): don't spawn a new window for settings
This commit is contained in:
Alan 2021-11-24 18:21:10 +05:30 committed by GitHub
commit c3760431a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 249 additions and 252 deletions

View File

@ -3,11 +3,12 @@
id="app"
class="h-screen flex flex-col font-sans overflow-hidden antialiased"
>
<WindowsTitleBar
v-if="platform === 'Windows'"
@close="reloadMainWindowOnSettingsClose"
<WindowsTitleBar v-if="platform === 'Windows'" />
<Desk
class="flex-1"
v-if="activeScreen === 'Desk'"
@change-db-file="changeDbFile"
/>
<Desk class="flex-1" v-if="activeScreen === 'Desk'" />
<DatabaseSelector
v-if="activeScreen === 'DatabaseSelector'"
@database-connect="showSetupWizardOrDesk(true)"
@ -16,23 +17,20 @@
v-if="activeScreen === 'SetupWizard'"
@setup-complete="showSetupWizardOrDesk(true)"
/>
<Settings v-if="activeScreen === 'Settings'" />
<portal-target name="popovers" multiple></portal-target>
</div>
</template>
<script>
import './styles/index.css';
// import 'frappe-charts/dist/frappe-charts.min.css';
import frappe from 'frappejs';
import Desk from './pages/Desk';
import SetupWizard from './pages/SetupWizard/SetupWizard';
import DatabaseSelector from './pages/DatabaseSelector';
import Settings from '@/pages/Settings/Settings.vue';
import WindowsTitleBar from '@/components/WindowsTitleBar';
import { ipcRenderer } from 'electron';
import config from '@/config';
import { connectToLocalDatabase } from '@/utils';
import { connectToLocalDatabase, routeTo, purgeCache } from '@/utils';
import { IPC_MESSAGES, IPC_ACTIONS } from '@/messages';
export default {
@ -48,16 +46,15 @@ export default {
const { width, height } = await ipcRenderer.invoke(
IPC_ACTIONS.GET_PRIMARY_DISPLAY_SIZE
);
let size = {
Desk: [width, height],
DatabaseSelector: [600, 600],
SetupWizard: [600, 600],
Settings: [460, 577],
}[value];
let resizable = value === 'Desk';
if (size.length && value != 'Settings') {
if (size.length) {
ipcRenderer.send(IPC_MESSAGES.RESIZE_MAIN_WINDOW, size, resizable);
}
},
@ -66,7 +63,6 @@ export default {
Desk,
SetupWizard,
DatabaseSelector,
Settings,
WindowsTitleBar,
},
async mounted() {
@ -86,24 +82,22 @@ export default {
const { setupComplete } = frappe.AccountingSettings;
if (!setupComplete) {
this.activeScreen = 'SetupWizard';
} else if (this.$route.path.startsWith('/settings')) {
this.activeScreen = 'Settings';
} else {
this.activeScreen = 'Desk';
this.checkForUpdates();
}
if (resetRoute) {
this.$router.replace('/');
}
},
reloadMainWindowOnSettingsClose() {
if (this.activeScreen === 'Settings') {
frappe.events.trigger('reload-main-window');
routeTo('/');
}
},
checkForUpdates() {
frappe.events.trigger('check-for-updates');
},
changeDbFile() {
config.set('lastSelectedFilePath', null);
purgeCache(true);
this.activeScreen = 'DatabaseSelector';
},
},
};
</script>

View File

@ -1,23 +1,21 @@
'use strict';
import path from 'path';
import electron, {
app,
dialog,
protocol,
BrowserWindow,
dialog,
ipcMain,
Menu,
protocol,
shell,
} from 'electron';
import { autoUpdater } from 'electron-updater';
import Store from 'electron-store';
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer';
import Store from 'electron-store';
import { autoUpdater } from 'electron-updater';
import path from 'path';
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib';
import { IPC_ACTIONS, IPC_MESSAGES } from './messages';
import saveHtmlAsPdf from './saveHtmlAsPdf';
import { IPC_MESSAGES, IPC_ACTIONS } from './messages';
import theme from '@/theme';
const isDevelopment = process.env.NODE_ENV !== 'production';
const isMac = process.platform === 'darwin';
@ -97,28 +95,6 @@ function createWindow() {
});
}
function createSettingsWindow(tab = 'General') {
let settingsWindow = new BrowserWindow({
parent: mainWindow,
frame: isLinux,
width: 460,
height: 577,
icon,
title,
backgroundColor: theme.backgroundColor.gray['200'],
webPreferences: {
contextIsolation: false, // TODO: Switch this on
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
},
resizable: false,
});
settingsWindow.loadURL(`${winURL}#/settings/${tab}`);
settingsWindow.on('close', () => {
mainWindow.reload();
});
}
/* ---------------------------------
* Register ipcMain message handlers
* ---------------------------------*/
@ -130,10 +106,6 @@ ipcMain.on(IPC_MESSAGES.CHECK_FOR_UPDATES, () => {
}
});
ipcMain.on(IPC_MESSAGES.OPEN_SETTINGS, (event, tab) => {
createSettingsWindow(tab);
});
ipcMain.on(IPC_MESSAGES.OPEN_MENU, (event) => {
const window = event.sender.getOwnerBrowserWindow();
const menu = Menu.getApplicationMenu();

View File

@ -1,4 +1,4 @@
<template>
t<template>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 18">
<g fill="none" fill-rule="evenodd" transform="translate(0 .5)">
<path

View File

@ -1,5 +1,18 @@
<template>
<div class="pt-6 pb-2 px-2 h-full block window-drag flex justify-between flex-col bg-gray-100" >
<div
class="
pt-6
pb-2
px-2
h-full
block
window-drag
flex
justify-between
flex-col
bg-gray-100
"
>
<div class="window-no-drag">
<WindowControls v-if="platform === 'Mac'" class="px-3 mb-6" />
<div class="px-3">
@ -10,7 +23,15 @@
<div class="mt-3">
<div class="mt-1 first:mt-0" v-for="group in groups" :key="group.title">
<div
class="px-3 py-2 flex items-center rounded-lg cursor-pointer hover:bg-white"
class="
px-3
py-2
flex
items-center
rounded-lg
cursor-pointer
hover:bg-white
"
:class="isActiveGroup(group) && !group.items ? 'bg-white' : ''"
@click="onGroupClick(group)"
>
@ -30,7 +51,16 @@
<div
v-for="item in group.items"
:key="item.label"
class="mt-1 first:mt-0 text-base text-gray-800 py-1 pl-10 rounded cursor-pointer hover:bg-white"
class="
mt-1
first:mt-0
text-base text-gray-800
py-1
pl-10
rounded
cursor-pointer
hover:bg-white
"
:class="itemActiveClass(item)"
@click="onItemClick(item)"
>
@ -40,41 +70,56 @@
</div>
</div>
</div>
<div class="px-5 pb-3 text-sm text-gray-600">v{{ appVersion }}</div>
<div class="px-5">
<button
class="pb-1 text-sm text-gray-600 hover:text-gray-800 truncate"
@click="$emit('change-db-file')"
>
{{ dbPath }}
</button>
<p class="pb-3 text-sm text-gray-600">v{{ appVersion }}</p>
</div>
</div>
</template>
<script>
import sidebarConfig from '../sidebarConfig';
import Button from '@/components/Button';
import WindowControls from './WindowControls';
import { routeTo } from '@/utils';
import path from 'path';
export default {
components: [Button],
data() {
return {
companyName: '',
groups: [],
activeGroup: null
activeGroup: null,
};
},
computed: {
appVersion() {
return frappe.store.appVersion;
}
},
dbPath() {
const splits = frappe.db.dbPath.split(path.sep);
return path.join(...splits.slice(splits.length - 2));
},
},
components: {
WindowControls
WindowControls,
},
async mounted() {
this.companyName = await sidebarConfig.getTitle();
this.groups = sidebarConfig.groups;
let currentPath = this.$router.currentRoute.fullPath;
this.activeGroup = this.groups.find(g => {
this.activeGroup = this.groups.find((g) => {
if (g.route === currentPath) {
return true;
}
if (g.items) {
let activeItem = g.items.filter(i => i.route === currentPath);
let activeItem = g.items.filter((i) => i.route === currentPath);
if (activeItem.length) {
return true;
}
@ -111,7 +156,7 @@ export default {
if (item.route) {
routeTo(item.route);
}
}
}
},
},
};
</script>

View File

@ -4,7 +4,6 @@
}}</Badge>
</template>
<script>
import frappe from 'frappejs';
import { statusColor } from '@/utils';
import Badge from '@/components/Badge';

View File

@ -1,6 +1,6 @@
<template>
<div class="flex overflow-hidden">
<Sidebar class="w-56 flex-shrink-0" />
<Sidebar class="w-56 flex-shrink-0" @change-db-file="$emit('change-db-file')"/>
<div class="flex flex-1 overflow-y-hidden bg-white">
<keep-alive>
<router-view class="flex-1" :key="$route.path" />

View File

@ -1,28 +1,48 @@
<template>
<div class="flex flex-col flex-1 overflow-hidden">
<div class="bg-gray-200 window-drag pb-2">
<div class="p-2">
<WindowControls v-if="platform === 'Mac'" :buttons="['close']" />
</div>
<Row
:columnCount="5"
class="px-6 border-none w-full window-no-drag"
gap="0.5rem"
<div class="flex flex-col overflow-hidden">
<PageHeader>
<h1 slot="title" class="text-2xl font-bold">
{{ _('Settings') }}
</h1>
</PageHeader>
<div class="flex justify-center flex-1 mb-8 mt-2">
<div
class="border rounded-lg shadow h-full flex flex-col justify-between"
style="width: 600px"
>
<div
v-for="(tab, i) in tabs"
:key="tab.label"
class="p-2 rounded-md hover:bg-white flex flex-col items-center justify-center cursor-pointer"
:class="i === activeTab && 'bg-white shadow text-blue-500'"
@click="activeTab = i"
>
<component :is="getIconComponent(tab)" :active="i === activeTab" />
<div class="mt-2 text-xs">{{ tab.label }}</div>
<div class="pb-2 mt-8">
<Row
:columnCount="tabs.length"
class="px-6 border-none w-full"
gap="0.5rem"
>
<div
v-for="(tab, i) in tabs"
:key="tab.label"
class="
p-2
rounded-md
hover:bg-white
flex flex-col
items-center
justify-center
cursor-pointer
"
:class="i === activeTab && 'text-blue-500'"
@click="activeTab = i"
>
<component
:is="getIconComponent(tab)"
:active="i === activeTab"
/>
<div class="mt-2 text-xs">{{ tab.label }}</div>
</div>
</Row>
</div>
</Row>
</div>
<div class="bg-white flex-1 p-6 overflow-y-auto">
<component :is="activeTabComponent" />
<div class="flex-1 p-6 overflow-y-auto">
<component :is="activeTabComponent" />
</div>
</div>
</div>
</div>
</template>
@ -32,49 +52,48 @@ import WindowControls from '@/components/WindowControls';
import TabGeneral from './TabGeneral.vue';
import TabSystem from './TabSystem.vue';
import TabInvoice from './TabInvoice.vue';
import Button from '@/components/Button';
import Row from '@/components/Row';
import Icon from '@/components/Icon';
import PageHeader from '@/components/PageHeader';
import StatusBadge from '@/components/StatusBadge';
export default {
name: 'Settings',
components: {
PageHeader,
WindowControls,
Row
StatusBadge,
Button,
Row,
},
data() {
return {
activeTab: 0,
updated: false,
tabs: [
{
label: _('General'),
icon: 'general',
component: TabGeneral
},
// {
// label: _('Mail'),
// icon: 'mail'
// },
{
label: _('Invoice'),
icon: 'invoice',
component: TabInvoice
component: TabInvoice,
},
{
label: _('General'),
icon: 'general',
component: TabGeneral,
},
{
label: _('System'),
icon: 'system',
component: TabSystem
}
// {
// label: _('Privacy'),
// icon: 'privacy'
// }
]
component: TabSystem,
},
],
};
},
mounted() {
let path = this.$router.currentRoute.fullPath;
let tab = path.replace('/settings/', '');
let index = this.tabs.findIndex(t => t.label === _(tab));
let index = this.tabs.findIndex((t) => t.label === _(tab));
if (index !== -1) {
this.activeTab = index;
}
@ -88,19 +107,23 @@ export default {
props: Object.assign(
{
name: tab.icon,
size: '24'
size: '24',
},
this.$attrs
)
),
});
}
},
};
}
},
onSaveClick() {
console.log('save clicked');
},
},
computed: {
activeTabComponent() {
return this.tabs[this.activeTab].component;
}
}
},
},
};
</script>

View File

@ -38,7 +38,7 @@
</template>
<script>
import frappe from 'frappejs';
import { dialog, ipcRenderer } from 'electron';
import { ipcRenderer } from 'electron';
import TwoColumnForm from '@/components/TwoColumnForm';
import FormControl from '@/components/Controls/FormControl';
import { IPC_ACTIONS } from '@/messages';

View File

@ -1,40 +1,11 @@
<template>
<div>
<div class="flex items-center justify-between">
<div class="flex items-center">
<svg
class="h-12"
viewBox="0 0 40 48"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M37.73 0c1.097 0 1.986.89 1.986 1.986v43.688c0 1.096-.889 1.986-1.986 1.986H1.986A1.986 1.986 0 010 45.674V1.986C0 .889.89 0 1.986 0zm-7.943 27.404c-2.283 1.688-6.156 2.383-9.929 2.383-3.773 0-7.645-.695-9.929-2.383v4.369l.006.156c.196 2.575 5.25 3.816 9.923 3.816 4.766 0 9.93-1.291 9.93-3.972zm0-7.943c-2.283 1.688-6.156 2.383-9.929 2.383-3.773 0-7.645-.695-9.929-2.383v4.369l.006.156c.196 2.575 5.25 3.815 9.923 3.815 4.766 0 9.93-1.29 9.93-3.971zm-9.929-7.546c-4.766 0-9.929 1.29-9.929 3.972 0 2.68 5.163 3.971 9.93 3.971 4.765 0 9.928-1.29 9.928-3.971s-5.163-3.972-9.929-3.972z"
fill="#2490EF"
fill-rule="evenodd"
/>
</svg>
<div class="flex flex-col w-56 ml-4 truncate">
<span class="font-semibold">{{ companyName }}</span>
<span class="text-xs text-gray-600">{{ dbPath }}</span>
</div>
</div>
<Button class="text-sm" @click="changeFile">
{{ _('Change File') }}
</Button>
</div>
<TwoColumnForm
class="mt-6"
v-if="doc"
:doc="doc"
:fields="fields"
:autosave="true"
/>
<TwoColumnForm v-if="doc" :doc="doc" :fields="fields" :autosave="true" />
<div class="mt-6">
<FormControl
:show-label="true"
:df="AccountingSettings.meta.getField('autoUpdate')"
@change="value => AccountingSettings.update('autoUpdate', value)"
@change="(value) => AccountingSettings.update('autoUpdate', value)"
:value="AccountingSettings.autoUpdate"
/>
<p class="pl-6 mt-1 text-sm text-gray-600">
@ -49,46 +20,30 @@
import frappe from 'frappejs';
import TwoColumnForm from '@/components/TwoColumnForm';
import FormControl from '@/components/Controls/FormControl';
import Button from '@/components/Button';
import config from '@/config';
import { ipcRenderer } from 'electron';
import { IPC_MESSAGES } from '@/messages';
export default {
name: 'TabSystem',
components: {
TwoColumnForm,
FormControl,
Button
},
data() {
return {
companyName: null,
doc: null
doc: null,
};
},
async mounted() {
this.doc = frappe.SystemSettings;
this.companyName = frappe.AccountingSettings.companyName;
},
methods: {
changeFile() {
config.set('lastSelectedFilePath', null);
frappe.events.trigger('reload-main-window');
ipcRenderer.send(IPC_MESSAGES.CLOSE_CURRENT_WINDOW);
}
},
computed: {
fields() {
let meta = frappe.getMeta('SystemSettings');
return meta.getQuickEditFields();
},
dbPath() {
return frappe.db.dbPath;
},
AccountingSettings() {
return frappe.AccountingSettings;
}
}
},
},
};
</script>

View File

@ -74,6 +74,7 @@ import {
getErrorMessage,
handleErrorWithDialog,
showMessageDialog,
purgeCache,
} from '@/utils';
export default {
@ -145,13 +146,7 @@ export default {
const filePath = config.get('lastSelectedFilePath');
renameDbFile(filePath);
// Clear cache to prevent doc changed error.
Object.keys(frappe.docs)
.filter((d) => frappe.docs[d][d] instanceof frappe.BaseMeta)
.forEach((d) => {
frappe.removeFromCache(d, d);
delete frappe[d];
});
purgeCache();
const connectionSuccess = await connectToLocalDatabase(filePath);
if (connectionSuccess) {

View File

@ -1,103 +1,110 @@
import Vue from 'vue';
import Router from 'vue-router';
import ChartOfAccounts from '@/pages/ChartOfAccounts';
// standard views
import Dashboard from '@/pages/Dashboard/Dashboard';
// custom views
import GetStarted from '@/pages/GetStarted';
import InvoiceForm from '@/pages/InvoiceForm';
import JournalEntryForm from '@/pages/JournalEntryForm';
import ListView from '@/pages/ListView/ListView';
import PrintView from '@/pages/PrintView/PrintView';
import QuickEditForm from '@/pages/QuickEditForm';
import Report from '@/pages/Report';
import Settings from '@/pages/Settings/Settings';
import Vue from 'vue';
import Router from 'vue-router';
// custom views
import GetStarted from '@/pages/GetStarted';
import ChartOfAccounts from '@/pages/ChartOfAccounts';
import InvoiceForm from '@/pages/InvoiceForm';
import JournalEntryForm from '@/pages/JournalEntryForm';
Vue.use(Router);
const routes = [
{
path: '/',
component: Dashboard
component: Dashboard,
},
{
path: '/get-started',
component: GetStarted
component: GetStarted,
},
{
path: '/edit/JournalEntry/:name',
name: 'JournalEntryForm',
components: {
default: JournalEntryForm,
edit: QuickEditForm
edit: QuickEditForm,
},
props: {
default: route => {
default: (route) => {
// for sidebar item active state
route.params.doctype = 'JournalEntry';
return {
doctype: 'JournalEntry',
name: route.params.name
name: route.params.name,
};
},
edit: route => route.query
}
edit: (route) => route.query,
},
},
{
path: '/edit/:doctype/:name',
name: 'InvoiceForm',
components: {
default: InvoiceForm,
edit: QuickEditForm
edit: QuickEditForm,
},
props: {
default: true,
edit: route => route.query
}
edit: (route) => route.query,
},
},
{
path: '/list/:doctype',
name: 'ListView',
components: {
default: ListView,
edit: QuickEditForm
edit: QuickEditForm,
},
props: {
default: route => {
default: (route) => {
const { doctype, filters } = route.params;
return {
doctype,
filters
filters,
};
},
edit: route => route.query
}
edit: (route) => route.query,
},
},
{
path: '/print/:doctype/:name',
name: 'PrintView',
component: PrintView,
props: true
props: true,
},
{
path: '/report/:reportName',
name: 'Report',
component: Report,
props: true
props: true,
},
{
path: '/chart-of-accounts',
name: 'Chart Of Accounts',
components: {
default: ChartOfAccounts,
edit: QuickEditForm
edit: QuickEditForm,
},
props: {
default: true,
edit: route => route.query
}
}
edit: (route) => route.query,
},
},
{
path: '/settings',
name: 'Settings',
component: Settings,
props: true,
},
];
let router = new Router({ routes });

View File

@ -1,5 +1,4 @@
import frappe from 'frappejs';
import { openSettings } from '@/utils';
import { _ } from 'frappejs/utils';
import Icon from './components/Icon';
@ -12,12 +11,12 @@ const config = {
{
title: _('Get Started'),
route: '/get-started',
icon: getIcon('general', '24', '5')
icon: getIcon('general', '24', '5'),
},
{
title: _('Dashboard'),
route: '/',
icon: getIcon('dashboard')
icon: getIcon('dashboard'),
},
{
title: _('Sales'),
@ -27,29 +26,29 @@ const config = {
{
label: _('Invoices'),
route: '/list/SalesInvoice',
doctype: 'SalesInvoice'
doctype: 'SalesInvoice',
},
{
label: _('Customers'),
route: '/list/Customer',
doctype: 'Customer'
doctype: 'Customer',
},
{
label: _('Items'),
route: '/list/Item',
doctype: 'Item'
doctype: 'Item',
},
{
label: _('Payments'),
route: '/list/Payment',
doctype: 'Payment'
doctype: 'Payment',
},
{
label: _('Journal Entry'),
route: '/list/JournalEntry',
doctype: 'JournalEntry'
}
]
doctype: 'JournalEntry',
},
],
},
{
title: _('Purchases'),
@ -59,29 +58,29 @@ const config = {
{
label: _('Bills'),
route: '/list/PurchaseInvoice',
doctype: 'PurchaseInvoice'
doctype: 'PurchaseInvoice',
},
{
label: _('Suppliers'),
route: '/list/Supplier',
doctype: 'Supplier'
doctype: 'Supplier',
},
{
label: _('Items'),
route: '/list/Item',
doctype: 'Item'
doctype: 'Item',
},
{
label: _('Payments'),
route: '/list/Payment',
doctype: 'Payment'
doctype: 'Payment',
},
{
label: _('Journal Entry'),
route: '/list/JournalEntry',
doctype: 'JournalEntry'
}
]
doctype: 'JournalEntry',
},
],
},
{
title: _('Reports'),
@ -90,21 +89,21 @@ const config = {
items: [
{
label: _('General Ledger'),
route: '/report/general-ledger'
route: '/report/general-ledger',
},
{
label: _('Profit And Loss'),
route: '/report/profit-and-loss'
route: '/report/profit-and-loss',
},
{
label: _('Balance Sheet'),
route: '/report/balance-sheet'
route: '/report/balance-sheet',
},
{
label: _('Trial Balance'),
route: '/report/trial-balance'
}
]
route: '/report/trial-balance',
},
],
},
{
title: _('Setup'),
@ -113,22 +112,20 @@ const config = {
items: [
{
label: _('Chart of Accounts'),
route: '/chart-of-accounts'
route: '/chart-of-accounts',
},
{
label: _('Taxes'),
route: '/list/Tax',
doctype: 'Tax'
doctype: 'Tax',
},
{
label: _('Settings'),
action() {
openSettings();
}
}
]
}
]
route: '/settings',
},
],
},
],
};
function getIcon(name, size = '18', height = null) {
@ -140,12 +137,12 @@ function getIcon(name, size = '18', height = null) {
{
name,
size,
height
height,
},
this.$attrs
)
),
});
}
},
};
}

View File

@ -1,14 +1,14 @@
import frappe from 'frappejs';
import fs from 'fs';
import { _ } from 'frappejs/utils';
import migrate from './migrate';
import { ipcRenderer } from 'electron';
import { IPC_MESSAGES, IPC_ACTIONS } from './messages';
import SQLite from 'frappejs/backends/sqlite';
import postStart from '../server/postStart';
import router from '@/router';
import Avatar from '@/components/Avatar';
import config from '@/config';
import router from '@/router';
import { ipcRenderer } from 'electron';
import frappe from 'frappejs';
import SQLite from 'frappejs/backends/sqlite';
import { _ } from 'frappejs/utils';
import fs from 'fs';
import postStart from '../server/postStart';
import { IPC_ACTIONS, IPC_MESSAGES } from './messages';
import migrate from './migrate';
export async function createNewDatabase() {
const options = {
@ -212,7 +212,7 @@ export function openQuickEdit({ doctype, name, hideFields, defaults = {} }) {
// editing another document of the same doctype
method = 'replace';
}
if (query.name === name) return
if (query.name === name) return;
router[method]({
query: {
edit: 1,
@ -257,7 +257,8 @@ export function getActionsForDocument(doc) {
component: {
template: `<span class="text-red-700">{{ _('Delete') }}</span>`,
},
condition: (doc) => !doc.isNew() && !doc.submitted && !doc.meta.isSingle && !doc.cancelled,
condition: (doc) =>
!doc.isNew() && !doc.submitted && !doc.meta.isSingle && !doc.cancelled,
action: () =>
deleteDocWithPrompt(doc).then((res) => {
if (res) {
@ -293,10 +294,6 @@ export function getActionsForDocument(doc) {
return actions;
}
export function openSettings(tab = 'General') {
ipcRenderer.send(IPC_MESSAGES.OPEN_SETTINGS, tab);
}
export async function runWindowAction(name) {
switch (name) {
case 'close':
@ -341,3 +338,16 @@ export function routeTo(route) {
router.push(route);
}
}
export function purgeCache(purgeAll = false) {
const filterFunction = purgeAll
? (d) => true
: (d) => frappe.docs[d][d] instanceof frappe.BaseMeta;
Object.keys(frappe.docs)
.filter(filterFunction)
.forEach((d) => {
frappe.removeFromCache(d, d);
delete frappe[d];
});
}