Web components are plain javascript elements which are introduced in order to achieve:
Web components are created in separate repositories, with separate Angular projects for every web component. Projects are separated into two repositories:
Accordingly web-components will be deployed to the non-gxp or gxp node of DCP.
The @angular/elements library is used to register every web component in window object. Details can be found here or here The compiled web components neither use NGRX Store, or session/local store, but instead they work as a black box with @Inputs/@Outpus.
To add unique identifications for every one component @angular-builders/custom-webpack and custom-webpack configs are used. This allows to use more than one Angular web components inside the apps The build process for every web component includes standard ng build and a gulp bundle task, which concatenates the files into a single JS file.
The built JS file is imported into the base app index.html, and use of the registered tag. See the example below:
<script type="text/javascript" src="./web-components/mvda/dashboard-model-presentation/dashboard-model-presentation.js"></script>
<dc-model-presentation-view></dc-model-presentation-view>
This section briefly describes the available components and how to use them.
The TimeRangeComponent is styled and ready to use time range web component based on @danielmoncada/angular-datetime-picker It extends the component with the following:
All inputs and outputs of the component use UTC date time strings. The visualization of the date is based on given UTC dates and given timezone.
The component javascript is loaded inside DCP Base App to be used inside Angular and VueJS application(s). The component emits a custom event timeRangeChange which other parts of the application can subscribe to, the selected time is delivered in the event details.
Attributes
| Name | Type | Default | Description |
|---|---|---|---|
language |
string | en |
Current language code, used to switch implemented translations. Currently implemented languages codes are en and de for English and German. |
timezone |
string | Europe/Berlin |
Timezone identifier used by moment-timezone for properly show dates if there is an date offset. |
timeRange |
ITimeRange | {StartTime: moment().subtract(4, 'hours').toISOString(), EndTime: moment().toDate().toISOString()} |
Preselected time range class with start and end time |
placeholder (optional) |
string | Select time range translated on current language (en/de) |
String to be used as a input label. |
minmax (optional) |
ITimeRange | undefined |
Time range class used to set up min and max selectable dates. When is not used, min date will not be set, and max date will be set to current time. |
disabled (optional) |
boolean | false |
Change Time Range component disable state |
showPredefinedPeriods (optional) |
boolean | true |
Show/hide predefined periods selectors |
listedPeriods (optional) |
predefinedPeriodsTypes[] | ['Today','Yesterday', 'CurrentWeek','PreviousWeek', 'CurrentMonth','PreviousMonth', 'CurrentQuarter','PreviousQuarter', 'CurrentYear','PreviousYear'] |
List of predefined options to be shown to user. |
Events
| Name | Type | Description |
|---|---|---|
timeRangeChange |
EventEmitter<{StartTime: string; EndTime: string;}> |
Return time range class after time range selection |
Types and Models
| Name | Value |
|---|---|
predefinedPeriodsTypes |
'Today', 'Yesterday', 'CurrentWeek', 'PreviousWeek', 'CurrentMonth', 'PreviousMonth', 'CurrentQuarter', 'PreviousQuarter', 'CurrentYear', 'PreviousYear', 'Last2Years', 'Last3Years' |
ITimeRange |
{StartTime: string; EndTime: string;} |
Usage
Because TimeRangeComponent is Web Component timeRangeChange create CustomEvent. This way the data that will be received is inside $event.detail;
<dcp-time-range [language]="uiFacade.language$ | async"
[timezone]="uiFacade.siteTimeZoneName$ | async"
[timeRange]="timeRange"
[disabled]="uiFacade.isLoading$ | async"
(timeRangeChange)="timeRangeChanged($event.detail)">
</dcp-time-range>
class Component {
timeRange = {
StartTime: moment().subtract(4, 'hours').toISOString(),
EndTime: moment().toDate().toISOString()
};
timeRangeChanged(data: ITimeRange) {
console.log(data.detail);
// This will print something like
// {StartTime: '2023-08-24T08:51:31.000Z', EndTime: '2023-08-24T11:51:31.000Z'}
}
}
Inside VueJS the comonent can be used as following:
<dcp-time-range :language="store.state.ui.language"
:timezone="store.state.ui.timeZoneName"
:disabled="disabled"
:timeRange="timeRange"
ref="timeRangeEl">
</dcp-time-range>
mounted() {
(this.$refs.timeRangeEl as HTMLElement)?.addEventListener('timeRangeChange', this.timeRangeChanged);
}
unmounted() {
(this.$refs.timeRangeEl as HTMLElement)?.removeEventListener('timeRangeChange', this.timeRangeChanged);
}
timeRangeChanged(data: any) {
console.log(data.detail);
// This will print something like
// {StartTime: '2023-08-24T08:51:31.000Z', EndTime: '2023-08-24T11:51:31.000Z'}
}
The purpose of User Info Banners is to show user information (e.g. system downtime, new updated functionality etc.). The visualization is similar to the one that can be found in many other systems like GitLab. The implementation of banners is split inside two applications - Administration and Base, and WebComponents where is situated User Banner Info web component.
Inside the Administration application all CRUD operations are implemented (responsible for visualize list, edit, create, delete and also activate or deactivate banners). UserInfoBannersComponent is responsible to show User Info Banners to end users by making API call from component to UserInfoBanner/GetAllActiveBanners. To ensure that users will see new banners, a API call is performed every 5 minutes, to updated available banners. Closed banners are stored in the localStorage, so that they are no visible on re-load.
Attributes
| Attribute | Data type | Description |
|---|---|---|
| Id | number |
|
| Name | string |
Name that is visible for administration purpose |
| Category | number |
Used for different UI styles. Info = 1, Downtime = 2, Error = 3 |
| Description | string |
This field is used as a banner text visualization |
| IsActive | boolean |
Is the banner active or not |
| StartTime | string |
Start time for the banner visualization in UI |
| EndTime | string |
End time for the banner visualization in UI |
| SiteId (optional) | number |
If is presented the banner will be visible only for selected Site |
| ModuleName (optional) | string |
If is presented the banner will be visible only for selected Module |
| LastModifiedAt | string |
Time of last edit |
| LastModifiedBy | string |
User name of the user that made the last edit |
Usage
UserInfoBannersComponent is responsible to show User Info Banners to end users by making
API call from component to UserInfoBanner/GetAllActiveBanners.
To achieve that we need to know to which server we need to make this API call.
Because UserInfoBannersComponent is a WebComponent and it is not part of the building process for any application,
we get that information with @Input baseUrl.
To be sure that user will see new banners we make API call every 5 minutes, to updated available banners.
User have available close button for every banner, that will add banner Id to localStorage.dcpDisabledBanners list.
We use localStorage to save this data, to be sure, that on browser refresh user will not see again same browser.
dcpDisabledBanners list and banners ModuleName, SiteId, StartTime and EndTime are used to filter visible for
user banners in the UI, based on user activity, current time and current url.
fillActiveBanners(): void {
const currentSite = this.getCurrentSite();
const currentModule = this.getCurrentModule();
this.activeBanners = [...this.banners.filter(b => {
const disabledBanners = this.getDisabledBanners();
const start = moment(b.StartTime);
const end = moment(b.EndTime);
const current = moment();
return current.isBetween(start, end)
&& !disabledBanners.includes(b.Id)
&& (!b.ModuleName || b.ModuleName === currentModule)
&& (!b.SiteId || b.SiteId.toString() === currentSite);
})];
}
index.html file in Base Application import UserInfoBannersComponent as a web component, display it and set base-url
to be used to get available User Info Banners.
<script type="text/javascript"
src="https://domain.com/web-components/shared/dcp-user-info-banners/dcp-user-info-banners.js">
</script>
<dcp-user-info-banners base-url="https://dc-dev-gxp.domain.com"></dcp-user-info-banners>
erDiagram
UserInfoBanner {
int(4) ID "UniqueId"
nvarchar Name "The name used by the admins for easy identification"
tinyint(1) Category "The catregory (Downtime/etc. used for the styling of the banner)"
nvarchar Description "The description/info text shown to the users"
bit(1) IsActive
datetime(8) StartTime "The start of the period where this banner should be shown (UTC)"
datetime(8) EndTime "The end of the period where this banner should be shown (UTC)"
int(4) LastModifiedBy
int(4) OwnerUserId
datetime2(8) SysStartTime
datetime2(8) SysEndTime
int(4) SiteId "If set the banner will be only shown to users in the context of this production site"
nvarchar ModuleName "If set the banner will be only shown to users in the context of this module"
}
Records classification and audit trail
| Specification | Value |
|---|---|
| Content/Overview | The configured banners |
| Data classification | Convenience records |
| Change Tracking | SystemVersioned table features inside SQL |
| Audit Trail | N/A |
| Retention period | 3 years |
Quill Text Editor component is a wrapper of ngx-quill. This way the same visual and functional Rich text editor can be used inside the different javascript frameworks (e.g. Angular an VueJS).
Usage
<dcp-quill-text-editor [value]="initialValue"
(updateValue)="updateValue($event)">
</dcp-quill-text-editor>
Attributes
| Name | Type | Data type | Description |
|---|---|---|---|
| control | Input | FormControl |
Used if we need to connect the editor with existing Angular FormControl |
| value | Input | string |
Initial value |
| updateValue | Output | string |
Event triggered when value is updated. |
This ModelPresentationViewComponent is designed to present data in a chart format, considering various attributes like timezone, validation status, and user-specific settings.
The component javascript is loaded inside DCP Base App to be used inside Angular and VueJS application(s). The component emits a custom event timeRangeChange which other parts of the application can subscribe to, the selected time is delivered in the event details.
Attributes
| Name | Type | Default | Description |
|---|---|---|---|
chart |
DashboardListResponseModel | A data configuration for the chart to be displayed. | |
limits |
LimitsModel[] | An object defining the limit lines for the chart. | |
timezone |
string | Timezone identifier used by moment-timezone for properly show dates if there is an date offset. | |
isValidated |
boolean | A boolean indicating whether the data presented in the chart has been validated. | |
translations |
TranslationsModel | An object containing key-value pairs for multi-language support. | |
userSettings |
{dateFormat: string; timeFormat: string;} | An object that includes user-specific settings for date and time formats. | |
height (optional) |
number | null | A numeric value (in pixels) defining the height of the component. If empty the height will be set to auto. This allows for a flexible layout that adapts to different screen sizes and container dimensions. |
Events
| Name | Type | Description |
|---|---|---|
navigateToData |
EventEmitter<DashboardListResponseModel> |
Return chart object after navigate to is triggered |
Usage
Allow Custom elements scheme: First, allow custom element scheme in the module that will use the ModelPresentationViewComponent component.
...
schemas: [CUSTOM_ELEMENTS_SCHEMA]
...
Component Setup: In your dashboard view, set up the ModelPresentationViewComponent component by passing the required attributes.
<dc-model-presentation-view
chart={}
limits={}
timezone="Europe/Berlin"
isValidated={true}
translations={
TOOLTIP: "",
NUMBER_OF_VIOLATIONS: "",
LAST_RESET_TIME: "",
UNDEFINED: "",
CONDITIONS: "",
VIOLATION_IN_ROW: "",
VIOLATION_NUMBER: ""
}
userSettings={
dateFormat: 'YYYY MMM dd',
timeFormat: 'hh:mm:ss'
}
height={300}></dc-model-presentation-view>
Data Handling: Ensure that the data passed to the chart attribute is in the correct format. Fetch or compute the data as necessary.
Dynamic Properties: Utilize state management or props to dynamically update the attributes like isValidated translations or userSettings based on user interactions or data changes.