2
0
mirror of https://github.com/frappe/books.git synced 2024-12-23 11:29:03 +00:00

incr: status badge and action buttons

This commit is contained in:
18alantom 2023-02-20 10:22:19 +05:30
parent 7cfd0726d6
commit 01e197f439
5 changed files with 135 additions and 58 deletions

View File

@ -56,7 +56,7 @@
<script lang="ts">
import { Money } from 'pesa';
import { getCreateRoute } from 'src/router';
import { getStatus, routeTo } from 'src/utils/ui';
import { routeTo } from 'src/utils/ui';
import { defineComponent, PropType } from 'vue';
import Button from '../Button.vue';
import StatusBadge from '../StatusBadge.vue';
@ -78,7 +78,17 @@ export default defineComponent({
linked: { type: Object as PropType<Linked>, required: true },
},
methods: {
getStatus,
getStatus(entry: { cancelled?: boolean; submitted?: boolean }) {
if (entry.cancelled) {
return 'Cancelled';
}
if (entry.submitted) {
return 'Submitted';
}
return 'Saved';
},
async openEntry(name: string) {
const route = getCreateRoute(this.linked.schemaName, name);
await routeTo(route);

View File

@ -1,11 +1,35 @@
<template>
<FormContainer>
<template #header v-if="hasDoc">
<StatusBadge :status="status" />
<DropdownWithActions
v-for="group of groupedActions"
:key="group.label"
:type="group.type"
:actions="group.actions"
>
<p v-if="group.group">
{{ group.group }}
</p>
<feather-icon v-else name="more-horizontal" class="w-4 h-4" />
</DropdownWithActions>
<Button v-if="doc?.canSave" type="primary" @click="() => doc.sync()">
{{ t`Save` }}
</Button>
<Button
v-else-if="doc?.canSubmit"
type="primary"
@click="() => doc.submit()"
>{{ t`Submit` }}</Button
>
</template>
<template #body>
<FormHeader
:form-title="title"
:form-sub-title="schema.label"
class="sticky top-0 bg-white border-b"
/>
>
</FormHeader>
<!-- Section Container -->
<div v-if="hasDoc" class="overflow-auto custom-scroll">
@ -61,20 +85,34 @@
<script lang="ts">
import { Doc } from 'fyo/model/doc';
import { ValidationError } from 'fyo/utils/errors';
import { getDocStatus } from 'models/helpers';
import { ModelNameEnum } from 'models/types';
import { Field, Schema } from 'schemas/types';
import Button from 'src/components/Button.vue';
import DropdownWithActions from 'src/components/DropdownWithActions.vue';
import FormContainer from 'src/components/FormContainer.vue';
import FormHeader from 'src/components/FormHeader.vue';
import { defineComponent } from 'vue';
import StatusBadge from 'src/components/StatusBadge.vue';
import { ActionGroup, UIGroupedFields } from 'src/utils/types';
import {
getFieldsGroupedByTabAndSection,
getGroupedActionsForDoc,
} from 'src/utils/ui';
import { computed, defineComponent } from 'vue';
import CommonFormSection from './CommonFormSection.vue';
type UIGroupedFields = Map<string, Map<string, Field[]>>;
export default defineComponent({
props: {
name: { type: String, default: 'PAY-1008' },
schemaName: { type: String, default: ModelNameEnum.Payment },
},
provide() {
return {
schemaName: computed(() => this.docOrNull?.schemaName),
name: computed(() => this.docOrNull?.name),
doc: computed(() => this.docOrNull),
};
},
data() {
return {
docOrNull: null,
@ -82,19 +120,24 @@ export default defineComponent({
} as { docOrNull: null | Doc; activeTab: string };
},
async mounted() {
if (this.name && !this.docOrNull) {
this.docOrNull = await this.fyo.doc.getDoc(this.schemaName, this.name);
}
if (this.fyo.store.isDevelopment) {
// @ts-ignore
window.cf = this;
}
await this.setDoc();
},
computed: {
hasDoc(): boolean {
return !!this.docOrNull;
},
status(): string {
if (!this.hasDoc) {
return '';
}
return getDocStatus(this.doc);
},
doc(): Doc {
const doc = this.docOrNull as Doc | null;
if (!doc) {
@ -105,9 +148,10 @@ export default defineComponent({
return doc;
},
title(): string {
if (this.schema.isSubmittable && !this.docOrNull?.notInserted) {
if (this.schema.isSubmittable && this.docOrNull?.notInserted) {
return this.t`New Entry`;
}
return this.docOrNull?.name!;
},
schema(): Schema {
@ -131,27 +175,34 @@ export default defineComponent({
allGroups(): UIGroupedFields {
return getFieldsGroupedByTabAndSection(this.schema);
},
groupedActions(): ActionGroup[] {
if (!this.hasDoc) {
return [];
}
return getGroupedActionsForDoc(this.doc);
},
},
methods: {
async setDoc() {
if (this.hasDoc) {
return;
}
if (this.name) {
this.docOrNull = await this.fyo.doc.getDoc(this.schemaName, this.name);
} else {
this.docOrNull = this.fyo.doc.getNewDoc(this.schemaName);
}
},
},
components: {
FormContainer,
FormHeader,
CommonFormSection,
StatusBadge,
Button,
DropdownWithActions,
},
components: { FormContainer, FormHeader, CommonFormSection },
});
function getFieldsGroupedByTabAndSection(schema: Schema): UIGroupedFields {
const grouped: UIGroupedFields = new Map();
for (const field of schema?.fields ?? []) {
const tab = field.tab ?? 'Default';
const section = field.section ?? 'Default';
if (!grouped.has(tab)) {
grouped.set(tab, new Map());
}
const tabbed = grouped.get(tab)!;
if (!tabbed.has(section)) {
tabbed.set(section, []);
}
tabbed.get(section)!.push(field);
}
return grouped;
}
</script>

View File

@ -1,5 +1,5 @@
<template>
<div>
<div v-if="filteredFields.length > 0">
<div
v-if="showTitle && title"
class="flex justify-between items-center cursor-pointer select-none"
@ -48,7 +48,9 @@ export default defineComponent({
},
computed: {
filteredFields(): Field[] {
return (this.fields ?? []).filter((f) => !evaluateHidden(f, this.doc));
return (this.fields ?? []).filter(
(f) => !evaluateHidden(f, this.doc) && !f.meta
);
},
},
components: { FormControl },

View File

@ -1,6 +1,7 @@
import { Doc } from "fyo/model/doc";
import { FieldType } from "schemas/types";
import { QueryFilter } from "utils/db/types";
import type { Doc } from 'fyo/model/doc';
import type { Action } from 'fyo/model/types';
import type { Field, FieldType } from 'schemas/types';
import type { QueryFilter } from 'utils/db/types';
export interface MessageDialogButton {
label: string;
@ -31,7 +32,7 @@ export interface QuickEditOptions {
hideFields?: string[];
showFields?: string[];
defaults?: Record<string, unknown>;
listFilters?: QueryFilter
listFilters?: QueryFilter;
}
export type SidebarConfig = SidebarRoot[];
@ -44,7 +45,7 @@ export interface SidebarRoot {
iconHeight?: string;
hidden?: () => boolean;
items?: SidebarItem[];
filters?: QueryFilter
filters?: QueryFilter;
}
export interface SidebarItem {
@ -55,7 +56,6 @@ export interface SidebarItem {
hidden?: () => boolean;
}
export interface ExportField {
fieldname: string;
fieldtype: FieldType;
@ -70,5 +70,13 @@ export interface ExportTableField {
fields: ExportField[];
}
export type ActionGroup = {
group: string;
label: string;
type: string;
actions: Action[];
};
export type UIGroupedFields = Map<string, Map<string, Field[]>>;
export type ExportFormat = 'csv' | 'json';
export type PeriodKey = 'This Year' | 'This Quarter' | 'This Month'
export type PeriodKey = 'This Year' | 'This Quarter' | 'This Month';

View File

@ -9,6 +9,7 @@ import { Action } from 'fyo/model/types';
import { getActions } from 'fyo/utils';
import { getDbError, LinkValidationError, ValueError } from 'fyo/utils/errors';
import { ModelNameEnum } from 'models/types';
import { Schema } from 'schemas/types';
import { handleErrorWithDialog } from 'src/errorHandling';
import { fyo } from 'src/initFyo';
import router from 'src/router';
@ -17,10 +18,12 @@ import { App, createApp, h, ref } from 'vue';
import { RouteLocationRaw } from 'vue-router';
import { stringifyCircular } from './';
import {
ActionGroup,
MessageDialogOptions,
QuickEditOptions,
SettingsTab,
ToastOptions,
UIGroupedFields,
} from './types';
export async function openQuickEdit({
@ -274,14 +277,7 @@ export function getActionsForDoc(doc?: Doc): Action[] {
});
}
export function getGroupedActionsForDoc(doc?: Doc) {
type Group = {
group: string;
label: string;
type: string;
actions: Action[];
};
export function getGroupedActionsForDoc(doc?: Doc): ActionGroup[] {
const actions = getActionsForDoc(doc);
const actionsMap = actions.reduce((acc, ac) => {
if (!ac.group) {
@ -297,7 +293,7 @@ export function getGroupedActionsForDoc(doc?: Doc) {
acc[ac.group].actions.push(ac);
return acc;
}, {} as Record<string, Group>);
}, {} as Record<string, ActionGroup>);
const grouped = Object.keys(actionsMap)
.filter(Boolean)
@ -393,14 +389,24 @@ function getDuplicateAction(doc: Doc): Action {
};
}
export function getStatus(entry: { cancelled?: boolean; submitted?: boolean }) {
if (entry.cancelled) {
return 'Cancelled';
export function getFieldsGroupedByTabAndSection(
schema: Schema
): UIGroupedFields {
const grouped: UIGroupedFields = new Map();
for (const field of schema?.fields ?? []) {
const tab = field.tab ?? 'Default';
const section = field.section ?? 'Default';
if (!grouped.has(tab)) {
grouped.set(tab, new Map());
}
if (entry.submitted) {
return 'Submitted';
const tabbed = grouped.get(tab)!;
if (!tabbed.has(section)) {
tabbed.set(section, []);
}
return 'Saved';
tabbed.get(section)!.push(field);
}
return grouped;
}