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.