This library provides reusable components for use inside the SRS **Umbrella UI,** a complex customer-facing frontend appllication that employs native module federation and microfrontends.
npm install umbrella-libraryThis library provides reusable components for use inside the SRS Umbrella UI, a complex customer-facing frontend appllication that employs native module federation and microfrontends.
This library was originally generated with Angular CLI version 12.2.0.
----
[TOC]
To install and run this application locally, you need to have NodeJS installed at a version of 10.0 or greater.
To complete installation and run the app locally, please follow these instructions.
This is an NPM library located at [https://www.npmjs.com/package/umbrella-library]() that should be installed via npm install umbrella-library locally in an MFE (microfrontend).
/lib - This is where the exportable library files and features are.
- /lib/public-modules - Place all components and services that will be made publicly available from this library here
- /lib/public-api.ts - List all exported components and services here.
Below is a list of the @input parameters the component can handle for customization and configuration:
* label: _string_ - A unique name and ID for the data-table
* columns: _dataTable_[] - An array of columns, each of type DataTableColumn, specifying the columns of data to display
* records: _any_[] - The array of data objects that are to be displayed.
* totalRecordsCount: _number_ - The number of records returned and sent to the data table.
* customCellTemplateRef: _TemplateRef_ Described below.
* customNoDataTemplateRef: _TemplateRef_ A template that can be used to customize what user sees when there is no data returned.
* showBorderFrame: _boolean_ - Display the table inside a "card" look with 24px spacing around it.
* allowHideColumns: _boolean_ - Show/Hide a dropdown that allows users to show and hide certain columns in the table. (Each column that can be hidden must be marked hideable: true)
* showDownloadButton: _boolean_ - Show/Hide download csv button
* downloadFileName: _string_ - Downloaded csv file name
* rowSpacing: _string_ - Can be set to 'wide' or 'compact' to configure the vertical padding of the rows in the table.
* readonly: _boolean_ - Whether the table should provide user interaction. A true value disables interactivity.
* pageSize: _number_ - The number of records to be displayed per page by default prior to user interaction.
* pagination: _string_ - Can be set to 'infinite' or 'normal' or 'none' to control pagination. For use of 'infinite' to implement Infinite Scroll, see the documentation below.
* internalFiltering: _boolean_ - Enable filtering with the API, used in conjunction with filtering: true and filterOperators set on individual columns.
* filterList: _DataTableFilter_[] - The filters selectable in your data table, passed in as an array of DataTableFilter objects.
* searchable: _boolean_ - Whether or not the table should offer a search bar
* selectable: _boolean_ - Whether or not the table should offer an ID column of checkboxes, enabling multi-select of the rows of the table
* selectedRecordSet: _Set_ - The set of records currently selected.
* sortingMode: _string | null_ - Which type of sorting, if any, that the table should offer. If set to frontend, any columns to offer sorting must be configured with a sortFn property that is either alphabetical, numerical or a custom nzTableSortFn function that takes two params and returns -1, 0, or 1. If set to backend, all sortable columns should have sortFn set to true, and the API integrated with this table should handle sortField and sortOrder in the fetchEvent when it makes its requests.
* selectedRecordSet: _Set_ - The set of records currently selected.
* selectRecord(): _function_ - An EventEmitter and callback used when user selects a record. Should be used with selectable
* fetchRecords(): _function_ - This is the required EventEmitter function used to fetch the records from the service in the MFE
Ant Design table data unless a format field is present when the column is defined, or a cellTemplateRef is used. If a format field is defined, these are the options: * date - Data will be displayed in the table as a date.
* dateTime - Data will appear in the table with both date and time displayed.
* currency - Data will appear formatted as currency, defaulting to US dollar format.
* twoFields - Two fields will be concatenated as strings. Useful to display a full name, for instance.
* boolean - A boolean data field will be displayed with one of two defined strings, depending on whether the data is true or false.
label - Data can be displayed as colored labels. Pass into the format object format.type = 'label' and a format.labels object with key(s) that are the value(s) you want to display labels for, and the value(s)* are mini-objects containing labelText and labelColor for each value. The colors currently available are green, red and gray.
* lookupTable - A data table can be used to display text depending on the data for each row. This data table can be loaded asynchronously in the makeLookupTables() component function.
* image - An image can be displayed, as defined in the format.src field.
format option above, a custom TemplateRef can be passed by name from the parent in the MFE using customCellTemplateRef.
Example:
``html
let-record="data">
{{record.fleet.name}}
$3
Infinite scroll will be implemented when pagination is set to 'infinite'. In this case, pageSize should then be set to a much higher number (500 or 1000 is recommended) than what would normally be used with 'normal' pagination. pageSize will control how much data is fetched at once, not how much is visible to the user.This implementation of Infinite Scroll is a hybrid approach, using both virtual scrolling with DOM Swapping in the frontend while also fetching additional pages of data for very large datasets. If the
pageSize is set to the recommended value of 1000, for instance, a dataset with fewer than 1000 records will be loaded locally and virtual scroll will be used to smooth scrolling and prevent hammering browser memory usage. For larger datasets, the same will happen and then additional records will be fetched 1000 records at a time as the user scrolls deep into the dataset. Note that when implementing Infinite Scroll, the component function in your microfrontend that loads data and sets the bound properties for
records and totalRecordCount must have a stanza that will recognize infiniteScroll on the fetchRecordsEvent and append rather than replace the records. The use of concat() or another function that creates a new array is recommended in your component to trigger change detection, like this: `
...fetch data...
.subscribe((data: any) => {
this.totalItems = data.totalRecords;
if (fetchRecordsEvent.infiniteScroll) {
/ Append records rather than replace /
this.sessions = this.sessions.concat(data.sessionDetailList);
} else {
this.sessions = data.sessionDetailList;
}
`
And in the template:
`
[records]="sessions"
[totalRecordsCount]="totalItems"
[pageSize]="1000"
pagination="infinite"
`
## Header
This custom component displays the header for the MFE, including the name of MFE and any buttons on the top left.
The
@input parameters for this component: * title _string_ - The title of the entire application.
* subTitle: _string_ - A secondary title string.
* tags: _HeaderTag_[] - An array of tags for the header using
HeaderTag type
* primaryButton: _ActionButton_ - The primary button on the upper right.
* secondaryButtons: _ActionButton_[] - An array of ActionButton that will appear to the left of the primary button.
* ellipsisDropdownItems: _MenuDropdownItem_[] - Dropdown options.
* breadcrumbItems: _HeaderBreadcrumb_[] - Navigation breadcrumb links.
* navRoutes: _HeaderNavRoute_[]. If a route with children is included, the parent route will appear selected in the UI when the child route is loaded. ## Footer
* primaryButton: _ActionButton_ - An optional primary button in the footer.
* secondaryButtons: _ActionButton_[] - An array of
ActionButton that will appear to the left of the primary button.
## Error Interceptor
The Umbrella Error Interceptor handles automatic logout for expired tokens. It should be added to all MFEs.
To add it to a MFE, simply import it in whatever module imports the
HttpClientModule (probably the MFE's Shared or App module). 1. Add
HTTP_INTERCEPTORS to your import from Angular's http library
1. Add UmbrellaErrorInterceptor to your Umbrella Library import
1. In the Module configuration, use a providers property and add the Umbrella Error Interceptor
`
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';import {
UmbrellaHeaderModule,
UmbrellaFooterModule,
UmbrellaDataTableModule,
UmbrellaErrorInterceptor
} from 'umbrella-library';
@NgModule({
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: UmbrellaErrorInterceptor,
multi: true,
}
],
imports:
...
`
Note: If your MFE has its own Error Interceptor, you can simply add it as another stanza inside the providers array. Ensure both Interceptors stanzas have the multi:true property.Extending the Application
Contributing
To add new features or new components to this library:
1. Create a new directory in the
public-modules directory to host your new feature.
1. Create your components or services there with Code Scaffolding and ng generate commands, as [specified below.
1. Name your exported class the way you would like it be imported into our Umbrella microfrontends.
1. Write your code to customize your component.
1. Add a stanza in the /public-api.ts file to ensure the library will export your new feature.
1. Use the directions below and publish a new version to npm:
* Publish a minor version if the changes are not going to break or require changes in any other components.
* Publish as a new major version if there are breaking changes.
Whether you're adding new features or simply fixing bugs in this shared library, always:
* Write unit tests for your components.
* Use Prettier and utilize formatting and linting to add code that is compliant with the standards listed below.
* Follow the Git branching strategy below to create your branches.
* Write your Pull Request as specified below.
* Update this README if and when necessary!
* That's it! 🎉
Code Scaffolding
Run
ng generate component component-name --project umbrella-library to generate a new component. You can also use ng generate directive|pipe|service|class|guard|interface|enum|module --project umbrella-library.
-> Note: Don't forget to add --project umbrella-library or else it will be added to the default project in your angular.json file.
Code Formatting
This application requires well-formatted code. It is recommended you set up automated code formatting. The easiest way to do this is to simply configure your IDE to format files on every save as follows:
$3
Configure your IDE to run the
format:all command upon save. With VSCode, this can be done by installing a plugin such as RunOnSave. If you do install RunOnSave, simply add this configuration to your VSCode's settings.json:`
"emeraldwalk.runonsave": {
"commands": [
{
"match": ".*",
"cmd": "npm run format:all"
}
]
}
`$3
If you don't choose to set up auto-formatting, you can also manually format your code with :
- Prettier (TS, CSS). We use Prettier to format all files except for HTML (see below). Manually call
npm run format:prettier to format all TS, CSS, and config files inside the src directory. This command is an alias for npx prettier --write src, which you can also use if you prefer not to use the alias, and you can replace the src with a single file or directory, and the relevant file(s) will be formatted automatically according to our current prettier standards. You can replace the --write with --check to simply check formatting without making changes. There's also- JSBeautify (HTML). We use JSBeautify to format HTML files. You can use
npm run format:html to format all HTML files in the repository. You can also use npm run format:html-file [FILE] to format a single file._Run All Formatting_. Use
npm run format:all and all TS, CSS, and HTML files inside the src directory will be formatted automatically for you. This is command you should automate or run prior to creating your Pull Requests.
$3
In addition, the following npm script commands are available when working on this application:
- Code Formatting (HTML). Use
npm run format -- '[FILE]' on an HTML template file named FILE, and the file will be formatted automatically according to our current linting standards. You can also run npm run format: all to reformat all html files of the application at once.- Code Linting (TS). Use
npm run lint --files '[FILE]' on a TS script file named FILE to see lint errors for that file (but make no changes to it). Append --fix to this command to fix some of the issues automatically for you.
Git Branching Model
We use git to manage all of our development flow.
Please create branches and pull requests properly. Read our Git Branching Model to accomplish this. (That document is specific to the Driver Portal, but the model is the same for this application).
Generally code should be clear and not complex so that inline documentation and explanation is not necessary. However, whenever the code is complex or uses a solution or algorithm that will not be readily apparent to another engineer who might review or extend the code, always add comments explaining the solution or algorithm used.
/ / comment notation should be used for these explanatory comments.Code Comments
$3
Generally code should be clear and not complex so that inline documentation and explanation is not necessary. However, whenever the code is complex or uses a solution or algorithm that will not be readily apparent to another engineer who might review or extend the code, always add comments explaining the solution or algorithm used. / / comment notation should be used for these explanatory comments.$3
Code that is currently unneeded should generally be removed from the repository. There is no need to keep unused code as the git history will keep it. However, during initial buildout of features or when the API integration is unstable or not yet used, there will be times to temporarily commment out code. // comment notation should be used. This way code comments is immediately differentiated from unneeded code.$3
Tasks that should be completed soon and that are not captured in JIRA tickets can be noted with JSDoc's / @TODO / notation. This way a quick search on the @TODO will bring up all the tasks flagged in the code. Also if we utilize JSDoc in the future, the @TODO notation will be helpful.Pull Requests
An optimal PR for our git history explains all of the changes that it makes to the repository with a title and description that is easy to read and to
understand, and (if necessary) to revert.
$3
The title of the PR should be a very brief imperative-voice description of what the PR does,
prefixed by the JIRA story abbreviation it addresses. (If there is no JIRA ticket,
use the component that the pull request affects or "[MAINT]" if the PR addresses repository
maintenance):
{{ [JIRA-XXX] }} - {{ Brief summary of what PR does }}
eg:
[FS-326] - Fix settings menu
If a pull request is not to be considered for merging (yet), please prefix the PR title with [WIP] or [DO NOT MERGE] to indicate the code isn't intended to be merged.
$3
While this isn't required, the body of the pull request ideally helps the next engineer review the code by following the _Problem/Solution/Result_ pattern. Each section
should contain a description or list of items. The _Solution_ section should describe what each change does, together with any justifications, reasoning, or concerns. Include
a link to the JIRA ticket when possible in the _Problem_ section.
eg:
`
PROBLEM
- Description (eg: Can’t view the menu)
- [JIRA ticket link] SOLUTION
- What you did, what files were edited, why
- (eg: Fixed menu visibility)
RESULT
- User experience change
- (eg: Menu now appears on click)
- Any changes engineers will experience
- If changes to UI are substantial or important, include screenshot of the app showing changes to the UI.
`Publishing the Library
When you have finished making your changes, publish a version to npm. We use the Angular CLI and the npm package managerto build and publish the library as an npm package.- New major and minor versions should be published from
develop branch. Patch versions can be published from feature branches if needed. - Only publish new major (breaking) versions when the version of Angular is changing or other truly breaking changes are taking place.
Make all of your changes inside the
/projects/umbrella-library/src directory.Then, to build and publish to npm, step back out to the
projects directory and build and publish:`
ng build @srs/umbrella-library
cd ../dist/umbrella-library
npm version [bump to new version]
npm publish
`As a single command (if you bump the version in the package.json), you can use:
cd ../../projects && ng build umbrella-library && cd ../dist/umbrella-library && npm patch && npm publish*Note: You can find instructions in the README of the asset-hierarchy-manager on how to use a script to use your local instance of this library inside your MFE during local development.
Note: You may need to use the public access flag when publishing:
npm publish --access=publicFrom Angular documentation: You should always build libraries for distribution using the production configuration. This ensures that generated output uses the appropriate optimizations and the correct package format for npm.
Monitoring
Information on site monitoring coming soon:
- Health Check
- NodePing
- New Relic
Further help
To get more help on the Angular CLI use
ng help` or review the Angular CLI README.