umbrella-library
v2.5.1
Published
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.
Keywords
Readme
Umbrella Library
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.
This library was originally generated with Angular CLI version 12.2.0.
[TOC]
Installation
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).
Versions
- < 1.0 - Versions prior to 1.0 are for use in MFEs running Angular 12
- 1.0+ - Versions on 1.x.x are for use in MFEs running Angular 16 and Angular 17
- 2.0+ - Versions on 2.x.x are for use in MFEs running Angular 18+
Directory Structure
/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.
Major Features
Data Table
This custom exported component can handle -- and should be used -- for most of the many data tables used in the Umbrella UI.
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
truevalue 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: trueandfilterOperatorsset 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 asortFnproperty that is eitheralphabetical,numericalor a custom nzTableSortFn function that takes two params and returns -1, 0, or 1. If set tobackend, all sortable columns should havesortFnset totrue, and the API integrated with this table should handlesortFieldandsortOrderin thefetchEventwhen 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
Cell Display with format
As for display, all data is displayed as standard 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
trueorfalse. - label - Data can be displayed as colored labels. Pass into the
formatobjectformat.type = 'label'and aformat.labelsobject with key(s) that are the value(s) you want to display labels for, and the value(s) are mini-objects containinglabelTextandlabelColorfor each value. The colors currently available aregreen,redandgray. - 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.srcfield.
Cell Display with CellTemplateRef
To further define custom cells displays not possible with the format option above, a custom TemplateRef can be passed by name from the parent in the MFE using customCellTemplateRef.
record Required <ng-template> attribute: let-record=record
column Optional <ng-template> attribute: let-column=column. Useful in case of multiple custom columns with 'templateRef' format type.
Example:
<ng-template #templateRefName
let-column="column"
let-record="data">
<ng-container *ngIf="column.field === 'myColumnFieldName'">
{{record.fleet.name}}
</ng-container>
</ng-template>Infinite Scroll
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:
<x-data-table #table
[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
HeaderTagtype - primaryButton: ActionButton - The primary button on the upper right.
- secondaryButtons: ActionButton[] - An array of
ActionButtonthat will appear to the left of the primary button. - ellipsisDropdownItems: MenuDropdownItem[] - Dropdown options.
- breadcrumbItems: HeaderBreadcrumb[] - Navigation breadcrumb links.
- navRoutes: HeaderNavRoute[]. If a route with
childrenis 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
ActionButtonthat 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).
- Add
HTTP_INTERCEPTORSto your import from Angular'shttplibrary - Add
UmbrellaErrorInterceptorto your Umbrella Library import - In the Module configuration, use a
providersproperty 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:
- Create a new directory in the
public-modulesdirectory to host your new feature. - Create your components or services there with Code Scaffolding and
ng generatecommands, as specified below. - Name your exported class the way you would like it be imported into our Umbrella microfrontends.
- Write your code to customize your component.
- Add a stanza in the
/public-api.tsfile to ensure the library will export your new feature. - 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:
Automated Formatting
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"
}
]
}Manual Formatting
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.
Other Commands
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
Explanations
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.
Unused code
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.
TODOs
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.
PR Title
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 menuIf 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.
PR Body
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
developbranch. 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 publishAs 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=public
From 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.
