From aa73a33669cea89f00cf4951c7d974d1893474a0 Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Tue, 24 May 2022 00:02:28 +0530 Subject: [PATCH] incr: add docs to search - still incomplete, lotsa improvements left --- reports/index.ts | 3 +- src/components/SearchBar.vue | 75 +++++++++++++++++++-------- src/renderer.ts | 3 ++ src/utils/search.ts | 99 ++++++++++++++++++++++++++++++------ 4 files changed, 143 insertions(+), 37 deletions(-) diff --git a/reports/index.ts b/reports/index.ts index c65e4657..562fcd90 100644 --- a/reports/index.ts +++ b/reports/index.ts @@ -3,6 +3,7 @@ import { GeneralLedger } from './GeneralLedger/GeneralLedger'; import { GSTR1 } from './GoodsAndServiceTax/GSTR1'; import { GSTR2 } from './GoodsAndServiceTax/GSTR2'; import { ProfitAndLoss } from './ProfitAndLoss/ProfitAndLoss'; +import { Report } from './Report'; import { TrialBalance } from './TrialBalance/TrialBalance'; export const reports = { @@ -12,4 +13,4 @@ export const reports = { TrialBalance, GSTR1, GSTR2, -}; +} as Record; diff --git a/src/components/SearchBar.vue b/src/components/SearchBar.vue index 9b81117c..0e59a082 100644 --- a/src/components/SearchBar.vue +++ b/src/components/SearchBar.vue @@ -90,30 +90,49 @@ const keys = useKeys();
-
+
-
- +
+
-
-

↑↓ {{ t`Navigate` }}

-

↩ {{ t`Select` }}

-

esc {{ t`Close` }}

+
+
+

↑↓ {{ t`Navigate` }}

+

↩ {{ t`Select` }}

+

esc {{ t`Close` }}

+
+

+ {{ t`${suggestions.length} out of ${totalLength} shown` }} +

@@ -122,7 +141,7 @@ const keys = useKeys(); import { t } from 'fyo'; import { fuzzyMatch } from 'src/utils'; import { getBgTextColorClass } from 'src/utils/colors'; -import { getSearchList, searchGroups } from 'src/utils/search'; +import { docSearch, getSearchList, searchGroups } from 'src/utils/search'; import { routeTo } from 'src/utils/ui'; import { useKeys } from 'src/utils/vueUtils'; import { getIsNullOrUndef } from 'utils/'; @@ -137,6 +156,8 @@ export default { openModal: false, inputValue: '', searchList: [], + docSearch: null, + totalLength: 0, groupFilters: { List: true, Report: true, @@ -147,7 +168,10 @@ export default { }; }, components: { Modal }, - mounted() { + async mounted() { + this.docSearch = docSearch; + await this.docSearch.fetchKeywords(); + this.makeSearchList(); watch(this.keys, (keys) => { if ( @@ -297,7 +321,7 @@ export default { this.searchGroups.filter((g) => this.groupFilters[g]) ); - return this.searchList + const nonDocs = this.searchList .filter((si) => filters.has(si.group)) .map((si) => ({ ...fuzzyMatch(this.inputValue, `${si.label} ${si.group}`), @@ -306,6 +330,15 @@ export default { .filter(({ isMatch }) => isMatch) .sort((a, b) => a.distance - b.distance) .map(({ si }) => si); + + let docs = []; + if (this.groupFilters.Docs && this.inputValue) { + docs = this.docSearch.search(this.inputValue); + } + + const all = [docs, nonDocs].flat(); + this.totalLength = all.length; + return all.slice(0, 50); }, }, }; diff --git a/src/renderer.ts b/src/renderer.ts index bfd1d816..1b3404e5 100644 --- a/src/renderer.ts +++ b/src/renderer.ts @@ -1,5 +1,6 @@ import { ipcRenderer } from 'electron'; import { ConfigKeys } from 'fyo/core/types'; +import { groupBy } from 'lodash'; import { DateTime } from 'luxon'; import { IPC_ACTIONS } from 'utils/messages'; import { App as VueApp, createApp } from 'vue'; @@ -105,5 +106,7 @@ function setOnWindow() { window.fyo = fyo; // @ts-ignore window.DateTime = DateTime; + // @ts-ignore + window.groupBy = groupBy; } } diff --git a/src/utils/search.ts b/src/utils/search.ts index cf9fb875..3a8deb2e 100644 --- a/src/utils/search.ts +++ b/src/utils/search.ts @@ -1,9 +1,12 @@ import { t } from 'fyo'; import { DocValueMap } from 'fyo/core/types'; +import { Dictionary, groupBy } from 'lodash'; import { ModelNameEnum } from 'models/types'; +import { reports } from 'reports'; import { OptionField } from 'schemas/types'; import { fyo } from 'src/initFyo'; import { GetAllOptions } from 'utils/db/types'; +import { fuzzyMatch } from '.'; import { routeTo } from './ui'; export const searchGroups = ['Docs', 'List', 'Create', 'Report', 'Page']; @@ -23,6 +26,11 @@ interface SearchItem { action?: () => void; } +interface DocSearchItem extends SearchItem { + schemaLabel: string; + more: string[]; +} + async function openQuickEditDoc(schemaName: string) { await routeTo(`/list/${schemaName}`); const doc = await fyo.doc.getNewDoc(schemaName); @@ -122,15 +130,23 @@ function getCreateList(): SearchItem[] { } function getReportList(): SearchItem[] { - /*return Object.values(reports).map((report) => { - return { - label: report.title, - route: `/report/${report.method}`, - group: 'Report', - }; - }); - */ - return []; + const hasGstin = !!fyo.singles?.AccountingSettings?.gstin; + return Object.keys(reports) + .filter((r) => { + const report = reports[r]; + if (report.title.startsWith('GST') && !hasGstin) { + return false; + } + return true; + }) + .map((r) => { + const report = reports[r]; + return { + label: report.title, + route: `/report/${r}`, + group: 'Report', + }; + }); } function getListViewList(): SearchItem[] { @@ -251,13 +267,62 @@ class Search { [ModelNameEnum.JournalEntry]: 50, }; + #groupedKeywords?: Dictionary; + constructor() { this.keywords = {}; } - getSearchList() { + get groupedKeywords() { + if (!this.#groupedKeywords || !Object.keys(this.#groupedKeywords!).length) { + this.#groupedKeywords = this.getGroupedKeywords(); + } + + return this.#groupedKeywords!; + } + + search(keyword: string /*, array: DocSearchItem[]*/): DocSearchItem[] { + const array: DocSearchItem[] = []; + if (!keyword) { + return []; + } + + const groupedKeywords = this.groupedKeywords; + const keys = Object.keys(groupedKeywords).sort( + (a, b) => parseFloat(b) - parseFloat(a) + ); + + for (const key of keys) { + for (const kw of groupedKeywords[key]) { + let isMatch = false; + for (const word of kw.values) { + isMatch ||= fuzzyMatch(keyword, word).isMatch; + if (isMatch) { + break; + } + } + + if (!isMatch) { + continue; + } + + array.push({ + label: kw.values[0], + schemaLabel: fyo.schemaMap[kw.meta.schemaName as string]?.label!, + more: kw.values.slice(1), + group: 'Docs', + action: () => { + console.log('selected', kw); + }, + }); + } + } + return array; + } + + getGroupedKeywords() { const keywords = Object.values(this.keywords); - return keywords.map((kw) => kw.keywords).flat(); + return groupBy(keywords.map((kw) => kw.keywords).flat(), 'priority'); } async fetchKeywords() { @@ -273,7 +338,7 @@ class Search { } const maps = await fyo.db.getAllRaw(searchable.schemaName, options); - this.addToSearchable(maps, searchable); + this.#addToSearchable(maps, searchable); } this.#setPriority(); @@ -332,7 +397,7 @@ class Search { } } - addToSearchable(maps: DocValueMap[], searchable: Searchable) { + #addToSearchable(maps: DocValueMap[], searchable: Searchable) { if (!maps.length) { return; } @@ -376,5 +441,9 @@ class Search { } } -//@ts-ignore -window.sc = new Search(); +export const docSearch = new Search(); + +if (fyo.store.isDevelopment) { + //@ts-ignore + window.search = docSearch; +}