Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ export default {
},
{
name: 'price',
inputSuffix: 'USD', // you can add a suffix to an input field that will be displayed when creating or editing records
allowMinMaxQuery: true, // use better experience for filtering e.g. date range, set it only if you have index on this column or if you sure there will be low number of rows
editingNote: 'Price is in USD', // you can put a note near field on editing or creating page
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,28 @@ export default {

> `validation` checks are enforced both on frontend and backend.

### Input prefix and suffix

You can add prefix or suffix to inputs by adding `inputPrefix` or `inputSuffix` fields to a column.

```typescript title="./resources/users.ts"
export default {
name: 'users',
columns: [
...
{
name: "price",
inputSuffix: "USD",
allowMinMaxQuery: true,
},
],
},
...
],
```

These fields can only be used with following `AdminForthDataTypes`: `DECIMAL`, `FLOAT`, `INTEGER`, `STRING` and `JSON` (only if `JSON` column is an array with appropriate `itemType`).

### Editing note

You can add `editingNote` to a column to show a note below the input field.
Expand Down
20 changes: 20 additions & 0 deletions adminforth/modules/configValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,26 @@ export default class ConfigValidator implements IConfigValidator {
}
}

if (inCol.inputPrefix || inCol.inputSuffix) {
if (![AdminForthDataTypes.DECIMAL, AdminForthDataTypes.FLOAT, AdminForthDataTypes.INTEGER, AdminForthDataTypes.STRING, undefined].includes(col.type)) {
if (inCol.type === AdminForthDataTypes.JSON) {
if (inCol.isArray && inCol.isArray.enabled && ![AdminForthDataTypes.DECIMAL, AdminForthDataTypes.FLOAT, AdminForthDataTypes.INTEGER, AdminForthDataTypes.STRING].includes(inCol.isArray.itemType)) {
errors.push(`Resource "${res.resourceId}" column "${col.name}" has input${inCol.inputPrefix ? 'Prefix': 'Suffix'} but it is not supported for array columns item type: ${inCol.isArray.itemType}`);
} else if (!inCol.isArray || !inCol.isArray.enabled) {
errors.push(`Resource "${res.resourceId}" column "${col.name}" has input${inCol.inputPrefix ? 'Prefix' : 'Suffix'} but it is not supported for this column type: ${col.type}`);
}
} else {
errors.push(`Resource "${res.resourceId}" column "${col.name}" has input${inCol.inputPrefix ? 'Prefix' : 'Suffix'} but it is not supported for this column type: ${col.type}`);
}
}
if (inCol.enum) {
errors.push(`Resource "${res.resourceId}" column "${col.name}" has input${inCol.inputPrefix ? 'Prefix' : 'Suffix'} but it is not supported for enum columns`);
}
if (inCol.foreignResource) {
errors.push(`Resource "${res.resourceId}" column "${col.name}" has input${inCol.inputPrefix ? 'Prefix' : 'Suffix'} but it is not supported for foreignResource columns`);
}
}

// check is all custom components files exists
if (col.components) {
for (const [key, comp] of Object.entries(col.components as Record<string, AdminForthComponentDeclarationFull>)) {
Expand Down
14 changes: 8 additions & 6 deletions adminforth/spa/src/afcl/Input.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

<div class="flex z-0">
<span
v-if="$slots.prefix"
class="inline-flex items-center px-3 text-sm text-gray-900 bg-gray-200 border border-s-0 border-gray-300 rounded-e-md dark:bg-gray-600 dark:text-gray-400 dark:border-gray-600">
<slot name="prefix"></slot>
v-if="$slots.prefix || prefix"
class="inline-flex items-center px-3 text-sm text-gray-900 bg-gray-200 border border-s-0 border-gray-300 rounded-s-md dark:bg-gray-600 dark:text-gray-400 dark:border-gray-600">
<slot name="prefix">{{ prefix }}</slot>
</span>

<!-- translate needed for bumping ring above prefix without z-index -->
Expand All @@ -16,14 +16,14 @@
aria-describedby="helper-text-explanation"
class="inline-flex bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-0 focus:ring-lightPrimary focus:border-lightPrimary dark:focus:ring-darkPrimary dark:focus:border-darkPrimary
blue-500 focus:border-blue-500 block w-20 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white translate-y-0"
:class="{'rounded-l-md': !$slots.prefix, 'rounded-r-md': !$slots.suffix, 'w-full': fullWidth}"
:class="{'rounded-l-md': !$slots.prefix && !prefix, 'rounded-r-md': !$slots.suffix && !suffix, 'w-full': fullWidth}"
>


<span
v-if="$slots.suffix"
v-if="$slots.suffix || suffix"
class="inline-flex items-center px-3 text-sm text-gray-900 bg-gray-200 border border-s-0 border-gray-300 rounded-e-md dark:bg-gray-600 dark:text-gray-400 dark:border-gray-600 ">
<slot name="suffix"></slot>
<slot name="suffix">{{ suffix }}</slot>
</span>

</div>
Expand All @@ -35,6 +35,8 @@ const props = defineProps({
type: String,
fullWidth: Boolean,
modelValue: String,
suffix: String,
prefix: String,
})


Expand Down
37 changes: 22 additions & 15 deletions adminforth/spa/src/components/ColumnValueInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,19 @@
:readonly="column.editReadonly && source === 'edit'"
@update:modelValue="$emit('update:modelValue', $event)"
/>
<input
<Input
v-else-if="['integer'].includes(type || column.type)"
ref="input"
type="number"
type="number"
step="1"
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg block w-40 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white focus:ring-lightPrimary focus:border-lightPrimary dark:focus:ring-darkPrimary dark:focus:border-darkPrimary"
class="w-40"
placeholder="0"
:prefix="column.inputPrefix"
:suffix="column.inputSuffix"
:readonly="column.editReadonly && source === 'edit'"
:value="value"
@input="$emit('update:modelValue', $event.target.value)"
>
:modelValue="value"
@update:modelValue="$emit('update:modelValue', $event)"
/>
<CustomDatePicker
v-else-if="['datetime'].includes(type || column.type)"
ref="input"
Expand All @@ -59,15 +61,17 @@
@update:valueStart="$emit('update:modelValue', $event)"
:readonly="column.editReadonly && source === 'edit'"
/>
<input
<Input
v-else-if="['decimal', 'float'].includes(type || column.type)"
ref="input"
type="number"
step="0.1"
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg block w-40 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white focus:ring-lightPrimary focus:border-lightPrimary dark:focus:ring-darkPrimary dark:focus:border-darkPrimary"
class="w-40"
placeholder="0.0"
:value="value"
@input="$emit('update:modelValue', $event.target.value)"
:prefix="column.inputPrefix"
:suffix="column.inputSuffix"
:modelValue="value"
@update:modelValue="$emit('update:modelValue', $event)"
:readonly="column.editReadonly && source === 'edit'"
/>
<textarea
Expand All @@ -87,19 +91,21 @@
:value="value"
@input="$emit('update:modelValue', $event.target.value)"
/>
<input
<Input
v-else
ref="input"
:type="!column.masked || unmasked[column.name] ? 'text' : 'password'"
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white focus:ring-lightPrimary focus:border-lightPrimary dark:focus:ring-darkPrimary dark:focus:border-darkPrimary"
class="w-full"
:placeholder="$t('Text')"
:value="value"
@input="$emit('update:modelValue', $event.target.value)"
:prefix="column.inputPrefix"
:suffix="column.inputSuffix"
:modelValue="value"
@update:modelValue="$emit('update:modelValue', $event)"
autocomplete="false"
data-lpignore="true"
readonly
@focus="onFocusHandler($event, column, source)"
>
/>

<button
v-if="deletable"
Expand All @@ -125,6 +131,7 @@
import { IconEyeSlashSolid, IconEyeSolid, IconTrashBinSolid } from '@iconify-prerendered/vue-flowbite';
import CustomDatePicker from "@/components/CustomDatePicker.vue";
import Select from '@/afcl/Select.vue';
import Input from '@/afcl/Input.vue';
import { ref } from 'vue';
import { getCustomComponent } from '@/utils';
import { useI18n } from 'vue-i18n';
Expand Down
6 changes: 6 additions & 0 deletions adminforth/types/Common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,12 @@ export interface AdminForthResourceColumnInputCommon {
*/
required?: boolean | { create?: boolean, edit?: boolean },

/**
* Prefix and suffix for input field on create and edit pages.
*/
inputPrefix?: string,
inputSuffix?: string,

/**
* Whether AdminForth will show editing note near the field in edit/create form.
*/
Expand Down