Example WIP
Usage
WUI log components are intended to display wescale logs of different types (e.g., audit, protocol) in a uniform table-like UI. Especially in the management area, we use audit logs for almost every item. It is a valuable resource for gaining insights for helpdesk staff, developers, and administrators who want to investigate suspicious activity or diagnose and fix issues.
Anatomy
Audit log

- Headline + counter. The counter shows the total number of all entries, even if they are loaded asynchronously when scrolling.
- Date & time. Use the
medium
date and time format at this point. You can find more information on that here. - Log message. The text always follows the same pattern. The "objects" of the sentence are written bold for better scannability. For more information about highlighting text, click here.
- Scrollbar. The scroll bar is essential for components where infinite scrolling is used. It serves as a visual cue to the user that there is more content than is currently displayed.
Protocol log
The protocol log component is based on the audit log component and uses a similar structure and the same functionality. Furthermore, there is the possibility of evaluating the severity of an entry.

- Severity filter. The user can use this multi-select dropdown to limit the selection of items displayed.
- Search. All entries can be searched, even those loaded later while scrolling.
- Severity label. To determine the severity of an entry we use the following labels and icons:
TRACE: Coloractive
, Typeinverted
, Iconfa-star-of-life
INFO: Colorhighlight
, Typeinverted
, Iconfa-info
DEBUG: Colorhighlight
, Typeinverted
, Iconfa-bug
WARNING: Colorwarning
, Typeinverted
, Iconfa-exclamation
ERROR: Colordanger
, Typeinverted
, Iconfa-exclamation
x 2
WUI decisions 
- Widths. The section for logs is almost always related to other sections. For the width of the time and date column, we ensure that the alignment is analogous to the labels from the other sections. Mostly - but not always - the TD has the width
col-sm-3
.
import { WuiAuditLog, WuiProtocolLog } from "@wui/wui-vue/lib/log";
Description
WUI log components are intended to display wescale logs of different types (e.g. audit, protocol) in a uniform table-like UI. The components support infinite scrolling by default and automatically reload newer entries. Since WUI log components use a
<wui-table />
, many of the functions & features are identical. Read below for more details.
Log component types
The following log components are currently available:
<wui-audit-log>
- displays audit log data<wui-protocol-log>
- displays job protocol data
Each of these components has its own table template and receives different table items (via your items provider function), whereby the basic functionality always remains the same. Therefore all props
are identical.
Basic usage
<template>
<div>
<wui-audit-log
:items="itemsProvider"
:total="itemsTotal"
:per-page="perPage"
/>
<!-- or -->
<wui-protocol-log
:items="itemsProvider"
:total="itemsTotal"
:per-page="perPage"
/>
</div>
</template>
<script>
export default {
data() {
return {
mockItemsAudit: [],
mockItemsProtocol: [],
currentPage: 1,
// initial # of items
perPage: 50,
// # of items per reload
perReload: 10,
// total # of all logs available in the db (required)
itemsTotal: 0,
initialized: false,
};
},
created() {
for (let i = 1, i <= 100, i++) {
this.mockItemsAudit.push(
{
"created_at": "2021-10-24T18:18:05.973Z",
"description": "dictum ultricies ligula. Nullam enim. Sed nulla ante, iaculis nec,"
},
)
this.mockItemsProtocol.push(
{
"severity": "INFO",
"created_at": "2021-10-24T18:18:05.973Z",
"description": "dictum ultricies ligula. Nullam enim. Sed nulla ante, iaculis nec,"
},
)
}
},
methods: {
itemsProvider(ctx) {
const { filter, perPage, scrollBottomTriggerCounter } = ctx;
// First call is made with `perPage`, all subsequent calls will use `perReload`
const numberOfItems = this.initialized ? this.perReload : perPage;
const params = {
offset: Math.max(
0,
perPage + scrollBottomTriggerCounter * numberOfItems - numberOfItems,
limit = parseInt(offset) + parseInt(numberOfItems);
),
limit: parseInt(offset) + parseInt(numberOfItems);
}:
const { items, total } = this.fetchItems(params);
this.initialized = true;
this.itemsTotal = total;
return items;
},
async fetchItems(params) {
try {
// You need to call your API here
const items = this.mockItemsAudit || this.mockItemsProtocol;
const { offset, limit } = params;
const res = {
items: items.slice(offset, limit),
total: items.length,
};
return res;
} catch (error) {
console.error("Error while fetching logs: ", error);
return [];
}
},
},
};
</script>
<!-- wui-log.vue -->
Items
items
is the table data in array format, where each record (row) data are keyed objects which has to be in the following format:
Audit log items
const logItems = [
{
// mandatory keys
created_at: "2021-10-24T18:18:05.973Z",
description: "dictum ultricies ligula",
// ... optional keys - the log component will not use them
},
{
created_at: "2021-10-23T18:18:05.973Z",
description: "ac tellus. Suspendisse sed",
},
{
created_at: "2021-10-22T18:18:05.973Z",
description: "nibh. Donec est mauris",
},
];
Protocol items
const logItems = [
{
// mandatory keys
severity: "INFO",
created_at: "2021-10-24T18:18:05.973Z",
description: "dictum ultricies ligula",
// ... optional keys - the log component will not use them
},
{
severity: "TRACE",
created_at: "2021-10-23T18:18:05.973Z",
description: "ac tellus. Suspendisse sed",
},
{
severity: "WARN",
created_at: "2021-10-22T18:18:05.973Z",
description: "nibh. Donec est mauris",
},
];
Log items - using items provider functions
In order to provide the log data (items) you need to use a provider function, by specifying a function reference via the items
prop.
The provider function is called with a context signature which contains all the ctx
properties from <wui-table>
.
See the <wui-tables>
docs for further information on how to use the provider function.
Example: returning an array of log items (synchronous):
function myProvider() {
let items = [];
// Perform any items processing needed
// Must return an array
return items || [];
}
Example: Using callback to return log items (asynchronous):
function myProvider(ctx, callback) {
const params =
"?page=" + ctx.scrollBottomTriggerCounter + "&size=" + this.perReload;
this.fetchData("/some/url" + params)
.then((data) => {
// Pluck the array of items off our axios response
const items = data.items;
// Provide the array of items to the callback
callback(items);
})
.catch(() => {
callback([]);
});
// Must return null or undefined to signal wui-log that callback is being used
return null;
}
Example: Using a Promise to return log items (asynchronous):
function myProvider(ctx) {
const promise = axios.get(
"/some/url?page=" +
ctx.scrollBottomTriggerCounter +
"&size=" +
this.perReload
);
// Must return a promise that resolves to an array of items
return promise.then((data) => {
// Pluck the array of items off our axios response
const items = data.items;
// Must return an array of items or an empty array if an error occurred
return items || [];
});
}
Example: Using an async function (semi-synchronous):
async function myProvider(ctx) {
try {
const response = await axios.get(
`/some/url?offset=${ctx.scrollBottomTriggerCounter}&limit=${this.perReload}`
);
return response.items;
} catch (error) {
return [];
}
}
Infinite scrolling
WUI Log components has enabled infinite scrolling of items. You can control how many rows are initially displayed by setting the perPage
prop to the maximum number of rows you would like displayed. Your items provider function is responsible for reloading the desired number of items for all subsequent requests. To calculate the correct limit, you can use the wui-table
context variable ctx.scrollBottomTriggerCounter
, or you can use your own calculation. WUI Log components automatically ensure that the provider function is triggered when the end of the table has been reached.
v-model
binding
If you bind a variable to the v-model
prop, the contents of this variable will be the currently displayed item records. This variable (the value prop) should usually be treated as readonly (see <wui-tables>
docs).
Automated busy states
WUI Log components automatically track / control their busy
state when items provider functions are used (same as with <wui-table>
). In contrast to <wui-table>
, WUI Log components do not offer a busy
prop to overwrite the busy
state or to control it yourself.
Fixed height
To enable infinite scrolling, the WUI Log components generate a <wui-table>
with a maximum height of 300px
.
To specify a maximum height other than 300px, set the table-height
prop to a valid CSS height (including units), i.e. table-height="400px"
.
Render HTML tags
By default, no HTML tags that could be in the description
are rendered. If your log data contains HTML, which the log component should render, then the property renderHtml
must be set totrue
.
Caution: With renderHtml
enabled the component is using innerHTML
to insert the description which can be vulnerable to Cross Site Scripting (XSS) attacks. Make sure the data is properly sanitized in the backend! This component also sanitizes the description with DOMPurify.
Log helper components
WuiVue provides for each log type additional helper child components:
wui-audit-log-header
wui-audit-log-body
wui-protocol-log-header
wui-protocol-log-body
They are mainly intended to integrate a WUI Log component within an existing <wui-panel>
in your app. The WUI log components use these two child components internally and wrap them in a<wui-panel
>.
However, this can lead to a problem if you already have a <wui-panel>
and want to insert the WUI Log component there. To avoid a double <wui-panel>
container within an existing <wui-panel>
, you can simply use the default
slot together with the log header and body child components.
Here is an example of audit logs:
<template>
<div>
<wui-panel>
<!-- ... here is you own content ... -->
<!-- Now you include the Logs within your wui-panel -->
<wui-audit-log
:items="itemsProvider"
:total="itemsTotal"
:per-page="perPage"
>
<!-- The default slot with scoped properties -->
<template #default="{ bodyProps, bodyEvents, headerProps }">
<!-- You need to pass the scoped properties to these child components -->
<wui-audit-log-header v-bind="headerProps" />
<wui-audit-log-body v-bind="bodyProps" v-on="bodyEvents" />
</template>
</wui-audit-log>
</wui-panel>
</div>
</template>
<script>
export default {
data() {
return {
mockItems: [],
currentPage: 1,
perPage: 50,
perReload: 10,
itemsTotal: 0,
initialized: false,
};
},
created() {
for (let i = 1, i <= 100, i++) {
this.mockItems.push(
{
"created_at": "2021-10-24T18:18:05.973Z",
"description": "dictum ultricies ligula. Nullam enim. Sed nulla ante, iaculis nec,"
},
)
}
},
methods: {
itemsProvider(ctx) {
const { filter, perPage, scrollBottomTriggerCounter } = ctx;
// First call is made with `perPage`, all subsequent calls will use `perReload`
const numberOfItems = this.initialized ? this.perReload : perPage;
const params = {
offset: Math.max(
0,
perPage + scrollBottomTriggerCounter * numberOfItems - numberOfItems,
limit = parseInt(offset) + parseInt(numberOfItems);
),
limit: parseInt(offset) + parseInt(numberOfItems);
}:
const { items, total } = this.fetchItems(params);
this.initialized = true;
this.itemsTotal = total;
return items;
},
async fetchItems(params) {
try {
// You need to call your API here
const items = this.mockItems;
const { offset, limit } = params;
const sliceLimit = parseInt(offset) + parseInt(limit);
const res = {
items: items.slice(parseInt(offset), sliceLimit),
total: items.length,
};
return res;
} catch (error) {
console.error("Error while fetching logs: ", error);
return [];
}
},
},
};
</script>
<!-- wui-audit-log-default-slot.vue -->
Force refreshing of log data
You may trigger the refresh of the provider function by calling the refresh()
method on the log component reference
<div>
<wui-audit-log ref="audit-log" ... />
</div>
When using the child components in the log default slot the refresh is only working on the log-body component reference:
<!-- Or when using the log helper components -->
<div>
<wui-audit-log>
<wui-audit-log-header />
<wui-audit-log-body ref="audit-log" />
</wui-audit-log>
</div>
this.$refs["audit-log"].refresh();
Component reference
<wui-audit-log>
and <wui-protocol-log>
The following <wui-table>
props are supported:
- apiUrl
- items
- perPage
- tableClass
- value
See the <wui-tables>
docs for further information about these props.
Properties
Property | Type | Default | Description |
---|---|---|---|
fieldProps | Object | null | Object with wui-table field definitions you can use to pass field props to the underlying wui-table component (see 'Field definition reference' in wui-table docs). Usefull to provide custom CSS classes for table cells fieldProps: { description: { tdClass: 'my-custom-css-class' } } |
perPage | Number or String | 50 | Number of rows to show at the beginning. This prop is used in wui-table but set to 50 by the WUI log component |
renderHtml Use with caution | Boolean | false | Whether the component should process HTML tags in the description or not (security risk) |
tableHeight | String | '300px' | Set the height of the log table by any valid CSS height (including units) |
total | Number or String | The total number of all log items in your database that could theoretically be loaded by infinite scrolling (required) | |
translations | Object | see translations.js | The translation object to pass custom texts title |
Slots
Name | Scope | Description |
---|---|---|
default | Yes, see below | Content to place in the component |
Default slot scope:
Prop | Type | Description |
---|---|---|
allProps | Object | All the props of this component |
bodyProps | Object | All the props you need to pass via v-bind to the wui-audit-log-body component |
bodyEvents | Object | All the events you need to pass via v-on to the wui-audit-log-body component |
headerProps | Object | All the props you need to pass via v-bind to the wui-audit-log-header component |
Events
All events from <wui-table>
are supported. You might be interested in the scroll-bottom
event.
See the <wui-tables>
docs for further information about events.
<wui-audit-log-header>
and <wui-protocol-log-header>
It's recommended to not use these properties directly, but to use the scoped prop
headerProps
from thedefault
slot of WUI log main instead. TheheaderProps
prop includes all of the following props.
Properties
Property | Type | Default | Description |
---|---|---|---|
initialized | Boolean | false | When set to true , it deactivates the initial loading skeleton of the log component and displays the items |
total | Number or String | The total number of all log items in your database that could theoretically be loaded by infinite scrolling | |
translations | Object | see translations.js | The translation object to pass custom texts title |
Slots
Name | Scope | Description |
---|---|---|
default | Yes, see below | Content to place in the log header |
Default slot scope:
Prop | Type | Description |
---|---|---|
allProps | Object | All the props of this component |
computedTitle | String | The computed title containing title and eg. the total of items |
<wui-audit-log-body>
and <wui-protocol-log-body>
It's recommended to not use these properties directly, but to use the scoped prop
bodyProps
from thedefault
slot of WUI log main component instead. ThebodyProps
prop includes all of the following props.
The following <wui-table>
props are supported:
- apiUrl
- items
- perPage
- tableClass
- value
See the <wui-tables>
docs for further information about these props.
Properties
Property | Type | Default | Description |
---|---|---|---|
fieldProps | Object | null | Object with wui-table field definitions you can use to pass field props to the underlying wui-table component (see 'Field definition reference' in wui-table docs). Usefull to provide custom CSS classes for table cells fieldProps: { description: { tdClass: 'my-custom-css-class' } } |
initialized | Boolean | false | When set to true , it deactivates the initial loading skeleton of the log component and displays the items |
perPage | Number or String | 50 | Number of rows to show at the beginning. This prop is used in wui-table but set to 50 by the WUI log component |
renderHtml Use with caution | Boolean | false | Whether the component should process HTML tags in the description or not (security risk) |
tableHeight | String | '300px' | Set the height of the log table by any valid CSS height (including units) |
total | Number or String | The total number of all log items in your database that could theoretically be loaded by infinite scrolling (required) | |
translations | Object | see translations.js | The translation object to pass custom texts title |
Events
All events from <wui-table>
are supported. You might be interested in the scroll-bottom
event.
See the <wui-tables>
docs for further information about events.
It's recommended to use the scoped prop
bodyEvents
from thedefault
slot of the WUI log main component instead. ThebodyEvents
prop includes all of events you have bound to the WUI log body component.
Importing individual components
You can import individual components into your project via the following named exports:
Component | Named Export |
---|---|
<wui-audit-log> | WuiAuditLog |
<wui-protocol-log> | WuiProtocolLog |
Helper components
Component | Named Export |
---|---|
<wui-audit-log-body> | WuiAuditLogBody |
<wui-audit-log-header> | WuiAuditLogHeader |
<wui-protocol-log-body> | WuiProtocolLogBody |
<wui-protocol-log-header> | WuiProtocolLogHeader |
Example
import {
WuiAuditLog,
WuiAuditLogBody,
WuiAuditLogHeader,
WuiProtocolLog,
WuiProtocolLogBody,
WuiProtocolLogHeader,
} from "@wui/wui-vue/lib/log";
Vue.component("wui-audit-log", WuiAuditLog);
Vue.component("wui-audit-log-body", WuiAuditLogBody);
Vue.component("wui-audit-log-header", WuiAuditLogHeader);
Vue.component("wui-protocol-log", WuiProtocolLog);
Vue.component("wui-protocol-log-body", WuiProtocolLogBody);
Vue.component("wui-protocol-log-header", WuiProtocolLogHeader);