Admin Layout

When you download the Olobase Admin Skelethon, your project will be launched with the pre-created default admin layout. The .vue template for this layout is located in the src/layout/Admin.vue file and is linked to the authenticated route in src/routes/admin.js. connected as follows:

src/router/admin.js

import AdminLayout from "@/layouts/Admin";
//...
export default {
  path: "/",
  name: "home",
  redirect: "/dashboard",
  component: AdminLayout,
  meta: {
    title: i18n.t("routes.home"),
  },
  children: [
    //...
  ],
};

Main Layout

The customizable main layout with one slot for each area is called VaLayout.

Name Description
VaAppBar The sidebar area is the ideal place for the VNavigationDrawer content header region, additional custom messages or important notifications as impersonation status, etc. Ideal place for.
VaBreadcrumbs Content header region, VBreadcrumbs and/or additional custom messages or important notifications as impersonation status, etc. Ideal place for.
VaFooter You can put some corporate information and links in the footer area.
VaAside 2nd left or right side area where you can put everything you need.

Menu Links

See links below.

VaAppBar

The default VAppBar contains the application title, header menus, direct resource creation links, global refresh action, profile menu. The profile user drop-down menu does not appear in guest mode.

Property Type Description
title string To change the default title, change the title key value in the OlobaseAdmin.setOptions() method.
elevation number|string Sets the shade degree of the component. (See. Vuetify Elevations).
headerMenu array Header allows links to be visible at the top.
disableCreate boolean Disables the creation menu.
disableReload boolean Disables the reload (page refresh) key.
color string Sets the main color for the VAppBar component.
sidebarColor string Sets the specified color for VNavigationDrawer.
listItemColor string Sets the list item color for the VAppBar component.
density string Sets the vertical height used by the component. The default is "compact". Possible values: 'default' | 'prominent' | 'comfortable' | 'compact'.
listItemDensity string Sets the vertical height of list items. The default is "compact". Possible values: 'default' | 'prominent' | 'comfortable' | 'compact'.
flat boolean Removes AppBar shadow.

Resource Links

If the current user has permissions, creating action links will be automatically created from your saved resources.

Reload Button

The reload key dynamically refreshes every listing call from your data provider (for example getList, getOne or getMany). With a manual click, the content sends a new listing call. This button appears only on listing pages.

Refresh Button

VaAppBar:sidebar

Vuetify is the default customizable section with hierarchical menu with VNavigationDrawer component. This section is located within the VaAppBar component.

packages/admin/src/components/layout/AppBar.vue

SideBar

src/layout/Admin.vue

<template>
  <v-app>
    <va-layout 
      v-if="authenticatedUser"
    >
      <template #appbar>
        <va-app-bar
          :key="getCurrentLocale"
          color="primary"
          density="compact"
          :header-menu="getHeaderMenu"
          sidebar-color="white"
        >
          <template v-slot:logo>
            <div class="mb-1" style="letter-spacing: 1px;">logo</div>
          </template>

          <template v-slot:avatar>
            <v-avatar v-if="avatarExists" size="24px">
              <v-img 
                :src="getAvatar"
                alt="Avatar"
              ></v-img>
            </v-avatar>
            <v-icon v-else>mdi-account-circle</v-icon>
          </template>

          <template v-slot:profile>
            <v-card min-width="300">
              <v-list nav>
                <v-list-item 
                   v-if="getFullname"
                  :prepend-avatar="getAvatar"
                >
                  <div class="list-item-content">
                    <v-list-item-title class="title">{{ getFullname }}</v-list-item-title>
                    <v-list-item-subtitle v-if="getEmail">{{ getEmail }}</v-list-item-subtitle>
                  </div>
                </v-list-item>
                <v-divider></v-divider>
                <v-card flat>
                  <v-card-text style="padding:9px">
                    <v-list-item
                      v-for="(item, index) in getProfileMenu"
                      :key="index"
                      link
                      :to="item.link"
                      @click="item.logout ? logout() : null"
                      class=" mt-2"
                    >
                      <template v-slot:prepend>
                        <v-icon>{{ item.icon }}</v-icon>
                      </template>
                      <v-list-item-title>{{ item.text }}</v-list-item-title>
                    </v-list-item>
                  </v-card-text>
                </v-card>
              </v-list>
            </v-card>
          </template>
        </va-app-bar>
      </template>

      <template #header>
        <va-breadcrumbs />
      </template>

      <template #aside>
        <va-aside />
      </template>

      <template #footer>
        <va-footer 
          :key="getCurrentLocale" 
          :menu="getFooterMenu"
        >
          <span style="font-size:13px">&copy; 2023</span>
        </va-footer>
      </template>
    </va-layout>
  </v-app>
</template>
<script>
import isEmpty from "lodash/isEmpty"
import { useDisplay } from "vuetify";
import { mapActions } from "vuex";
import Trans from "@/i18n/translation";

export default {
  name: "App",
  inject: ["admin"],
  data() {
    return {
      authenticatedUser: null,
    };
  },
  async created() {
    /**
     * Set default locale
     */
    const lang = Trans.guessDefaultLocale();
    if (lang && Trans.supportedLocales.includes(lang)) { // assign browser language
      await Trans.switchLanguage(lang);
    }
    /**
     * Check user is authenticated
     */
    this.authenticatedUser = await this.checkAuth();
    if (! this.authenticatedUser) {
      this.$router.push({name: "login"});
    } else {
      // 
      // Please do not remove it, it periodically updates the session lifetime.
      // Thus, as long as the user's browser is open, the user logged in to the application,
      // otherwise the session will be closed when the ttl period expires.
      // 
      this.admin.http.post('/auth/session', { update: 1 }); 
    }
  },
  computed: {
    avatarExists() {
      let base64Image = this.$store.getters["auth/getAvatar"];
      if (base64Image == "undefined" || base64Image == "null" || isEmpty(base64Image)) { 
        return false;
      }
      return true;
    },
    getAvatar() {
      let base64Image = this.$store.getters["auth/getAvatar"]; 
      if (base64Image == "undefined" || base64Image == "null" || isEmpty(base64Image)) { 
        return this.admin.getConfig().avatar.base64; // default avatar image
      }
      return base64Image;
    },
    getEmail() {
      return this.$store.getters["auth/getEmail"];
    },
    getFullname() {
      return this.$store.getters["auth/getFullname"];
    },
    getCurrentLocale() {
      return this.$store.getters[`getLocale`];
    },
    getHeaderMenu() {
      return [];
    },
    getProfileMenu() {
      return [
        {
          icon: "mdi-account",
          text:  this.$t("va.account"),
          link: "/account",
        },
        {
          icon: "mdi-key-variant",
          text: this.$t("va.changePassword"),
          link: "/password",
        },
        {
          icon: "mdi-logout",
          text: this.$t("va.logout"),
          logout: true,
        },
      ];
    },
    getFooterMenu() {
      return [
        {
          href: "https://oloma.dev/end-user-license-agreement",
          text: this.$t("menu.terms"),
        },
      ]
    }
  },
  methods: {
    ...mapActions({
      checkAuth: "auth/checkAuth",
    }),
    logout() {
      this.$store.dispatch("auth/logout");
    },
  },
};
</script>

VaAppBar:logo

VaAppBar allows you to add logos from two separate slots: layout logo and navbar-logo.

<template v-slot:logo>
  <div class="mb-1" style="letter-spacing: 1px;">logo</div>
</template>

As an alternative to the logo in the header section, you can also add a logo on the navigation with the navbar-logo slot.

SideBar

<template v-slot:navbar-logo>
  <div class="navbar-logo ml-14">
    <img src="/src/assets/logo/navbar-logo.png" border="0" />
  </div>
</template>

VaAppBar:header-buttons

You can create your own buttons using the VaAppBar layout header-buttons slot.

Header Buttons

<template v-slot:header-buttons>
  <v-btn
    icon
    small
  >
    <v-badge :color="yellow" dot>
      <v-icon>mdi-cart-outline</v-icon>
    </v-badge>
  </v-btn>
  <v-btn v-if="!authenticatedUser" :to="{ name: 'login' }">{{ $t("menu.login") }}</v-btn>
</template>

Footer

This section is a footer area that allows displaying some corporate information in the VFooter component.

Property Type Description
footerMenu array Menu links.

SideBar

Slots

Name Description
default Information on the right.

Breadcrumbs

Automatically creates hierarchical links from the current route using the v-breadcrumbs component for breadcrumbs.

Breadcrumbs

Aside

Customizable layout where you put some additional contextualized information. The VaAsideLayout component is used to integrate content from anywhere, in any context.

Aside

olobase-demo-ui/src/resources/Companies/List.vue

<template>
  <div>
    <va-aside-layout 
      :title="asideTitle"
    >
      <companies-form
        v-if="action !== 'show'"
        :id="id"
        :item="item"
        @saved="onSaved"
      ></companies-form>
    </va-aside-layout>
    <va-list 
      class="mb-0" 
      @action="onAction"
      :filters="filters"
      :fields="fields"
      :items-per-page="50"
      disable-create-redirect
    >
      <va-data-table-server
        row-show
        disable-show
        disable-create-redirect
        disable-edit-redirect
        @item-action="onAction"
      >
      </va-data-table-server>
    </va-list>
   </div>
</template>

For more details, check out the companies module in our demo application.

Property Type Description
location string Position of the opened section. Possible values: 'top' | 'end' | 'bottom' | 'start' | 'left' | 'right'.
width number Width of the opened section.

Menu Links

Any navigation menu that can be placed in components that support navigation is a simple array of objects that represent a link. Components that support navigation; It consists of a total of 4 different components: header, profile, sidebar and footer menu.

Menus are created by sending a simple menu array as follows to these components.

[
  {
    icon: "mdi-account",
    text: this.$t("menu.profile"),
    link: "/profile",
  },
  {
    icon: "mdi-settings",
    text: this.$t("menu.settings"),
    link: "/settings",
  },
]

Sidebar menu example:

src/_nav.js

export default  {

  build: async function(t, admin) {

    return [
      {
        icon: "mdi-view-dashboard-outline",
        text: t("menu.dashboard"),
        link: "/dashboard",
      },
      {
        icon: "mdi-cart-variant",
        text: t("menu.plans"),
        children: [
          {
            icon: "circle",
            text: t("menu.subscriptions"),
            link: "/subscriptions",
          },
          {
            icon: "circle",
            text: t("menu.services"),
            link: "/services",
          },
        ]
      },
    ];

  } // end func

} // end class

To create the menu dynamically based on authorizations, see related document.

Object link structure:

Property Type Description
icon string The menu icon shown on the left. Must be a valid mdi and is only supported in sidebar and profile menu.
text string Link tag.
link string | object Current Vue router menu. It cannot be used with child connections.
href string Use for external links only. The target value is sent as empty. It cannot be used with child connections.
children array Used only for sublinks to the hierarchical menu for the sidebar. Cannot be used with link or href.
expanded boolean Shows Children links as expanded by default. It only affects links that are children.
heading string It just turns the link into a section label title for the sidebar menu. All other features within it are disabled.
divider boolean It turns the link into a separator for the sidebar menu only. All other features within it are disabled.