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:
commit
c3760431a1
34
src/App.vue
34
src/App.vue
@ -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>
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -4,7 +4,6 @@
|
||||
}}</Badge>
|
||||
</template>
|
||||
<script>
|
||||
import frappe from 'frappejs';
|
||||
import { statusColor } from '@/utils';
|
||||
import Badge from '@/components/Badge';
|
||||
|
||||
|
@ -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" />
|
||||
|
@ -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>
|
||||
|
@ -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';
|
||||
|
@ -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>
|
||||
|
@ -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) {
|
||||
|
@ -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 });
|
||||
|
@ -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
|
||||
)
|
||||
),
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
40
src/utils.js
40
src/utils.js
@ -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];
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user