Extends UnityBase adminUI by Vue + ElementUI libraries. Starts from UB@5 Vue is a preferred way to build a UI.

This documentation contains a JS (non-visual) functions/methods/modules exported by @unitybase/adminui-vue. For documentation of the VueJS based UI components see UI library for Vue.

What included

  • VueJS - exported as global Vue variable and registered in SystemJS as 'vue'
  • Vuex - injected into Vue.prototype
  • Vuelidate - injected into Vue.prototype as $v
  • throttle-debounce - exported as throttleDebounce
  • magicLink - a hyperlink click custom actions - see module:magicLinks
  • ElementUI - exported as global ElementUI variable and registered in SystemJS as 'element-ui'
  • @unitybase/ub-pub - available as Vue.prototype.$UB (or this.$UB inside vue component)
  • UB.i18n - integrated into Vue as $ut
  • i18n filter available in vue templates. Lines below produce the same output
<div> {{ 'uba_user' | i18n}} </div>
<div> {{ $ut('uba_user') }} </div>
  • dist/adminui-vue.css theme include normalize.css && modified element-theme-chalk
  • modern login page - located in /views/ub-auth.html. The path to this page is a default for uiSettings.adminUI.loginURL

Usage

adminUI based app

An adminUI based application should add a @unitybase/adminui-vue model into domain.models section of ubConfig after adminui-pub

"application": {
  "domain": {
    "models": [
      ...
      { "path": "./node_modules/@unitybase/adminui-vue" }
      ..

Webpack && SystemJS

Module is registered in SystemJS registry as @unitybase/adminui-vue, so any file what loaded using SystemJS (all UnityBase forms and their dependencies) will use adminui-vue what already loaded into browser.

For packages, what need to be compiled using webpack starts from @unitybase/adminui-vue@5.23.11 module also exposed as a global $AdminUiVue variable. To prevent load adminui-vue twice webpack config must contain external @unitybase/adminui-vue': '$AdminUiVue:

  externals: {
    'lodash': '_',
    '@unitybase/ub-pub': 'UB',
    '@unitybase/adminui-vue': '$AdminUiVue',
    'vue': 'Vue',
    'element-ui': 'ElementUI'
  }

Stand-alone app

See /views/ub-auth.html for sample

Embed a compiled Vue app into adminUI

  • define output and externals section into webpack config to prevent loading modules twice:
  {output: {
    path: path.join(__dirname, 'dist'),
    library: 'YUR_LIB_NAME',
    libraryTarget: 'var',
    filename: 'your-lib-entry-point.min.js',
    publicPath: '/clientRequire/YOUR_MODULE_NAME/dist/'
  },
  externals: {
    lodash: '_',
    '@unitybase/ub-pub': 'UB',
    '@unitybase/adminui-pub': '$App',
    'vue': 'Vue',
    'element-ui': 'ElementUI',
  }}

PDF Viewer AppOptions

UPdfViewerExt accepts a viewerOptions prop — a bag of PDF.js AppOptions applied via PDFViewerApplicationOptions on the iframe's webviewerloaded event (before PDFViewerApplication.open()). Keys that are not passed are not set, so PDF.js defaults stay in effect. Changing the prop after mount does not reload the document.

Global defaults can be set under uiSettings.adminUI.pdfViewer.viewerOptions in ubConfig; the prop is merged on top.

// per-instance (e.g. for PDFs stamped/watermarked on each getDocument)
<u-pdf-viewer-ext :src="src" :viewer-options="{ disableRange: true }" />

// or globally in ubConfig.json
"uiSettings": {
  "adminUI": {
    "pdfViewer": {
      "extendedPdfViewer": true,
      "viewerOptions": { "disableRange": true }
    }
  }
}

disableRange: true forces a single full-file fetch instead of HTTP Range partials — required when the server regenerates the PDF bytes on every request (QR stamps, watermarks), otherwise PDF.js can hit Bad (uncompressed) XRef entry.

As soon as at least one option is configured, disablePreferences: true is added to the bag — otherwise PDF.js reads its Preferences from localStorage right before opening the document and can override what was set here. Pass disablePreferences: false explicitly to opt out. An option PDF.js refuses to accept (unknown name or a value of a wrong type, e.g. "true" instead of true) is silently ignored by AppOptions, so such a case is reported into the browser console.

API options (forwarded to getDocument)

These are PDF.js OptionKind.API keys. They are applied on webviewerloaded and then spread into getDocument({ ...AppOptions.getAll(API) }), so they take effect for document loading. Defaults below are PDF.js defaults (we do not override unpassed keys). Upstream: app_options.js v5.3.31.

Option Default Description
disableRange false Disable HTTP Range; fetch the whole file in one response. Use when PDF bytes are not identical across requests (QR/watermark).
disableStream false Disable response streaming; wait for the full body before parsing.
disableAutoFetch false When Range is on, do not background-fetch the rest of the file — only requested chunks.
disableFontFace false Do not use CSS @font-face; render glyphs via built-in paths (slower, more compatible).
enableXfa true Render XFA forms when the PDF contains them.
enableHWA true Prefer hardware-accelerated canvas rendering.
maxImageSize -1 Max embedded image size as width * height pixels; -1 = no limit.
canvasMaxAreaInBytes -1 Cap for canvas memory area; -1 = no extra cap.
verbosity 1 Log level: 0 errors, 1 warnings, 5 infos.
docBaseUrl "" Base URL for resolving relative links inside the PDF.
cMapUrl "../web/cmaps/" Base URL for CMap files (CJK). Keep default unless you host cmaps elsewhere.
cMapPacked true Load packed CMap binaries.
standardFontDataUrl "../web/standard_fonts/" Base URL for standard font data.
iccUrl "../web/iccs/" Base URL for ICC profiles.
wasmUrl "../web/wasm/" Base URL for WASM helpers.
fontExtraProperties false Keep extra font metadata (mainly for debugging).
isEvalSupported true Allow eval in font path code (some Type1 fonts).
isOffscreenCanvasSupported true Allow OffscreenCanvas when available.
useSystemFonts undefined When true, prefer system fonts over embedded substitutes.
pdfBug false Enable PDF.js internal debug hooks.

Other AppOptions (VIEWER / BROWSER / WORKER) can still be passed in the same object, but they are not guaranteed to affect loading the same way (and paths like workerSrc should normally stay at viewer defaults). UI flags such as allowPrint / allowDownload / allowAnnotations are not AppOptions — they are separate UPdfViewerExt props / uiSettings.adminUI.pdfViewer.* keys.

PDF Viewer Extensions

@unitybase/adminui-vue exports the pdfViewerExtensions registry, which allows external packages to extend the UPdfViewerExt component with custom toolbar buttons, side panels and event handlers without modifying the component source code.

const { pdfViewerExtensions } = require('@unitybase/adminui-vue')

pdfViewerExtensions.register('my-extension', {
  getToolbarButtons (context) {
    return [{ id: 'btn-id', icon: '<svg>...</svg>', action: 'toggle-right-panel', position: 'right' }]
  },
  onDocumentLoaded (context) { /* populate panel items, etc. */ },
  onToolbarButtonClick (context, detail) { },
  onPanelItemClick (context, detail) { },

  // OPTIONAL: ship an iframe-side script that registers an iframe module via
  // `globalThis.__upveModules.register(...)` to add toolbar actions, listen to
  // PDF.js events or claim postMessage types from inside the viewer iframe.
  iframeModule: { src: '/clientRequire/@my-scope/my-pkg/dist/my.iframe.js' }
})

See iframe/README.md in the UPdfViewerExt directory for the full extension protocol, available actions, the __upveModules iframe-side registry and context properties.

Debugging

ElementUI in debug mode

For better debugging experience we recommend rebuilding element-ui in development mode. Use element-ui branch for a version specified in adminui-vue package.json (2.5.4 in a moment of writing this manual)

git clone https://github.com/ElemeFE/element.git
cd element
git checkout v2.5.4
npm i
npm run clean && npm run build:file && npx webpack --config build/webpack.conf.js --mode development

and copy /lib/index.js into your project. In my case project is located in ~/dev/ubjs/apps/autotest

cp ./lib/index.js ~/dev/ubjs/apps/autotest/node_modules/element-ui/lib

Prevent debugger to dig into vue sources

While debugging a components source you can prevent debugger to dig into vue sources.

To do this in Source tab of debugger press F1 to open Preferences, select Blackboxing on the left and add a pattern vue.common.dev.js$.

After this Step into (F11) will skip vue sources

Theme

Generate variables

npm run gen-el-vars

Edit theme/ub-el.scss and build a theme using command:

npm run build:theme

Submodules

Members

# BASIC_SANITIZE_CONFIG : object static

Basic sanitize config for the sanitize-html library

# BASIC_SANITIZE_CONFIG_WITH_STYLES : object static

Basic sanitize config for the sanitize-html library with styles

# BASIC_SANITIZE_SVG_CONFIG : object static

Basic SVG sanitize config for the sanitize-html library

# clickOutsideDropdownMixin static

Mixin for USelectEntity/USelectMultiple like components to close options dropdown on click outside

# columnTemplates : columnTemplates static

The module provides column settings, cell templates,s and filter templates by UB data types or by the customSettings.columnTemplate value. Different types can have the same templates or settings.

Entity attributes with Text, BLOB, TimeLog dataTypes do not have a default render template. If you need to render attributes values with these data types, register a custom column template for them or use column slots. You should decide to display this column type with great caution because this column can create large server requests

# computedVuex static

See module:formHelpers.computedVuex

# dialog : uDialogs.dialog static

Show modal dialog with 3 optional button and text/html content, see uDialogs.dialog

# dialogError : uDialogs.dialogError static

Error dialog, see uDialogs.dialogError

# dialogInfo : uDialogs.dialogInfo static

Information dialog, see uDialogs.dialogInfo

# dialogYesNo : uDialogs.dialogYesNo static

Confirmation dialog, see uDialogs.dialogYesNo

# errorReporter : uDialogs.errorReporter static

Error reporter dialog, see uDialogs.errorReporter

# fileActions : fileActions static

Helper functions for creating files in a specific way: with dictaphone or webcam help

# fileRendererFactory static

Factory for registering file renderers by MIME type, used by UFileRenderer. type {import('../components/controls/UFile/views/rendererFactory').RendererFactory}

# fileRendererMixin static

Mixin for components used in fileRendererFactory for rendering file of some MIME type.

# filterTemplateMixin static

Mixin for reusing common logic needed for registering custom UTableEntity filter templates components

# Form static

Creates a new instance of UI module. See module:Form.Form

# formHelpers : formHelpers static

Helper functions for forms. See module:formHelpers. mapInstanceFields and computedVuex are aliased into @unitybase/adminui-vue

# lookups : lookups static

A reactive (in terms of Vue reactivity) entities data cache. See examples in lookups module documentation

# mapInstanceFields static

See module:formHelpers.mapInstanceFields

# mountUtils : mountUtils static

Mount a Vue based component as a navbar tab, a modal form or inside other component (as a container). See mountUtils module documentation for samples.

# pdfViewerExtensions : pdfViewerExtensions static

Registry for PDF viewer extensions. External packages can register toolbar buttons, event handlers and other enhancements for UPdfViewerExt without modifying the component source code.

# richTextEditorConfigurator : richTextEditorConfigurator static

The module provides the ability to extend default CSS styles, fonts, .etc for the rich text editor (tinymce)

# syncIsCollapsedWithExt static

Function for synchronizing between sidebar size and EXT body width needed if need to override sidebar component

# throttleDebounce : Object static

throttle-debounce see original doc

# tinyMCEService : tinymceService static

Service for TinyMCE

# uDialogs : uDialogs static

Modal uDialogs (message boxes) for showing errors, information and confirmation For usage examples see uDialogs module documentation

# uiSettings : uiSettings static

Storage for User Interface settings. Wrapper around localStorage

  
      // inside vue can be used as this.$uiSettings
this.videoRatio = this.$uiSettings.get('UFileWebcamButton', 'videoRatio') ?? this.videoRatios[0]
this.$uiSettings.put(this.videoRatios[0], 'UFileWebcamButton', 'videoRatio')

// or from adminui-vue exports
const App = require('@unitybase/adminui-vue')
const isCollapsed = App.uiSettings.get('sidebar', 'isCollapsed')
  

# validationMixin static

Mixin for using in forms with own single-form validation. Mixin automatically creates and passes a validator instance for use in nested controls (UFormRow for example).

# webDav : webDav static

Open files using WebDav protocol (require @ub-e/web-daw to be added into application)

Methods

# sanitizeHtml (valuestring, configoptobject) static

Sanitize-html library with pre-defined basic config if not passed as second argument

Arguments:
  • value: string

    HTML code to e sanitized

  • config: object

    sanitize-html config. Default is BASIC_SANITIZE_CONFIG

Events

# 'applicationReady'  --> ()

Fires after application loads all models and mounts UI

# 'portal:loader'  --> ()

portal:loader event, which shall be set or remove global loader (overlay) over UI, so that user won't trigger action in the process loading, for example, big components over a poor network connection.

  
      try {
      $App.fireEvent('portal:loader', {
        text: 'portal.loader.form',
        show: true
      })

      // Do action which takes long.  Await for it, if just return unresolved promise, the "finally" block execute
      // before action finish
    } finally {
      // ALWAYS use try-finally to avoid loading overlay hanging in case of errors
      $App.fireEvent('portal:loader', {
        text: 'portal.loader.form',
        show: false
      })
    }
  

# 'portal:mountTableEntity:before'  --> (cfgobject, entityNamestring, continueboolean)

Fired before the showList (dictionary shown) command. Handler can cancel command by set params.continue = false

  
      window.$App.on('portal:mountTableEntity:before', (params) => {
    if (params.entityName.startsWith('org_') && !$App.connection.userData.hasRole('LocalOrgManager')) {
      params.continue = false // prevent show dictionary
      $App.dialogError('recordNotExistsOrDontHaveRights')
    }
  })
  
Arguments:
  • cfg: object

    Config, passed to showList

  • entityName: string

    Name of entity command runs for

  • continue: boolean

    Initial value is true. Event handler can set is ot false to prevent command execution

# 'portal:navbar:defineSlot'  --> ()

Additional components can be added to the Sidebar and NavBar using this event

  
      window.$App.on('applicationReady', () => {
    const SidebarSlotExample = require('./samples/SidebarSlotExample.vue').default
    $App.fireEvent('portal:sidebar:defineSlot', SidebarSlotExample, { some attrs })

    const NavBarSlotExample = require('./samples/NavbarSlotExample.vue').default
    $App.fireEvent('portal:navbar:defineSlot', NavBarSlotExample, { some attrs })
  }
  

# 'portal:navbar:userButton:appendSlot'  --> (ComponentComponent, bindingsobject, slotNameoptstring.<('menuAppend' | 'logoutAppend' | 'logoutPrepend')>)

Insert some elements into user menu

  
      Vue.nextTick(() => {
    const UserButtonSelectDepartment = require('./components/UserButtonSelectDepartment.vue').default
    $App.fireEvent('portal:navbar:userButton:appendSlot', UserButtonSelectDepartment, {})
  })
  
Arguments:
  • Component: Component
  • bindings: object
  • slotName = 'default': string.<('menuAppend' | 'logoutAppend' | 'logoutPrepend')>

    supported values: 'menuAppend', 'logoutAppend', 'logoutPrepend'

# 'portal:resetUI'  --> ()

Fired when globally resetting UI settings (not for an individual component or property). Handlers can do custom reset UI actions, possible for keys, which do not start with portal:

# 'portal:sidebar:desktopChanged'  --> (desktopIDnumber)

Fired on desktop changed

Arguments: