mirror of
https://github.com/frappe/books.git
synced 2024-11-09 23:30:56 +00:00
feat: Settings - TabGeneral
This commit is contained in:
parent
38c3237ff3
commit
d7dc08a45d
@ -1,6 +1,4 @@
|
|||||||
const countryList = Object.keys(
|
const countryList = Object.keys(require('../../../fixtures/countryInfo.json')).sort();
|
||||||
require('../../../fixtures/countryInfo.json')
|
|
||||||
).sort();
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'AccountingSettings',
|
name: 'AccountingSettings',
|
||||||
@ -29,7 +27,7 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
fieldname: 'country',
|
fieldname: 'country',
|
||||||
label: 'Country',
|
label: 'Country',
|
||||||
fieldtype: 'Autocomplete',
|
fieldtype: 'AutoComplete',
|
||||||
required: 1,
|
required: 1,
|
||||||
getList: () => countryList
|
getList: () => countryList
|
||||||
},
|
},
|
||||||
@ -85,5 +83,14 @@ module.exports = {
|
|||||||
fieldtype: 'Date',
|
fieldtype: 'Date',
|
||||||
required: 1
|
required: 1
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
quickEditFields: [
|
||||||
|
'fullname',
|
||||||
|
'email',
|
||||||
|
'companyName',
|
||||||
|
'country',
|
||||||
|
'currency',
|
||||||
|
'fiscalYearStart',
|
||||||
|
'fiscalYearEnd',
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
10
src/App.vue
10
src/App.vue
@ -55,9 +55,7 @@ export default {
|
|||||||
Settings
|
Settings
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
if (this.$route.path === '/settings') {
|
if (!localStorage.dbPath) {
|
||||||
this.showSettings = true;
|
|
||||||
} else if (!localStorage.dbPath) {
|
|
||||||
this.showDatabaseSelector = true;
|
this.showDatabaseSelector = true;
|
||||||
} else {
|
} else {
|
||||||
frappe.events.trigger('connect-database', localStorage.dbPath);
|
frappe.events.trigger('connect-database', localStorage.dbPath);
|
||||||
@ -70,7 +68,11 @@ export default {
|
|||||||
});
|
});
|
||||||
|
|
||||||
frappe.events.on('show-desk', () => {
|
frappe.events.on('show-desk', () => {
|
||||||
this.showDesk = true;
|
if (this.$route.path === '/settings') {
|
||||||
|
this.showSettings = true;
|
||||||
|
} else {
|
||||||
|
this.showDesk = true;
|
||||||
|
}
|
||||||
this.showSetupWizard = false;
|
this.showSetupWizard = false;
|
||||||
this.showDatabaseSelector = false;
|
this.showDatabaseSelector = false;
|
||||||
});
|
});
|
||||||
|
40
src/components/TwoColumnForm.vue
Normal file
40
src/components/TwoColumnForm.vue
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<template>
|
||||||
|
<div class="border-t">
|
||||||
|
<div class="grid border-b text-xs" style="grid-template-columns: 1fr 1fr" v-for="df in fields">
|
||||||
|
<div class="py-2 pl-4 text-gray-600 flex items-center">{{ df.label }}</div>
|
||||||
|
<div class="py-2 pr-4">
|
||||||
|
<FormControl
|
||||||
|
size="small"
|
||||||
|
:df="df"
|
||||||
|
:value="doc[df.fieldname]"
|
||||||
|
@change="value => onChange(df, value)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import FormControl from '@/components/Controls/FormControl';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'TwoColumnForm',
|
||||||
|
props: ['doc', 'fields', 'autosave'],
|
||||||
|
provide() {
|
||||||
|
return {
|
||||||
|
doctype: this.doc.doctype,
|
||||||
|
name: this.doc.name
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
FormControl
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onChange(df, value) {
|
||||||
|
this.doc.set(df.fieldname, value);
|
||||||
|
if (this.autosave) {
|
||||||
|
this.doc.update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -1,32 +1,43 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="flex flex-col flex-1">
|
||||||
<div class="bg-gray-200 window-drag pb-2">
|
<div class="bg-gray-200 window-drag pb-2">
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<WindowControls />
|
<WindowControls />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-center">
|
<Row :columnCount="5" class="px-6" gap="0.5rem">
|
||||||
<div
|
<div
|
||||||
v-for="tab in tabs"
|
v-for="(tab, i) in tabs"
|
||||||
:key="tab.label"
|
:key="tab.label"
|
||||||
class="ml-2 p-2 w-20 h-16 rounded-6px hover:bg-white flex flex-col items-center justify-center cursor-pointer"
|
class="p-2 rounded-6px 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)" />
|
<component :is="getIconComponent(tab)" />
|
||||||
<div class="mt-2 text-xs">{{ tab.label }}</div>
|
<div class="mt-2 text-xs">{{ tab.label }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Row>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white flex-1 p-6">
|
||||||
|
<component :is="activeTabComponent" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { _ } from 'frappejs/utils';
|
import { _ } from 'frappejs/utils';
|
||||||
import WindowControls from '@/components/WindowControls';
|
import WindowControls from '@/components/WindowControls';
|
||||||
|
import TabGeneral from './TabGeneral.vue';
|
||||||
|
import Row from '@/components/Row';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Settings',
|
name: 'Settings',
|
||||||
components: {
|
components: {
|
||||||
WindowControls
|
WindowControls,
|
||||||
|
TabGeneral,
|
||||||
|
Row
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
activeTab: 0,
|
||||||
tabs: [
|
tabs: [
|
||||||
{
|
{
|
||||||
label: _('General'),
|
label: _('General'),
|
||||||
@ -35,7 +46,8 @@ export default {
|
|||||||
<path d="M18.94 13.94l4.025 4.024a3.535 3.535 0 11-5 5l-4.518-4.518 3.641-4.499c.304.035.607.053.912.053.318 0 .631-.024.94-.06zM4 0l4 4-1.293 1.293 2.378 2.378-1.522 1.306-2.27-2.27L4 8 0 4l4-4z" fill="#A1ABB4"/>
|
<path d="M18.94 13.94l4.025 4.024a3.535 3.535 0 11-5 5l-4.518-4.518 3.641-4.499c.304.035.607.053.912.053.318 0 .631-.024.94-.06zM4 0l4 4-1.293 1.293 2.378 2.378-1.522 1.306-2.27-2.27L4 8 0 4l4-4z" fill="#A1ABB4"/>
|
||||||
<path d="M20.271 6.771l-3.042-3.042L20.437.521A5.97 5.97 0 0018 0a6 6 0 00-5.75 7.708l-10.789 8.73a4.335 4.335 0 00-1.459 3.106 4.335 4.335 0 001.264 3.19 4.325 4.325 0 006.296-.195l8.73-10.789A6 6 0 0024 6c0-.869-.189-1.692-.521-2.438l-3.208 3.209z" fill="#415668"/>
|
<path d="M20.271 6.771l-3.042-3.042L20.437.521A5.97 5.97 0 0018 0a6 6 0 00-5.75 7.708l-10.789 8.73a4.335 4.335 0 00-1.459 3.106 4.335 4.335 0 001.264 3.19 4.325 4.325 0 006.296-.195l8.73-10.789A6 6 0 0024 6c0-.869-.189-1.692-.521-2.438l-3.208 3.209z" fill="#415668"/>
|
||||||
</g>
|
</g>
|
||||||
</svg>`
|
</svg>`,
|
||||||
|
component: TabGeneral
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: _('Mail'),
|
label: _('Mail'),
|
||||||
@ -78,6 +90,11 @@ export default {
|
|||||||
return {
|
return {
|
||||||
template: tab.icon
|
template: tab.icon
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
activeTabComponent() {
|
||||||
|
return this.tabs[this.activeTab].component;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
58
src/pages/TabGeneral.vue
Normal file
58
src/pages/TabGeneral.vue
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="bg-blue-500 px-6 py-5 rounded-12px flex justify-between items-center">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<div class="bg-white rounded-full w-16 h-16 flex justify-center items-center">
|
||||||
|
<svg class="w-6 h-6" viewBox="0 0 24 21" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path
|
||||||
|
d="M21 3h-4l-2-3H9L7 3H3a3 3 0 00-3 3v12a3 3 0 003 3h18a3 3 0 003-3V6a3 3 0 00-3-3zm-9 14a5 5 0 110-10 5 5 0 010 10z"
|
||||||
|
fill="#B7BFC6"
|
||||||
|
fill-rule="nonzero"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col text-white ml-4">
|
||||||
|
<span class="text-lg font-semibold">Company Name</span>
|
||||||
|
<span class="text-sm">Email</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button class="text-xs">Edit</Button>
|
||||||
|
</div>
|
||||||
|
<TwoColumnForm class="mt-6" v-if="doc" :doc="doc" :fields="fields" :autosave="true" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import frappe from 'frappejs';
|
||||||
|
import Button from '@/components/Button';
|
||||||
|
import TwoColumnForm from '@/components/TwoColumnForm';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'TabGeneral',
|
||||||
|
components: {
|
||||||
|
Button,
|
||||||
|
TwoColumnForm
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
doc: null
|
||||||
|
};
|
||||||
|
},
|
||||||
|
async mounted() {
|
||||||
|
this.doc = await frappe.getSingle('AccountingSettings');
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
fields() {
|
||||||
|
let meta = frappe.getMeta('AccountingSettings');
|
||||||
|
return [
|
||||||
|
'country',
|
||||||
|
'bankName',
|
||||||
|
'currency',
|
||||||
|
'fiscalYearStart',
|
||||||
|
'fiscalYearEnd'
|
||||||
|
].map(fieldname => meta.getField(fieldname));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
@ -109,6 +109,5 @@ const routes = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
let router = new Router({ routes });
|
let router = new Router({ routes });
|
||||||
router.replace('/list/Item');
|
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import frappe from 'frappejs';
|
import frappe from 'frappejs';
|
||||||
|
import { remote } from 'electron';
|
||||||
import { _ } from 'frappejs/utils';
|
import { _ } from 'frappejs/utils';
|
||||||
import DashboardIcon from './components/Icons/Dashboard';
|
import DashboardIcon from './components/Icons/Dashboard';
|
||||||
import SalesIcon from './components/Icons/Sales';
|
import SalesIcon from './components/Icons/Sales';
|
||||||
import PurchasesIcon from './components/Icons/Purchases';
|
import PurchasesIcon from './components/Icons/Purchases';
|
||||||
import ReportsIcon from './components/Icons/Reports';
|
import ReportsIcon from './components/Icons/Reports';
|
||||||
import SettingsIcon from './components/Icons/Settings';
|
import SettingsIcon from './components/Icons/Settings';
|
||||||
|
import theme from '@/theme';
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
getTitle: async () => {
|
getTitle: async () => {
|
||||||
@ -105,7 +107,18 @@ const config = {
|
|||||||
title: _('Settings'),
|
title: _('Settings'),
|
||||||
icon: SettingsIcon,
|
icon: SettingsIcon,
|
||||||
action() {
|
action() {
|
||||||
window.open('/index.html#/settings');
|
let child = new remote.BrowserWindow({
|
||||||
|
parent: remote.getCurrentWindow(),
|
||||||
|
frame: false,
|
||||||
|
width: 460,
|
||||||
|
height: 577,
|
||||||
|
backgroundColor: theme.backgroundColor.gray['200'],
|
||||||
|
webPreferences: {
|
||||||
|
webSecurity: false,
|
||||||
|
nodeIntegration: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
child.loadURL('http://localhost:8000/#/settings');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
4
src/theme.js
Normal file
4
src/theme.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import resolveConfig from 'tailwindcss/resolveConfig';
|
||||||
|
import tailwindConfig from '../tailwind.config';
|
||||||
|
|
||||||
|
export default resolveConfig(tailwindConfig).theme;
|
@ -40,7 +40,8 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
variants: {
|
variants: {
|
||||||
margin: ['responsive', 'first', 'hover', 'focus']
|
margin: ['responsive', 'first', 'hover', 'focus'],
|
||||||
|
backgroundColor: ['responsive', 'first', 'hover', 'focus', 'focus-within'],
|
||||||
},
|
},
|
||||||
plugins: []
|
plugins: []
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user