After completing the Installation section, configure your environments and review the examples by running the demo application. You can open a support request for sections you do not understand from the documentation, or browse previously asked questions on the Github Discussions page.
Step 1 is to identify the backend resources you want to manage.
Go to src/resources/index.js.
export default [
{
name: "companies",
icon: "mdi-city",
label: "name",
},
{
name: "users",
icon: "mdi-account",
permissions: ["admin"],
},
{
name: "roles",
icon: "mdi-account-key",
label: "name",
permissions: [
{ name: "admin", actions: ["show","list","edit","delete", "create"] },
],
actions: ["show","list", "edit", "delete", "create"],
}
];
In your Olobase Admin application, permissions are defined in the "pernissions" array as seen above. On the frontend, items that the user does not have permission to access are simply hidden or shown by show/hide. In the backend, a 403 Forbidden response is sent to the user for each unauthorized transaction.
Step 2 is to define CRUD pages for each resource, following this naming convention:
src/resources/{Resource}/{action}.vue.
For example, for the List request, create a file named List.vue under a src/resources/Users/ folder.
src/resources/Users/List.vue
<template>
<div>
<v-card>
<v-card-text>
<va-list :fields="fields" :filters="filters" :disable-global-search="false" :disable-actions="false">
<va-data-table-server>
</va-data-table-server>
</va-list>
</v-card-text>
</v-card>
</div>
</template>
<script>
export default {
props: ["resource"],
data() {
return {
filters: [
{ source: "firstname", label: this.$t("users.firstname"), col: 2 },
{ source: "lastname", label: this.$t("users.lastname") },
{ source: "email", label: this.$t("users.email") },
{ source: "active", label: this.$t("users.active"), type: "boolean" },
],
fields: [
{
source: "firstname",
label: this.$t("users.firstname"),
sortable: true,
width: "5%"
},
{
source: "lastname",
label: this.$t("users.lastname"),
sortable: true,
},
{
source: "email",
label: this.$t("users.email"),
sortable: true,
},
{
source: "active",
label: this.$t("users.active"),
sortable: true,
}
],
};
},
};
</script>
src/resources/Users/Show.vue
<template>
<v-card>
<v-card-text>
<va-show-layout :title="title">
<va-show :item="item">
<v-row justify="left">
<v-col cols="4">
<v-table density="compact" class="va-show-table">
<tbody>
<tr>
<td><b>{{ $t('users.firstname') }}</b></td>
<td>
<va-field source="firstname"></va-field>
</td>
</tr>
<tr>
<td><b>{{ $t('users.lastname') }}</b></td>
<td>
<va-field source="lastname" :label="$t('users.lastname')"></va-field>
</td>
</tr>
<tr>
<td><b>{{ $t('users.email') }}</b></td>
<td>
<va-field source="email" :label="$t('users.email')"></va-field>
</td>
</tr>
<tr>
<td><b>{{ $t('users.active') }}</b></td>
<td>
<va-field source="active" type="boolean"></va-field>
</td>
</tr>
<tr>
<td><b>{{ $t('users.createdAt') }}</b></td>
<td>
<va-field source="createdAt" :label="$t('users.createdAt')"></va-field>
</td>
</tr>
</tbody>
</v-table>
</v-col>
</v-row>
</va-show>
</va-show-layout>
</v-card-text>
</v-card>
</template>
<script>
export default {
props: ["title", "item"],
};
</script>
src/resources/Users/Create.vue
<template>
<va-create-layout :title="title">
<users-form :item="item"></users-form>
</va-create-layout>
</template>
<script>
export default {
props: ["title", "item"],
};
</script>
src/resources/Users/Edit.vue
<template>
<va-edit-layout :title="title">
<users-form :id="id" :item="item"></users-form>
</va-edit-layout>
</template>
<script>
export default {
props: ["id", "title", "item"],
};
</script>
src/resources/Users/Form.vue
<template>
<va-form :id="id" :item="item" v-model="model">
<v-row no-gutters>
<v-col lg="3" md="3" sm="8">
<va-avatar-input source="avatar.image">
</va-avatar-input>
<va-text-input source="firstname" :error-messages="firstnameErrors"></va-text-input>
<va-text-input source="lastname" :error-messages="lastnameErrors"></va-text-input>
<va-text-input source="email" :error-messages="emailErrors"></va-text-input>
<va-text-input source="password" :error-messages="passwordErrors"></va-text-input>
<va-select-input source="userRoles" reference="roles" :error-messages="userRoleErrors" multiple clearable></va-select-input>
<va-boolean-input source="active" hide-details class="mb-2"></va-boolean-input>
<va-boolean-input source="emailActivation" class="mb-1">
</va-boolean-input>
</v-col>
</v-row>
<va-save-button class="mr-2"></va-save-button>
</va-form>
</template>
<script>
import { provide } from 'vue';
import { useVuelidate } from "@vuelidate/core";
import { required, email, minLength, maxLength } from "@vuelidate/validators";
import Utils from "olobase-admin/src/mixins/utils";
export default {
props: ["id", "item"],
mixins: [Utils],
setup() {
let vuelidate = useVuelidate();
provide('v$', vuelidate)
return { v$: vuelidate }
},
validations: {
model: {
firstname: {
required,
minLength: minLength(2),
},
lastname: {
required,
minLength: minLength(2),
maxLength: maxLength(120),
},
userRoles: {
required,
},
email: {
required,
email,
},
password: {
minLength: minLength(8),
maxLength: maxLength(16),
},
}
},
data() {
return {
model: {
id: null,
firstname: null,
lastname: null,
email: null,
password: null,
active: 0,
emailActivation: 0,
userRoles: null,
avatar: {
image: null
}
},
};
},
created() {
this.model.id = this.generateId(this);
if (!this.id) {
this.model.password = this.generatePassword(8);
}
},
computed: {
firstnameErrors() {
const errors = [];
if (!this.v$['model'].firstname.$dirty) return errors;
this.v$['model'].firstname.required.$invalid &&
errors.push(this.$t("v.text.required"));
this.v$['model'].firstname.minLength.$invalid &&
errors.push(this.$t("v.string.minLength", { min: "2" }));
return errors;
},
lastnameErrors() {
const errors = [];
if (!this.v$['model'].lastname.$dirty) return errors;
this.v$['model'].lastname.required.$invalid &&
errors.push(this.$t("v.text.required"));
this.v$['model'].lastname.minLength.$invalid &&
errors.push(this.$t("v.string.minLength", { min: "2" }));
this.v$['model'].lastname.maxLength.$invalid &&
errors.push(this.$t("v.string.maxLength", { max: "120" }));
return errors;
},
emailErrors() {
const errors = [];
if (!this.v$['model'].email.$dirty) return errors;
this.v$['model'].email.required.$invalid &&
errors.push(this.$t("v.email.required"));
this.v$["model"].email.email.$invalid &&
errors.push(this.$t("v.email.invalid"));
return errors;
},
passwordErrors() {
const errors = [];
if (!this.v$["model"].password.$dirty) return errors;
this.v$["model"].password.minLength.$invalid &&
errors.push(this.$t("v.string.minLength", { min: "8" }));
this.v$["model"].password.maxLength.$invalid &&
errors.push(this.$t("v.string.maxLength", { max: "16" }));
return errors;
},
userRoleErrors() {
const errors = [];
if (!this.v$["model"].userRoles.$dirty) return errors;
this.v$["model"].userRoles.required.$invalid &&
errors.push(this.$t("v.text.required"));
return errors;
},
},
}
</script>