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

Merge pull request #466 from 18alantom/fix-fields-ui

fix: fields UI/UX
This commit is contained in:
Alan 2022-09-19 04:25:10 -07:00 committed by GitHub
commit 9592ec4bc7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 281 additions and 232 deletions

View File

@ -1,15 +1,11 @@
<template>
<div
class="
relative
bg-white
border
rounded-full
flex-center
overflow-hidden
cursor-pointer
"
:class="{ 'w-20 h-20': size !== 'small', 'w-12 h-12': size === 'small' }"
class="relative bg-white border rounded-full flex-center overflow-hidden"
:class="{
'w-20 h-20': size !== 'small',
'w-12 h-12': size === 'small',
'cursor-pointer': !isReadOnly,
}"
@mouseover="showEdit = true"
@mouseleave="showEdit = false"
@click="openFileSelector"
@ -48,9 +44,16 @@
</div>
<div
v-show="showEdit"
class="absolute bottom-0 text-gray-500 text-center text-xs pt-3 pb-1"
class="
absolute
bottom-0
text-gray-500 text-center text-xs
pt-3
pb-1
select-none
"
>
{{ t`Edit` }}
{{ !isReadOnly ? t`Edit` : '' }}
</div>
</div>
</template>
@ -72,6 +75,10 @@ export default {
},
methods: {
async openFileSelector() {
if (this.isReadOnly) {
return;
}
const options = {
title: fyo.t`Select Image`,
properties: ['openFile'],

View File

@ -8,17 +8,18 @@
selectHighlightedItem,
}"
>
<div class="text-gray-600 text-sm mb-1" v-if="showLabel">
<div :class="labelClasses" v-if="showLabel">
{{ df.label }}
</div>
<div
class="flex items-center justify-between pr-2 rounded"
:class="isReadOnly ? '' : 'focus-within:bg-gray-200'"
:class="containerClasses"
>
<input
ref="input"
spellcheck="false"
:class="inputClasses"
class="bg-transparent"
type="text"
:value="linkValue"
:placeholder="inputPlaceholder"
@ -38,10 +39,12 @@
style="background: inherit; margin-right: -3px"
viewBox="0 0 5 10"
xmlns="http://www.w3.org/2000/svg"
@click="(e) => !isReadOnly && onFocus(e, toggleDropdown)"
>
<path
d="M1 2.636L2.636 1l1.637 1.636M1 7.364L2.636 9l1.637-1.636"
stroke="#404040"
class="stroke-current"
:class="showMandatory ? 'text-red-500' : 'text-gray-500'"
fill="none"
fill-rule="evenodd"
stroke-linecap="round"

View File

@ -1,12 +1,14 @@
<template>
<div>
<div class="text-gray-600 text-sm mb-1" v-if="showLabel">
<div :class="labelClasses" v-if="showLabel">
{{ df.label }}
</div>
<div :class="showMandatory ? 'show-mandatory' : ''">
<input
spellcheck="false"
ref="input"
:class="inputClasses"
class="bg-transparent"
:class="[inputClasses, containerClasses]"
:type="inputType"
:value="value"
:placeholder="inputPlaceholder"
@ -18,10 +20,13 @@
@input="(e) => !isReadOnly && $emit('input', e)"
/>
</div>
</div>
</template>
<script>
import { isNumeric } from 'src/utils';
import { evaluateReadOnly, evaluateRequired } from 'src/utils/doc';
import { getIsNullOrUndef } from 'utils/index';
export default {
name: 'Base',
@ -29,11 +34,13 @@ export default {
df: Object,
value: [String, Number, Boolean, Object],
inputClass: [Function, String, Object],
border: { type: Boolean, default: false },
placeholder: String,
size: String,
showLabel: Boolean,
readOnly: Boolean,
autofocus: Boolean,
readOnly: { type: [null, Boolean], default: null },
required: { type: [null, Boolean], default: null },
},
emits: ['focus', 'input', 'change'],
inject: {
@ -56,28 +63,89 @@ export default {
inputType() {
return 'text';
},
inputClasses() {
let classes = [
{
'px-3 py-2': this.size !== 'small',
'px-2 py-1': this.size === 'small',
labelClasses() {
return 'text-gray-600 text-sm mb-1';
},
'focus:outline-none rounded w-full placeholder-gray-500',
this.isReadOnly
? 'text-gray-800 focus:bg-transparent'
: 'text-gray-900 focus:bg-gray-200',
inputClasses() {
/**
* These classes will be used by components that extend Base
*/
const classes = [
'text-base',
'focus:outline-none',
'w-full',
'placeholder-gray-500',
];
if (isNumeric(this.df)) {
classes.push('text-right');
}
if (this.size === 'small') {
classes.push('px-2 py-1');
} else {
classes.push('px-3 py-2');
}
if (this.isReadOnly) {
classes.push('text-gray-800 cursor-default');
} else {
classes.push('text-gray-900');
}
return this.getInputClassesFromProp(classes);
},
containerClasses() {
/**
* Used to accomodate extending compoents where the input is contained in
* a div eg AutoComplete
*/
const classes = ['rounded'];
if (!this.isReadOnly) {
classes.push('focus-within:bg-gray-100');
}
if (this.border) {
classes.push('bg-gray-50 border border-gray-200');
}
return classes;
},
inputPlaceholder() {
return this.placeholder || this.df.placeholder || this.df.label;
},
showMandatory() {
return this.isEmpty && this.isRequired;
},
isEmpty() {
if (Array.isArray(this.value) && !this.value.length) {
return true;
}
if (typeof this.value === 'string' && !this.value) {
return true;
}
if (getIsNullOrUndef(this.value)) {
return true;
}
return false;
},
isReadOnly() {
if (this.readOnly != null) {
if (typeof this.readOnly === 'boolean') {
return this.readOnly;
}
return this.df.readOnly;
return evaluateReadOnly(this.df, this.doc);
},
isRequired() {
if (typeof this.required === 'boolean') {
return this.required;
}
return evaluateRequired(this.df, this.doc);
},
},
methods: {
@ -112,9 +180,3 @@ export default {
},
};
</script>
<style>
input[type='number']::-webkit-inner-spin-button {
appearance: none;
}
</style>

View File

@ -1,10 +1,13 @@
<template>
<div>
<div :class="[inputClasses, containerClasses]">
<label class="flex items-center">
<div class="mr-3 text-gray-600 text-sm" v-if="showLabel && !labelRight">
{{ df.label }}
</div>
<div style="width: 14px; height: 14px; overflow: hidden; cursor: pointer">
<div
style="width: 14px; height: 14px; overflow: hidden"
:class="isReadOnly ? 'cursor-default' : 'cursor-pointer'"
>
<svg
v-if="checked"
width="14"
@ -54,7 +57,6 @@
<input
ref="input"
type="checkbox"
:class="inputClasses"
:checked="value"
:readonly="isReadOnly"
@change="(e) => !isReadOnly && triggerChange(e.target.checked)"
@ -88,9 +90,11 @@ export default {
};
},
computed: {
/*
inputClasses() {
return this.getInputClassesFromProp([]);
},
*/
checked() {
return this.value;
},

View File

@ -1,13 +1,13 @@
<template>
<div>
<div class="text-gray-600 text-sm mb-1" v-if="showLabel">
<div :class="labelClasses" v-if="showLabel">
{{ df.label }}
</div>
<Popover placement="bottom-end">
<template #target="{ togglePopover }">
<div
tabindex="0"
:class="inputClasses"
:class="[inputClasses, containerClasses]"
@click="!isReadOnly && togglePopover()"
>
<div class="flex items-center">
@ -26,7 +26,7 @@
</div>
</template>
<template #content>
<div class="text-sm py-3 px-2 text-center">
<div class="text-sm p-2 text-center">
<div>
<Row class="border-none" :column-count="5" gap="0.5rem">
<div
@ -42,10 +42,9 @@
<input
type="text"
:placeholder="t`Custom Hex`"
:class="inputClasses"
:class="[inputClasses, containerClasses]"
:value="value"
@change="(e) => setColorValue(e.target.value)"
class="bg-gray-100"
/>
</div>
</div>

View File

@ -1,12 +1,13 @@
<template>
<div>
<div class="text-gray-600 text-sm mb-1" v-if="showLabel">
<div :class="labelClasses" v-if="showLabel">
{{ df.label }}
</div>
<input
v-show="showInput"
ref="input"
:class="inputClasses"
class="text-right"
:class="[inputClasses, containerClasses]"
:type="inputType"
:value="value?.round()"
:placeholder="inputPlaceholder"
@ -17,7 +18,8 @@
/>
<div
v-show="!showInput"
:class="[inputClasses, 'cursor-text whitespace-nowrap overflow-x-auto']"
class="whitespace-nowrap overflow-x-auto"
:class="[inputClasses, containerClasses, ,]"
@click="activateInput"
@focus="activateInput"
tabindex="0"
@ -61,6 +63,10 @@ export default {
this.triggerChange(value);
},
activateInput() {
if (this.isReadOnly) {
return;
}
this.showInput = true;
nextTick(() => {
this.focus();

View File

@ -1,12 +1,13 @@
<template>
<div>
<div class="text-gray-600 text-sm mb-1" v-if="showLabel">
<div :class="labelClasses" v-if="showLabel">
{{ df.label }}
</div>
<DatePicker
ref="input"
:input-class="[inputClasses, 'cursor-text']"
:show-mandatory="showMandatory"
:input-class="['bg-transparent', inputClasses, containerClasses]"
:value="value"
:placeholder="inputPlaceholder"
:readonly="isReadOnly"

View File

@ -3,7 +3,8 @@
:df="languageDf"
:value="value"
@change="onChange"
:input-class="'focus:outline-none rounded ' + inputClass"
:border="true"
:input-class="'rounded py-1.5'"
/>
</template>
<script>
@ -17,11 +18,6 @@ export default {
setLanguageMap,
},
props: {
inputClass: {
type: String,
default:
'px-3 py-2 text-base',
},
dontReload: {
type: Boolean,
default: false,

View File

@ -1,11 +1,11 @@
<template>
<div>
<div class="text-gray-600 text-sm mb-1" v-if="showLabel">
<div :class="labelClasses" v-if="showLabel">
{{ df.label }}
</div>
<div
class="flex items-center justify-between focus-within:bg-gray-200"
:class="inputClasses"
class="flex items-center justify-between"
:class="[inputClasses, containerClasses]"
>
<select
class="
@ -17,7 +17,7 @@
"
:class="{
'pointer-events-none': isReadOnly,
'text-gray-400': !value,
'text-gray-500': !value,
}"
:value="value"
@change="(e) => triggerChange(e.target.value)"
@ -44,7 +44,8 @@
>
<path
d="M1 2.636L2.636 1l1.637 1.636M1 7.364L2.636 9l1.637-1.636"
stroke="#404040"
class="stroke-current"
:class="showMandatory ? 'text-red-500' : 'text-gray-500'"
fill="none"
fill-rule="evenodd"
stroke-linecap="round"

View File

@ -5,7 +5,7 @@
w-full
px-2
border-b
hover:bg-gray-50
hover:bg-gray-25
group
flex
items-center
@ -32,8 +32,6 @@
<FormControl
v-for="df in tableFields"
:size="size"
:read-only="readOnly"
:input-class="{ 'text-right': isNumeric(df), 'bg-transparent': true }"
:key="df.fieldname"
:df="df"
:value="row[df.fieldname]"

View File

@ -1,12 +1,13 @@
<template>
<div>
<div class="text-gray-600 text-sm mb-1" v-if="showLabel">
<div :class="labelClasses" v-if="showLabel">
{{ df.label }}
</div>
<div :class="showMandatory ? 'show-mandatory' : ''">
<textarea
ref="input"
rows="3"
:class="['resize-none', inputClasses]"
:class="['resize-none', inputClasses, containerClasses]"
:value="value"
:placeholder="inputPlaceholder"
style="vertical-align: top"
@ -16,6 +17,7 @@
@input="(e) => $emit('input', e)"
></textarea>
</div>
</div>
</template>
<script>

View File

@ -1,6 +1,7 @@
<template>
<Popover @open="selectCurrentMonthYear">
<template #target="{ togglePopover, handleBlur }">
<div :class="showMandatory ? 'show-mandatory' : ''">
<input
type="text"
:class="inputClass"
@ -10,6 +11,7 @@
@focus="!readonly ? togglePopover() : null"
@blur="handleBlur"
/>
</div>
</template>
<template #content="{ togglePopover }">
<div class="text-left p-3 select-none">
@ -63,7 +65,11 @@
{{ d }}
</div>
</div>
<div v-for="(week, i) in datesAsWeeks" :key="`${i}-${Math.random().toString(36)}`" class="mt-1">
<div
v-for="(week, i) in datesAsWeeks"
:key="`${i}-${Math.random().toString(36)}`"
class="mt-1"
>
<div class="flex w-full">
<div
v-for="date in week"
@ -123,7 +129,14 @@ import Popover from '../Popover';
export default {
name: 'DatePicker',
props: ['value', 'placeholder', 'readonly', 'formatValue', 'inputClass'],
props: [
'value',
'placeholder',
'readonly',
'formatValue',
'inputClass',
'showMandatory',
],
emits: ['change'],
components: {
Popover,
@ -256,7 +269,7 @@ export default {
return '';
}
return DateTime.fromJSDate(date).toISODate()
return DateTime.fromJSDate(date).toISODate();
},
getDate(...args) {

View File

@ -56,9 +56,9 @@
</span>
</div>
<FormControl
:border="true"
size="small"
class="w-24"
input-class="bg-gray-100"
:df="{
placeholder: t`Field`,
fieldname: 'fieldname',
@ -69,9 +69,9 @@
@change="(value) => (filter.fieldname = value)"
/>
<FormControl
:border="true"
size="small"
class="w-24"
input-class="bg-gray-100"
:df="{
placeholder: t`Condition`,
fieldname: 'condition',
@ -82,9 +82,9 @@
@change="(value) => (filter.condition = value)"
/>
<FormControl
:border="true"
size="small"
class="w-24"
input-class="bg-gray-100"
:df="{
placeholder: t`Value`,
fieldname: 'value',
@ -124,9 +124,9 @@
</template>
<script>
import { fyo } from 'src/initFyo';
import { t } from 'fyo';
import { FieldTypeEnum } from 'schemas/types';
import { fyo } from 'src/initFyo';
import { getRandomString } from 'utils';
import Button from './Button';
import FormControl from './Controls/FormControl.vue';

View File

@ -9,8 +9,8 @@
size="small"
:df="df"
:value="doc[df.fieldname]"
:read-only="evaluateReadOnly(df)"
@change="async (value) => await onChange(df, value)"
:read-only="readOnly"
/>
<!-- Inline Field Form (Eg: Address) -->
@ -29,6 +29,7 @@
:no-border="true"
:focus-first-input="true"
:autosave="false"
:read-only="readOnly"
@error="(msg) => $emit('error', msg)"
/>
<div
@ -79,8 +80,7 @@
:df="df"
:value="getRegularValue(df)"
:class="{ 'p-2': df.fieldtype === 'Check' }"
:read-only="evaluateReadOnly(df)"
input-class="bg-transparent"
:read-only="readOnly"
@change="async (value) => await onChange(df, value)"
@focus="activateInlineEditing(df)"
@new-doc="async (newdoc) => await onChange(df, newdoc.name)"
@ -103,7 +103,7 @@ import FormControl from 'src/components/Controls/FormControl.vue';
import { handleErrorWithDialog } from 'src/errorHandling';
import { fyo } from 'src/initFyo';
import { getErrorMessage } from 'src/utils';
import { evaluateHidden, evaluateReadOnly } from 'src/utils/doc';
import { evaluateHidden } from 'src/utils/doc';
export default {
name: 'TwoColumnForm',
@ -122,6 +122,7 @@ export default {
},
noBorder: Boolean,
focusFirstInput: Boolean,
readOnly: { type: [null, Boolean], default: null },
},
data() {
return {
@ -183,9 +184,6 @@ export default {
this.inlineEditField?.fieldname === df?.fieldname && this.inlineEditDoc
);
},
evaluateReadOnly(df) {
return evaluateReadOnly(df, this.doc);
},
async onChange(df, value) {
if (df.inline) {
return;

View File

@ -137,17 +137,13 @@
"
style="top: 100%; transform: translateY(-100%)"
>
<LanguageSelector
v-show="!creatingDemo"
class="text-sm w-28 bg-gray-100 rounded-md"
input-class="py-1.5 bg-transparent"
/>
<LanguageSelector v-show="!creatingDemo" class="text-sm w-28" />
<button
class="
text-sm
bg-gray-100
hover:bg-gray-200
rounded-md
rounded
px-4
py-1.5
w-28

View File

@ -63,8 +63,8 @@
<!-- Invoice Form Data Entry -->
<div class="m-4 grid grid-cols-3 gap-4">
<FormControl
class="bg-gray-100 rounded text-base"
input-class="text-lg font-semibold bg-transparent"
input-class="font-semibold"
:border="true"
:df="getField('party')"
:value="doc.party"
@change="(value) => doc.set('party', value)"
@ -72,67 +72,28 @@
:read-only="doc?.submitted"
/>
<FormControl
input-class="bg-gray-100 px-3 py-2 text-base text-right"
input-class="text-right"
:border="true"
:df="getField('date')"
:value="doc.date"
@change="(value) => doc.set('date', value)"
:read-only="doc?.submitted"
/>
<FormControl
class="text-base bg-gray-100 rounded"
input-class="bg-transparent px-3 py-2 text-base text-right"
input-class="text-right"
:border="true"
:df="getField('numberSeries')"
:value="doc.numberSeries"
@change="(value) => doc.set('numberSeries', value)"
:read-only="!doc.notInserted || doc?.submitted"
/>
<FormControl
class="text-base bg-gray-100 rounded"
input-class="px-3 py-2 text-base bg-transparent"
:border="true"
:df="getField('account')"
:value="doc.account"
@change="(value) => doc.set('account', value)"
:read-only="doc?.submitted"
/>
<!--
<FormControl
v-if="doc.enableDiscounting"
:show-label="true"
:label-right="false"
class="
text-base
bg-gray-100
rounded
flex
items-center
justify-center
w-ful
"
input-class="px-3 py-2 text-base bg-transparent text-right"
:df="getField('setDiscountAmount')"
:value="doc.setDiscountAmount"
@change="(value) => doc.set('setDiscountAmount', value)"
:read-only="doc?.submitted"
/>
<FormControl
v-if="doc.enableDiscounting && !doc.setDiscountAmount"
class="text-base bg-gray-100 rounded"
input-class="px-3 py-2 text-base bg-transparent text-right"
:df="getField('discountPercent')"
:value="doc.discountPercent"
@change="(value) => doc.set('discountPercent', value)"
:read-only="doc?.submitted"
/>
<FormControl
v-if="doc.enableDiscounting && doc.setDiscountAmount"
class="text-base bg-gray-100 rounded"
input-class="px-3 py-2 text-base bg-transparent text-right"
:df="getField('discountAmount')"
:value="doc.discountAmount"
@change="(value) => doc.set('discountAmount', value)"
:read-only="doc?.submitted"
/>
-->
</div>
<hr />
@ -161,10 +122,10 @@
</p>
<!-- Form Terms-->
<FormControl
:border="true"
v-if="!doc?.submitted || doc.terms"
:df="getField('terms')"
:value="doc.terms"
input-class="bg-gray-100"
class="mt-auto"
@change="(value) => doc.set('terms', value)"
:read-only="doc?.submitted"

View File

@ -47,43 +47,42 @@
<div class="m-4 grid grid-cols-3 gap-y-4 gap-x-4">
<!-- First Column of Fields -->
<FormControl
:border="true"
:df="getField('numberSeries')"
:value="doc.numberSeries"
@change="(value) => doc.set('numberSeries', value)"
class="bg-gray-100 rounded"
input-class="p-2 text-base bg-transparent"
:read-only="!doc.notInserted || doc.submitted"
/>
<FormControl
:border="true"
:df="getField('date')"
:value="doc.date"
:placeholder="'Date'"
@change="(value) => doc.set('date', value)"
input-class="bg-gray-100 px-3 py-2 text-base"
:read-only="doc.submitted"
/>
<FormControl
:border="true"
:df="getField('entryType')"
:value="doc.entryType"
placeholder="Entry Type"
@change="(value) => doc.set('entryType', value)"
input-class="bg-gray-100 px-3 py-2 text-base"
:read-only="doc.submitted"
/>
<FormControl
:border="true"
:df="getField('referenceNumber')"
:value="doc.referenceNumber"
:placeholder="'Reference Number'"
@change="(value) => doc.set('referenceNumber', value)"
input-class="bg-gray-100 p-2 text-base"
:read-only="doc.submitted"
/>
<FormControl
:border="true"
:df="getField('referenceDate')"
:value="doc.referenceDate"
:placeholder="'Reference Date'"
@change="(value) => doc.set('referenceDate', value)"
input-class="bg-gray-100 px-3 py-2 text-base"
:read-only="doc.submitted"
/>
</div>
@ -106,9 +105,9 @@
<div class="flex justify-between text-base m-4 gap-12">
<!-- User Remark -->
<FormControl
:border="true"
v-if="!doc.submitted || doc.userRemark"
class="w-1/2 self-end"
input-class="bg-gray-100"
:df="getField('userRemark')"
:value="doc.userRemark"
@change="(value) => doc.set('userRemark', value)"

View File

@ -14,15 +14,13 @@
</PageHeader>
<!-- Filters -->
<div v-if="report" class="grid grid-cols-5 gap-2 p-4 border-b">
<div v-if="report" class="grid grid-cols-5 gap-4 p-4 border-b">
<FormControl
v-for="field in report.filters"
:border="true"
size="small"
:show-label="field.fieldtype === 'Check'"
:key="field.fieldname + '-filter'"
class="bg-gray-100 rounded"
:class="field.fieldtype === 'Check' ? 'flex pl-2 py-1' : ''"
input-class="bg-transparent text-sm"
:df="field"
:value="report.get(field.fieldname)"
:read-only="loading"

View File

@ -9,10 +9,7 @@
@change="forwardChangeEvent"
/>
<div class="flex p-4 justify-between">
<LanguageSelector
class="text-sm w-28 bg-gray-100 rounded-md"
input-class="py-1.5 bg-transparent"
/>
<LanguageSelector class="text-sm w-28" />
<p class="mt-auto text-gray-600 text-base select-none">
{{ `v${fyo.store.appVersion}` }}
</p>

View File

@ -6,8 +6,9 @@
<!-- Setup Wizard Slide -->
<Slide
:primary-disabled="!valuesFilled || loading"
@primary-clicked="handlePrimary"
@secondary-clicked="handleSecondary"
:secondary-disabled="loading"
@primary-clicked="submit()"
@secondary-clicked="$emit('setup-canceled')"
:class="{ 'window-no-drag': platform !== 'Windows' }"
>
<template #title>
@ -21,6 +22,7 @@
<FormControl
:df="getField('logo')"
:value="doc.logo"
:read-only="loading"
@change="(value) => setValue('logo', value)"
/>
<div>
@ -28,9 +30,9 @@
ref="companyField"
:df="getField('companyName')"
:value="doc.companyName"
:read-only="loading"
@change="(value) => setValue('companyName', value)"
input-class="
bg-transparent
font-semibold
text-xl
"
@ -39,11 +41,8 @@
<FormControl
:df="getField('email')"
:value="doc.email"
:read-only="loading"
@change="(value) => setValue('email', value)"
input-class="
text-base
bg-transparent
"
/>
</div>
</div>
@ -56,11 +55,13 @@
{{ emailError }}
</p>
<TwoColumnForm :doc="doc" />
<TwoColumnForm :doc="doc" :read-only="loading" />
</div>
</template>
<template #secondaryButton>{{ t`Cancel` }}</template>
<template #primaryButton>{{ t`Submit` }}</template>
<template #primaryButton>{{
loading ? t`Setting up...` : t`Submit`
}}</template>
</Slide>
</div>
</template>
@ -69,7 +70,6 @@
import FormControl from 'src/components/Controls/FormControl.vue';
import TwoColumnForm from 'src/components/TwoColumnForm.vue';
import { getErrorMessage } from 'src/utils';
import { openLink } from 'src/utils/ipcCalls';
import { getSetupWizardDoc } from 'src/utils/misc';
import { showMessageDialog } from 'src/utils/ui';
import Slide from './Slide.vue';
@ -106,17 +106,6 @@ export default {
getField(fieldname) {
return this.doc.schema?.fields.find((f) => f.fieldname === fieldname);
},
openContributingTranslations() {
openLink(
'https://github.com/frappe/books/wiki/Contributing-Translations'
);
},
handlePrimary() {
this.submit();
},
handleSecondary() {
this.$emit('setup-canceled');
},
setValue(fieldname, value) {
this.emailError = null;
this.doc.set(fieldname, value).catch((e) => {
@ -142,14 +131,5 @@ export default {
this.$emit('setup-complete', this.doc.getValidDict());
},
},
computed: {
buttonText() {
if (this.loading) {
return this.t`Submit`;
}
return this.t`Setting Up...`;
},
},
};
</script>

View File

@ -1,5 +1,8 @@
<template>
<div class="w-form shadow-lg rounded-lg border relative bg-white" style="height: 700px">
<div
class="w-form shadow-lg rounded-lg border relative bg-white"
style="height: 700px"
>
<!-- Slide Title -->
<div class="p-4">
<h1 class="text-2xl font-semibold select-none">
@ -19,15 +22,16 @@
style="top: 100%; transform: translateY(-100%)"
>
<Button
class="text-sm text-grey-900 w-28"
class="text-sm text-grey-900 min-w-28"
@click="$emit('secondary-clicked')"
:disabled="secondaryDisabled"
>
<slot name="secondaryButton"></slot>
</Button>
<Button
@click="$emit('primary-clicked')"
type="primary"
class="text-sm text-white w-28"
class="text-sm text-white min-w-28"
:disabled="primaryDisabled"
>
<slot name="primaryButton"></slot>
@ -45,6 +49,7 @@ export default {
props: {
usePrimary: { type: Boolean, default: true },
primaryDisabled: { type: Boolean, default: false },
secondaryDisabled: { type: Boolean, default: false },
},
};
</script>

View File

@ -23,6 +23,10 @@ html {
color: theme('colors.black');
}
input[type='number']::-webkit-inner-spin-button {
appearance: none;
}
.window-drag {
-webkit-app-region: drag;
}
@ -75,7 +79,7 @@ html {
}
.w-quick-edit {
width: var(--w-quick-edit)
width: var(--w-quick-edit);
}
.h-form {
@ -109,3 +113,13 @@ html {
.w-desk {
width: var(--w-desk);
}
.show-mandatory::after {
content: '*';
display: inline-block;
width: 0px;
height: 0px;
margin-left: -0.875rem;
vertical-align: -3px;
@apply text-red-500;
}

View File

@ -1,40 +1,49 @@
import { Doc } from 'fyo/model/doc';
import { Field } from 'schemas/types';
export function evaluateReadOnly(field: Field, doc: Doc) {
if (field.readOnly !== undefined) {
return field.readOnly;
}
if (field.fieldname === 'numberSeries' && !doc.notInserted) {
export function evaluateReadOnly(field: Field, doc?: Doc) {
if (field.fieldname === 'numberSeries' && !doc?.notInserted) {
return true;
}
if (doc.isSubmitted || doc.parentdoc?.isSubmitted) {
if (doc?.isSubmitted || doc?.parentdoc?.isSubmitted) {
return true;
}
if (doc.isCancelled || doc.parentdoc?.isCancelled) {
if (doc?.isCancelled || doc?.parentdoc?.isCancelled) {
return true;
}
const readOnlyFunc = doc.readOnly[field.fieldname];
if (readOnlyFunc !== undefined) {
return readOnlyFunc();
return evaluateFieldMeta(field, doc, 'readOnly');
}
return false;
export function evaluateHidden(field: Field, doc?: Doc) {
return evaluateFieldMeta(field, doc, 'hidden');
}
export function evaluateHidden(field: Field, doc: Doc) {
if (field.hidden !== undefined) {
return field.hidden;
export function evaluateRequired(field: Field, doc?: Doc) {
return evaluateFieldMeta(field, doc, 'required');
}
const hiddenFunction = doc.hidden[field.fieldname];
function evaluateFieldMeta(
field: Field,
doc?: Doc,
meta?: 'required' | 'hidden' | 'readOnly',
defaultValue: boolean = false
) {
if (meta === undefined) {
return defaultValue;
}
const value = field[meta];
if (value !== undefined) {
return value;
}
const hiddenFunction = doc?.[meta]?.[field.fieldname];
if (hiddenFunction !== undefined) {
return hiddenFunction();
}
return false;
return defaultValue;
}