mirror of
https://github.com/frappe/books.git
synced 2025-01-03 15:17:30 +00:00
feat: add search modal
This commit is contained in:
parent
758727b296
commit
89983f24e2
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<button
|
<button
|
||||||
class="focus:outline-none rounded-md shadow-button flex-center"
|
class="focus:outline-none rounded-md shadow-button flex-center h-8"
|
||||||
:style="style"
|
:style="style"
|
||||||
:class="_class"
|
:class="_class"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
|
@ -1,14 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="absolute w-screen h-screen z-20 flex justify-center items-center"
|
class="
|
||||||
style="background: rgba(0, 0, 0, 0.25); backdrop-filter: blur(6px)"
|
fixed
|
||||||
|
top-0
|
||||||
|
left-0
|
||||||
|
w-screen
|
||||||
|
h-screen
|
||||||
|
z-20
|
||||||
|
flex
|
||||||
|
justify-center
|
||||||
|
items-center
|
||||||
|
"
|
||||||
|
style="background: rgba(0, 0, 0, 0.2); backdrop-filter: blur(4px)"
|
||||||
v-if="openModal"
|
v-if="openModal"
|
||||||
>
|
>
|
||||||
<div
|
<div class="bg-white rounded-lg shadow-2xl w-600" v-bind="$attrs">
|
||||||
class="bg-white rounded-lg shadow-2xl"
|
|
||||||
v-bind="$attrs"
|
|
||||||
style="width: 600px"
|
|
||||||
>
|
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<BackLink v-if="backLink" />
|
<BackLink v-if="backLink" />
|
||||||
<div class="flex items-stretch window-no-drag gap-2">
|
<div class="flex items-stretch window-no-drag gap-2">
|
||||||
<slot />
|
<slot />
|
||||||
<SearchBar v-show="!hideSearch" />
|
<SearchBar v-if="!hideSearch"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -2,82 +2,145 @@
|
|||||||
const keys = useKeys();
|
const keys = useKeys();
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div v-on-outside-click="clearInput" class="relative">
|
<div>
|
||||||
<Dropdown :items="suggestions" class="text-sm h-full">
|
<!-- Search Bar Button -->
|
||||||
<template
|
<button
|
||||||
v-slot="{
|
@click="open"
|
||||||
toggleDropdown,
|
class="
|
||||||
highlightItemUp,
|
focus:outline-none
|
||||||
highlightItemDown,
|
shadow-button
|
||||||
selectHighlightedItem,
|
flex flex-row
|
||||||
}"
|
gap-1
|
||||||
|
text-base text-gray-700
|
||||||
|
bg-gray-100
|
||||||
|
rounded-md
|
||||||
|
h-8
|
||||||
|
w-48
|
||||||
|
px-3
|
||||||
|
items-center
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<feather-icon name="search" class="w-4 h-4" />
|
||||||
|
<p>{{ t`Search` }}</p>
|
||||||
|
<div v-if="!inputValue" class="text-gray-500 ml-auto">
|
||||||
|
{{ platform === 'Mac' ? '⌘ K' : 'Ctrl K' }}
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Search Modal -->
|
||||||
|
<Modal :open-modal="openModal">
|
||||||
|
<!-- Search Input -->
|
||||||
|
<div class="p-1">
|
||||||
|
<input
|
||||||
|
ref="input"
|
||||||
|
type="search"
|
||||||
|
autocomplete="off"
|
||||||
|
spellcheck="false"
|
||||||
|
:placeholder="t`Type to search...`"
|
||||||
|
v-model="inputValue"
|
||||||
|
@focus="search"
|
||||||
|
@input="search"
|
||||||
|
@keydown.up="up"
|
||||||
|
@keydown.down="down"
|
||||||
|
@keydown.enter="() => select()"
|
||||||
|
@keydown.esc="close"
|
||||||
|
class="
|
||||||
|
bg-gray-100
|
||||||
|
text-2xl
|
||||||
|
focus:outline-none
|
||||||
|
w-full
|
||||||
|
placeholder-gray-700
|
||||||
|
text-gray-900
|
||||||
|
rounded-md
|
||||||
|
p-3
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<hr v-if="suggestions.length" />
|
||||||
|
|
||||||
|
<!-- Search List -->
|
||||||
|
<div :style="`max-height: ${49 * 6 - 1}px`" class="overflow-scroll">
|
||||||
|
<div
|
||||||
|
v-for="(si, i) in suggestions"
|
||||||
|
:key="`${i}-${si.key}`"
|
||||||
|
ref="suggestions"
|
||||||
|
class="hover:bg-blue-100 cursor-pointer"
|
||||||
|
:class="idx === i ? 'bg-blue-100' : ''"
|
||||||
|
@click="select(i)"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="rounded-md relative flex items-center overflow-hidden h-full"
|
class="flex flex-row w-full justify-between px-3 items-center"
|
||||||
|
style="height: 48px"
|
||||||
>
|
>
|
||||||
<div class="absolute flex justify-center w-8">
|
<p class="">
|
||||||
<feather-icon name="search" class="w-3 h-3 text-gray-800" />
|
{{ si.label }}
|
||||||
</div>
|
</p>
|
||||||
<input
|
|
||||||
type="search"
|
|
||||||
class="
|
|
||||||
bg-gray-100
|
|
||||||
text-sm
|
|
||||||
pl-7
|
|
||||||
focus:outline-none
|
|
||||||
h-full
|
|
||||||
w-56
|
|
||||||
placeholder-gray-800
|
|
||||||
"
|
|
||||||
:placeholder="t`Search...`"
|
|
||||||
autocomplete="off"
|
|
||||||
spellcheck="false"
|
|
||||||
v-model="inputValue"
|
|
||||||
@focus="
|
|
||||||
() => {
|
|
||||||
search();
|
|
||||||
toggleDropdown(true);
|
|
||||||
}
|
|
||||||
"
|
|
||||||
@input="search"
|
|
||||||
ref="input"
|
|
||||||
@keydown.up="highlightItemUp"
|
|
||||||
@keydown.down="highlightItemDown"
|
|
||||||
@keydown.enter="selectHighlightedItem"
|
|
||||||
@keydown.tab="toggleDropdown(false)"
|
|
||||||
@keydown.esc="toggleDropdown(false)"
|
|
||||||
/>
|
|
||||||
<div
|
<div
|
||||||
v-if="!inputValue"
|
class="text-base px-2 py-1 rounded-lg flex items-center"
|
||||||
class="absolute justify-center right-1.5 text-gray-500 px-1.5"
|
:class="groupColorClassMap[si.group]"
|
||||||
>
|
>
|
||||||
{{ platform === 'Mac' ? '⌘ K' : 'Ctrl K' }}
|
{{ groupLabelMap[si.group] }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
<hr v-if="i !== suggestions.length - 1" />
|
||||||
</Dropdown>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<hr />
|
||||||
|
<div class="m-2 flex justify-between items-center">
|
||||||
|
<!-- Group Filters -->
|
||||||
|
<div class="flex flex-row gap-2">
|
||||||
|
<button
|
||||||
|
v-for="g in searchGroups"
|
||||||
|
:key="g"
|
||||||
|
class="text-base border px-2 py-0.5 rounded-lg"
|
||||||
|
:class="getGroupFilterButtonClass(g)"
|
||||||
|
@click="groupFilters[g] = !groupFilters[g]"
|
||||||
|
>
|
||||||
|
{{ groupLabelMap[g] }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Keybindings Help -->
|
||||||
|
<div class="flex text-base gap-3 justify-center text-gray-700">
|
||||||
|
<p>↑↓ {{ t`Navigate` }}</p>
|
||||||
|
<p>↩ {{ t`Select` }}</p>
|
||||||
|
<p><span class="text-sm tracking-tighter">esc</span> {{ t`Close` }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { t } from 'fyo';
|
import { t } from 'fyo';
|
||||||
import Dropdown from 'src/components/Dropdown';
|
import { fuzzyMatch } from 'src/utils';
|
||||||
import { getSearchList } from 'src/utils/search';
|
import { getBgTextColorClass } from 'src/utils/colors';
|
||||||
|
import { getSearchList, searchGroups } from 'src/utils/search';
|
||||||
import { routeTo } from 'src/utils/ui';
|
import { routeTo } from 'src/utils/ui';
|
||||||
import { useKeys } from 'src/utils/vueUtils';
|
import { useKeys } from 'src/utils/vueUtils';
|
||||||
import { watch } from 'vue';
|
import { getIsNullOrUndef } from 'utils/';
|
||||||
|
import { nextTick, watch } from 'vue';
|
||||||
|
import Modal from './Modal.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
idx: 0,
|
||||||
|
searchGroups,
|
||||||
|
openModal: false,
|
||||||
inputValue: '',
|
inputValue: '',
|
||||||
searchList: [],
|
searchList: [],
|
||||||
suggestions: [],
|
groupFilters: {
|
||||||
|
List: true,
|
||||||
|
Report: true,
|
||||||
|
Create: true,
|
||||||
|
Page: true,
|
||||||
|
Docs: true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
components: {
|
components: { Modal },
|
||||||
Dropdown,
|
|
||||||
},
|
|
||||||
emits: ['change'],
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.makeSearchList();
|
this.makeSearchList();
|
||||||
watch(this.keys, (keys) => {
|
watch(this.keys, (keys) => {
|
||||||
@ -86,28 +149,63 @@ export default {
|
|||||||
keys.has('KeyK') &&
|
keys.has('KeyK') &&
|
||||||
(keys.has('MetaLeft') || keys.has('ControlLeft'))
|
(keys.has('MetaLeft') || keys.has('ControlLeft'))
|
||||||
) {
|
) {
|
||||||
this.$refs.input.focus();
|
this.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.openModal) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keys.size === 1 && keys.has('Escape')) {
|
if (keys.size === 1 && keys.has('Escape')) {
|
||||||
this.$refs.input.blur();
|
this.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
const input = this.$refs.input;
|
||||||
|
if (!getIsNullOrUndef(input) && document.activeElement !== input) {
|
||||||
|
input.focus();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
this.openModal = false;
|
||||||
|
},
|
||||||
|
activated() {
|
||||||
|
this.openModal = false;
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async search() {
|
open() {
|
||||||
this.suggestions = this.searchList.filter((d) => {
|
this.openModal = true;
|
||||||
let key = this.inputValue.toLowerCase();
|
nextTick(() => {
|
||||||
return d.label.toLowerCase().includes(key);
|
this.$refs.input.focus();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.suggestions.length === 0) {
|
|
||||||
this.suggestions = [{ label: t`No results found.` }];
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
clearInput() {
|
close() {
|
||||||
|
this.openModal = false;
|
||||||
|
this.reset();
|
||||||
|
},
|
||||||
|
reset() {
|
||||||
|
this.searchGroups.forEach((g) => {
|
||||||
|
this.groupFilters[g] = true;
|
||||||
|
});
|
||||||
this.inputValue = '';
|
this.inputValue = '';
|
||||||
this.$emit('change', null);
|
},
|
||||||
|
up() {
|
||||||
|
this.idx = Math.max(this.idx - 1, 0);
|
||||||
|
this.scrollToHighlighted();
|
||||||
|
},
|
||||||
|
down() {
|
||||||
|
this.idx = Math.max(
|
||||||
|
Math.min(this.idx + 1, this.suggestions.length - 1),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
this.scrollToHighlighted();
|
||||||
|
},
|
||||||
|
select(idx) {
|
||||||
|
this.idx = idx ?? this.idx;
|
||||||
|
this.suggestions[this.idx]?.action();
|
||||||
|
this.close();
|
||||||
|
},
|
||||||
|
scrollToHighlighted() {
|
||||||
|
const ref = this.$refs.suggestions[this.idx];
|
||||||
|
ref.scrollIntoView({ block: 'nearest' });
|
||||||
},
|
},
|
||||||
async makeSearchList() {
|
async makeSearchList() {
|
||||||
const searchList = getSearchList();
|
const searchList = getSearchList();
|
||||||
@ -115,12 +213,61 @@ export default {
|
|||||||
if (d.route && !d.action) {
|
if (d.route && !d.action) {
|
||||||
d.action = () => {
|
d.action = () => {
|
||||||
routeTo(d.route);
|
routeTo(d.route);
|
||||||
this.inputValue = '';
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return d;
|
return d;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
getGroupFilterButtonClass(g) {
|
||||||
|
const isOn = this.groupFilters[g];
|
||||||
|
const color = this.groupColorMap[g];
|
||||||
|
if (isOn) {
|
||||||
|
return `${getBgTextColorClass(color)} border-${color}-100`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `text-${color}-600 border-${color}-100`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
groupLabelMap() {
|
||||||
|
return {
|
||||||
|
Create: t`Create`,
|
||||||
|
List: t`List`,
|
||||||
|
Report: t`Report`,
|
||||||
|
Docs: t`Docs`,
|
||||||
|
Page: t`Page`,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
groupColorMap() {
|
||||||
|
return {
|
||||||
|
Docs: 'blue',
|
||||||
|
Create: 'green',
|
||||||
|
List: 'teal',
|
||||||
|
Report: 'yellow',
|
||||||
|
Page: 'orange',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
groupColorClassMap() {
|
||||||
|
return searchGroups.reduce((map, g) => {
|
||||||
|
map[g] = getBgTextColorClass(this.groupColorMap[g]);
|
||||||
|
return map;
|
||||||
|
}, {});
|
||||||
|
},
|
||||||
|
suggestions() {
|
||||||
|
const filters = new Set(
|
||||||
|
this.searchGroups.filter((g) => this.groupFilters[g])
|
||||||
|
);
|
||||||
|
|
||||||
|
return this.searchList
|
||||||
|
.filter((si) => filters.has(si.group))
|
||||||
|
.map((si) => ({
|
||||||
|
...fuzzyMatch(this.inputValue, `${si.label} ${si.group}`),
|
||||||
|
si,
|
||||||
|
}))
|
||||||
|
.filter(({ isMatch }) => isMatch)
|
||||||
|
.sort((a, b) => a.distance - b.distance)
|
||||||
|
.map(({ si }) => si);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -6,7 +6,13 @@
|
|||||||
@change="applyFilter"
|
@change="applyFilter"
|
||||||
:fields="fields"
|
:fields="fields"
|
||||||
/>
|
/>
|
||||||
<Button :icon="true" type="primary" @click="makeNewDoc">
|
<Button
|
||||||
|
:icon="true"
|
||||||
|
type="primary"
|
||||||
|
@click="makeNewDoc"
|
||||||
|
:padding="false"
|
||||||
|
class="px-3"
|
||||||
|
>
|
||||||
<feather-icon name="plus" class="w-4 h-4 text-white" />
|
<feather-icon name="plus" class="w-4 h-4 text-white" />
|
||||||
</Button>
|
</Button>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
@ -21,9 +27,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import Button from 'src/components/Button';
|
import Button from 'src/components/Button.vue';
|
||||||
import FilterDropdown from 'src/components/FilterDropdown';
|
import FilterDropdown from 'src/components/FilterDropdown.vue';
|
||||||
import PageHeader from 'src/components/PageHeader';
|
import PageHeader from 'src/components/PageHeader.vue';
|
||||||
import { fyo } from 'src/initFyo';
|
import { fyo } from 'src/initFyo';
|
||||||
import { routeTo } from 'src/utils/ui';
|
import { routeTo } from 'src/utils/ui';
|
||||||
import List from './List';
|
import List from './List';
|
||||||
|
@ -36,7 +36,6 @@ import { setLanguageMap } from './utils/language';
|
|||||||
app.component('App', App);
|
app.component('App', App);
|
||||||
app.component('FeatherIcon', FeatherIcon);
|
app.component('FeatherIcon', FeatherIcon);
|
||||||
app.component('Badge', Badge);
|
app.component('Badge', Badge);
|
||||||
|
|
||||||
app.directive('on-outside-click', outsideClickDirective);
|
app.directive('on-outside-click', outsideClickDirective);
|
||||||
app.mixin({
|
app.mixin({
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -108,7 +108,7 @@ const routes: RouteRecordRaw[] = [
|
|||||||
},
|
},
|
||||||
/*
|
/*
|
||||||
{
|
{
|
||||||
path: '/data_import',
|
path: '/data-import',
|
||||||
name: 'Data Import',
|
name: 'Data Import',
|
||||||
component: DataImport,
|
component: DataImport,
|
||||||
},
|
},
|
||||||
|
@ -18,9 +18,18 @@ export const statusColor = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getValidColor = (color: string) => {
|
const getValidColor = (color: string) => {
|
||||||
const isValid = ['gray', 'orange', 'green', 'red', 'yellow', 'blue'].includes(
|
const isValid = [
|
||||||
color
|
'gray',
|
||||||
);
|
'orange',
|
||||||
|
'green',
|
||||||
|
'red',
|
||||||
|
'yellow',
|
||||||
|
'blue',
|
||||||
|
'indigo',
|
||||||
|
'pink',
|
||||||
|
'purple',
|
||||||
|
'teal',
|
||||||
|
].includes(color);
|
||||||
return isValid ? color : 'gray';
|
return isValid ? color : 'gray';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4,11 +4,13 @@ import reports from 'reports/view';
|
|||||||
import { fyo } from 'src/initFyo';
|
import { fyo } from 'src/initFyo';
|
||||||
import { routeTo } from './ui';
|
import { routeTo } from './ui';
|
||||||
|
|
||||||
|
export const searchGroups = ['Docs', 'List', 'Create', 'Report', 'Page'];
|
||||||
enum SearchGroupEnum {
|
enum SearchGroupEnum {
|
||||||
'List' = 'List',
|
'List' = 'List',
|
||||||
'Report' = 'Report',
|
'Report' = 'Report',
|
||||||
'Create' = 'Create',
|
'Create' = 'Create',
|
||||||
'Setup' = 'Setup',
|
'Page' = 'Page',
|
||||||
|
'Docs' = 'Docs',
|
||||||
}
|
}
|
||||||
|
|
||||||
type SearchGroup = keyof typeof SearchGroupEnum;
|
type SearchGroup = keyof typeof SearchGroupEnum;
|
||||||
@ -38,50 +40,37 @@ async function openFormEditDoc(schemaName: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getCreateList(): SearchItem[] {
|
function getCreateList(): SearchItem[] {
|
||||||
return [
|
const quickEditCreateList = [
|
||||||
{
|
ModelNameEnum.Item,
|
||||||
label: t`Create Item`,
|
ModelNameEnum.Party,
|
||||||
group: 'Create',
|
ModelNameEnum.Payment,
|
||||||
action() {
|
].map(
|
||||||
openQuickEditDoc(ModelNameEnum.Item);
|
(schemaName) =>
|
||||||
},
|
({
|
||||||
},
|
label: fyo.schemaMap[schemaName]?.label,
|
||||||
{
|
group: 'Create',
|
||||||
label: t`Create Party`,
|
action() {
|
||||||
group: 'Create',
|
openQuickEditDoc(schemaName);
|
||||||
action() {
|
},
|
||||||
openQuickEditDoc(ModelNameEnum.Party);
|
} as SearchItem)
|
||||||
},
|
);
|
||||||
},
|
|
||||||
{
|
const formEditCreateList = [
|
||||||
label: t`Create Payment`,
|
ModelNameEnum.SalesInvoice,
|
||||||
group: 'Create',
|
ModelNameEnum.PurchaseInvoice,
|
||||||
action() {
|
ModelNameEnum.JournalEntry,
|
||||||
openQuickEditDoc(ModelNameEnum.Payment);
|
].map(
|
||||||
},
|
(schemaName) =>
|
||||||
},
|
({
|
||||||
{
|
label: fyo.schemaMap[schemaName]?.label,
|
||||||
label: t`Create Sales Invoice`,
|
group: 'Create',
|
||||||
group: 'Create',
|
action() {
|
||||||
action() {
|
openFormEditDoc(schemaName);
|
||||||
openFormEditDoc(ModelNameEnum.SalesInvoice);
|
},
|
||||||
},
|
} as SearchItem)
|
||||||
},
|
);
|
||||||
{
|
|
||||||
label: t`Create Purchase Invoice`,
|
return [quickEditCreateList, formEditCreateList].flat();
|
||||||
group: 'Create',
|
|
||||||
action() {
|
|
||||||
openFormEditDoc(ModelNameEnum.PurchaseInvoice);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t`Create Journal Entry`,
|
|
||||||
group: 'Create',
|
|
||||||
action() {
|
|
||||||
openFormEditDoc(ModelNameEnum.JournalEntry);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getReportList(): SearchItem[] {
|
function getReportList(): SearchItem[] {
|
||||||
@ -116,36 +105,34 @@ function getListViewList(): SearchItem[] {
|
|||||||
|
|
||||||
function getSetupList(): SearchItem[] {
|
function getSetupList(): SearchItem[] {
|
||||||
return [
|
return [
|
||||||
|
{
|
||||||
|
label: t`Dashboard`,
|
||||||
|
route: '/',
|
||||||
|
group: 'Page',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: t`Chart of Accounts`,
|
label: t`Chart of Accounts`,
|
||||||
route: '/chartOfAccounts',
|
route: '/chart-of-accounts',
|
||||||
group: 'Setup',
|
group: 'Page',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t`Data Import`,
|
label: t`Data Import`,
|
||||||
route: '/data_import',
|
route: '/data-import',
|
||||||
group: 'Setup',
|
group: 'Page',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t`Settings`,
|
label: t`Settings`,
|
||||||
route: '/settings',
|
route: '/settings',
|
||||||
group: 'Setup',
|
group: 'Page',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getSearchList() {
|
export function getSearchList() {
|
||||||
const group: Record<SearchGroup, string> = {
|
return [
|
||||||
Create: t`Create`,
|
getListViewList(),
|
||||||
List: t`List`,
|
getCreateList(),
|
||||||
Report: t`Report`,
|
getReportList(),
|
||||||
Setup: t`Setup`,
|
getSetupList(),
|
||||||
};
|
].flat();
|
||||||
|
|
||||||
return [getListViewList(), getCreateList(), getReportList(), getSetupList()]
|
|
||||||
.flat()
|
|
||||||
.map((si) => ({
|
|
||||||
...si,
|
|
||||||
group: group[si.group],
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user