Skip to content

Commit

Permalink
feat: allow to create custom list views
Browse files Browse the repository at this point in the history
  • Loading branch information
mildred committed Nov 22, 2024
1 parent 22b78e8 commit 6e16a13
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 2 deletions.
22 changes: 22 additions & 0 deletions models/baseModels/SidebarEntry/SidebarEntry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Doc } from 'fyo/model/doc';
import type { QueryFilter } from 'utils/db/types';

export class SidebarEntry extends Doc {
section?: string;
route?: string;
model?: string;
filters?: string;

fullRoute(): string {
switch (this.route) {
case '/list':
return `/list/${this.model!}/${this.name!}`;
default:
return this.route!;
}
}

parsedFilters(): QueryFilter {
return JSON.parse(this.filters!) as QueryFilter;
}
}
2 changes: 2 additions & 0 deletions models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { SalesInvoiceItem } from './baseModels/SalesInvoiceItem/SalesInvoiceItem
import { SalesQuote } from './baseModels/SalesQuote/SalesQuote';
import { SalesQuoteItem } from './baseModels/SalesQuoteItem/SalesQuoteItem';
import { SetupWizard } from './baseModels/SetupWizard/SetupWizard';
import { SidebarEntry } from './baseModels/SidebarEntry/SidebarEntry';
import { Tax } from './baseModels/Tax/Tax';
import { TaxSummary } from './baseModels/TaxSummary/TaxSummary';
import { Batch } from './inventory/Batch';
Expand Down Expand Up @@ -83,6 +84,7 @@ export const models = {
SalesQuoteItem,
SerialNumber,
SetupWizard,
SidebarEntry,
PrintTemplate,
Tax,
TaxSummary,
Expand Down
1 change: 1 addition & 0 deletions models/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export enum ModelNameEnum {
LoyaltyPointEntry = 'LoyaltyPointEntry',
CollectionRulesItems = 'CollectionRulesItems',
CouponCode = 'CouponCode',
SidebarEntry = 'SidebarEntry',

AppliedCouponCodes = 'AppliedCouponCodes',
Payment = 'Payment',
Expand Down
46 changes: 46 additions & 0 deletions schemas/app/SidebarEntry.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"name": "SidebarEntry",
"label": "Sidebar Entry",
"naming": "manual",
"fields": [
{
"fieldname": "name",
"section": "Default",
"label": "Name",
"fieldtype": "Data",
"required": true,
"placeholder": "Entry Name"
},
{
"fieldname": "section",
"section": "Default",
"label": "Section",
"fieldtype": "Data",
"required": false
},
{
"fieldname": "route",
"section": "Default",
"label": "Route",
"fieldtype": "Data",
"required": true,
"default": "/list"
},
{
"fieldname": "model",
"section": "Default",
"label": "Document Type",
"fieldtype": "Data",
"required": true,
"default": "JournalEntry"
},
{
"fieldname": "filters",
"section": "Default",
"label": "Filters",
"fieldtype": "Data",
"required": true,
"default": "{}"
}
]
}
2 changes: 2 additions & 0 deletions schemas/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import PurchaseReceiptItem from './app/inventory/PurchaseReceiptItem.json';
import SerialNumber from './app/inventory/SerialNumber.json';
import Shipment from './app/inventory/Shipment.json';
import ShipmentItem from './app/inventory/ShipmentItem.json';
import SidebarEntry from './app/SidebarEntry.json';
import StockLedgerEntry from './app/inventory/StockLedgerEntry.json';
import StockMovement from './app/inventory/StockMovement.json';
import StockMovementItem from './app/inventory/StockMovementItem.json';
Expand Down Expand Up @@ -92,6 +93,7 @@ export const appSchemas: Schema[] | SchemaStub[] = [
SetupWizard as Schema,
GetStarted as Schema,
PrintTemplate as Schema,
SidebarEntry as Schema,

Color as Schema,
Currency as Schema,
Expand Down
12 changes: 12 additions & 0 deletions src/components/Sidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,15 @@ export default defineComponent({
});
this.shortcuts?.set(COMPONENT_NAME, ['F1'], () => this.openDocumentation());
fyo.doc.observer.on(
'sync:SidebarEntry',
async () => await this.refreshSidebar()
);
fyo.doc.observer.on(
'delete:SidebarEntry',
async () => await this.refreshSidebar()
);
this.showDevMode = this.fyo.store.isDevelopment;
},
unmounted() {
Expand All @@ -324,6 +333,9 @@ export default defineComponent({
routeTo,
reportIssue,
toggleSidebar,
async refreshSidebar() {
this.groups = await getSidebarConfig();
},
async toggleProvisionalMode() {
let title, detail, provisionalModeSince, showUnlimited;
if (fyo.singles.SystemSettings?.provisionalModeSince != null) {
Expand Down
22 changes: 22 additions & 0 deletions src/pages/ListView/ListView.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<template>
<div class="flex flex-col">
<PageHeader :title="title">
<Button ref="saveViewButton" :icon="false" @click="saveView">
{{ t`Save view` }}
</Button>
<Button ref="exportButton" :icon="false" @click="openExportModal = true">
{{ t`Export` }}
</Button>
Expand Down Expand Up @@ -44,6 +47,8 @@
</template>
<script lang="ts">
import { Field } from 'schemas/types';
import { ModelNameEnum } from 'models/types';
import { SidebarEntry } from 'models/baseModels/SidebarEntry/SidebarEntry';
import Button from 'src/components/Button.vue';
import ExportWizard from 'src/components/ExportWizard.vue';
import FilterDropdown from 'src/components/FilterDropdown.vue';
Expand Down Expand Up @@ -167,6 +172,23 @@ export default defineComponent({
applyFilter(filters: QueryFilter) {
this.list?.updateData(filters);
},
async saveView() {
const data = {
route: '/list',
model: this.schemaName,
filters: JSON.stringify(this.listFilters),
};
let entry = fyo.doc.getNewDoc(
ModelNameEnum.SidebarEntry,
data
) as SidebarEntry;
const { openQuickEdit } = await import('src/utils/ui');
await openQuickEdit({
doc: entry,
showFields: ['section'],
});
},
},
});
Expand Down
82 changes: 80 additions & 2 deletions src/utils/sidebarConfig.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { t } from 'fyo';
import { routeFilters } from 'src/utils/filters';
import { fyo } from '../initFyo';
import { SidebarEntry } from 'models/baseModels/SidebarEntry/SidebarEntry';
import { SidebarConfig, SidebarItem, SidebarRoot } from './types';

export function getSidebarConfig(): SidebarConfig {
const sideBar = getCompleteSidebar();
export async function getSidebarConfig(): SidebarConfig {
let sideBar: SidebarConfig = getCompleteSidebar();
sideBar = (await addCustomSidebarEntries(sideBar)) as SidebarConfig;
return getFilteredSidebar(sideBar);
}

Expand Down Expand Up @@ -341,6 +343,11 @@ function getCompleteSidebar(): SidebarConfig {
hidden: () =>
!fyo.singles.AccountingSettings?.enableFormCustomization,
},
{
label: t`Extra Sidebar Entries`,
name: 'sidebar-entries',
route: `/list/SidebarEntry`,
},
{
label: t`Settings`,
name: 'settings',
Expand All @@ -350,3 +357,74 @@ function getCompleteSidebar(): SidebarConfig {
},
].flat();
}

async function addCustomSidebarEntries(
sidebar: SidebarConfig
): Future<SidebarConfig> {
const entries = await fyo.db.getAll('SidebarEntry', {
fields: ['name', 'section', 'route'],
});

for (const [i, _ent] of Object.entries(entries)) {
if (_ent.section) continue;

const ent: SidebarEntry = (await fyo.doc.getDoc(
'SidebarEntry',
_ent.name
)) as SidebarEntry;

sidebar = [
{
label: ent.name!,
route: ent.fullRoute()! || `/list/JournalEntry/${ent.name!}`,
name: `section-${i}`,
icon: 'common-entries',
filters: ent.parsedFilters(),
items: [],
} as SidebarItem,
...sidebar,
];
}

for (const [i, _ent] of Object.entries(entries)) {
if (!_ent.section) continue;

const ent = (await fyo.doc.getDoc(
'SidebarEntry',
_ent.name
)) as SidebarEntry;

const item: SidebarItem = {
label: ent.name,
route: ent.fullRoute() || `/list/JournalEntry/${ent.name!}`,
filters: ent.parsedFilters(),
} as SidebarItem;

let inserted = false;
for (const section of sidebar) {
if (section.label == ent.section || section.name == ent.section) {
inserted = true;
item.name = `${section.name}-entry-${i}`;
section.items = [...section.items, item];
continue;
}
}

if (!inserted) {
item.name = `section-${i}-entry-${i}`;
sidebar = [
{
label: ent.section,
name: `section-${i}`,
icon: 'common-entries',
route: item.route,
filters: item.filters,
items: [item],
} as SidebarItem,
...sidebar,
];
}
}

return sidebar;
}

0 comments on commit 6e16a13

Please sign in to comment.