diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..be4dd009 --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2024, Ex Libris, Ltd. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md index 863ada13..0ff58e62 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,47 @@ # CustomModule +## ✨ New Feature (9th November 2025): Support for all customization files in assets folder: +All files that are you are able to customize through the assets folder of your customization package are now supported for preview when using the custom module in proxy mode. + +For example to preview your brand logo you can now place your customized logo file in the following path in your local project: +`src/assets/images/library-logo.png` + +To start proxy mode use the command: +``` bash +npm run start:proxy +``` + +### How the asset manifest is resolved in proxy mode + +When running in proxy mode, requests to `/custom/*/asset-manifest.json` are answered with a manifest +computed at runtime (nothing is ever written to disk) by merging three sources: + +- The **remote** manifest from your configured `PROXY_TARGET` environment. +- Your **locally built** output at `dist/{INST_ID}-{VIEW_ID}` (named from `build-settings.env`) — this + is where compiled/bundled files such as the generated `custom.css` or `remoteEntry.js` live. +- Your **local `src/assets`** folder — scanned live on every request. + +Because the built output is only picked up if it already exists on disk, **you must run `npm run build` +at least once before starting proxy mode** so that `dist/{INST_ID}-{VIEW_ID}` is present; otherwise only +files under `src/assets` will show up in the manifest, and compiled-only files (like a root-level +`custom.css`) will appear to be missing. + +After that initial build: +- Changes under `src/assets` are picked up immediately on the next request — no rebuild needed. +- Changes to compiled/bundled files (e.g. theme/SCSS changes, code changes) require re-running + `npm run build` to refresh `dist/{INST_ID}-{VIEW_ID}`; no dev-server restart is needed, the proxy + re-scans the folder on every manifest request. + +--- + ### Overview + + The NDE Customization package offers options to enhance and extend the functionality of Primo’s New Discovery Experience (NDE). You can add and develop your own components, customize theme templates, and tailor the discovery interface to your specific needs. +**Note:** +This branch includes updates and other improvements that are compatible with the December 2025 release of NDE. + **Note:** The NDE Customization package is currently available exclusively to Primo customers who have early access to the New Discovery Experience (NDE). Further availability will be announced in upcoming releases. @@ -43,7 +82,7 @@ The NDE Customization package is currently available exclusively to Primo custom --- -## Development Server Setup +## Development server setup and startup ### Step 1: Download the Project 1. Navigate to the GitHub repository: [https://github.com/ExLibrisGroup/customModule](https://github.com/ExLibrisGroup/customModule). @@ -56,82 +95,414 @@ The NDE Customization package is currently available exclusively to Primo custom npm install ``` ---- +### Step 3: Configuring proxy for and starting local development server -## Code Scaffolding and Customization +There are two options for setting up your local development environment: configuring a proxy or using parameter on your NDE URL. -### Step 3: Add Custom Components -1. Create custom components within the `custom1-module` module by running: - ```bash - ng generate component --module custom1-module +- **Option 1: Update `proxy.const.mjs` Configuration**: + - Set the URL of the server you want to test your code with by modifying the proxy.const.mjs file in the ./proxy directory: + ```javascript + // Configuration for the development proxy + const environments = { + 'example': 'https://myPrimoVE.com', + } + + export const PROXY_TARGET = environments['example']; ``` - Example: + - Start the development server with the configured proxy by running: ```bash - ng generate component RecommendationsComponent --module custom1-module + npm run start:proxy ``` + - Open your browser on port 4201 to see your changes. e.g: http://localhost:4201/nde/home?vid=EXLDEV1_INST:NDE&lang=en + + +- **Option 2: Parameter on NDE URL**: + - Start your development server by running + ```bash + npm run start + ``` + - Add the following query parameter to your NDE URL: + ``` + useLocalCustomPackage=true + ``` + For example: `https://sqa-na02.alma.exlibrisgroup.com/nde/home?vid=EXLDEV1_INST:NDE&useLocalCustomPackage=true` + - This setting assumes that your local development environment is running on the default port `4201`. + + +--- + +## Step 4: Code Scaffolding and Customization -2. To add components before and after a target component, use: +### Add Custom Components +1. Create custom components by running: ```bash - ng generate component -before --module custom1-module - ng generate component -after --module custom1-module + ng generate component ``` + Example: + ```bash + ng generate component RecommendationsComponent + ``` -3. Update `selectorComponentMap` in `custom1-module.module.ts` to connect the newly created components: +2. Update `selectorComponentMap` in `customComponentMappings.ts` to connect the newly created components: ```typescript export const selectorComponentMap = new Map([ ['nde-recommendations-before', RecommendationsComponentBefore], ['nde-recommendations-after', RecommendationsComponentAfter], + ['nde-recommendations-top', RecommendationsComponentTop], + ['nde-recommendations-bottom', RecommendationsComponentBottom], ['nde-recommendations', RecommendationsComponent], // Add more pairs as needed ]); ``` -4. Customize the component’s `.html`, `.ts`, and `.scss` files as needed: +3. Customize the component’s `.html`, `.ts`, and `.scss` files as needed: - `src/app/recommendations-component/recommendations-component.component.html` - `src/app/recommendations-component/recommendations-component.component.ts` - `src/app/recommendations-component/recommendations-component.component.scss` -### Customization of Component Selectors + - All components in the NDE are intended to be customizable. However, if you encounter a component that does not support customization, please open a support case with us. This helps ensure that we can address the issue and potentially add customization support for that component in future updates. +### Accessing host component instance ---- +You can get the instance of the component your custom component is hooked to by adding this property to your component class: -### Step 4: Configuring Proxy for Local Development +```angular2html +@Input() private hostComponent!: any; +``` -There are two options for setting up your local development environment: configuring a proxy or using customization enhancements. +### Accessing app state -- **Option 1: Update `proxy.conf.mjs` Configuration**: - - Set the URL of the server you want to test your code with by modifying the `proxy.conf.mjs` file in the `./proxy` directory: - ```javascript - // Configuration for the development proxy - const environments = { - 'example': 'https://myPrimoVE.com', +- You can gain access to the app state which is stored on an NGRX store by injecting the Store service to your component: + +```angular2html +private store = inject(Store); +``` + +- Create selectors. For example: + +```angular2html +const selectUserFeature = createFeatureSelector<{isLoggedIn: boolean}>('user'); +const selectIsLoggedIn = createSelector(selectUserFeature, state => state.isLoggedIn); +``` + +- Apply selector to the store to get state as Signal: + +```angular2html +isLoggedIn = this.store.selectSignal(selectIsLoggedIn); +``` + +Or as Observable: + +```angular2html +isLoggedIn$ = this.store.select(selectIsLoggedIn); +``` +### Automatic assets public path (`assets/...`) + +If your custom module/add-on is hosted under a dynamic base URL, plain template URLs like: + +```html + +``` +may break, because the browser resolves them relative to the host page. + +To fix this, we provide: + +src/app/services/assets-public-path.directive.ts + +This directive automatically rewrites any src / href that starts with assets/ (or /assets/) to: + +```js +__webpack_public_path__ + 'assets/...' +``` +Import the directive in a component (Standalone) +Add the directive to the component imports: + +```js +import { CommonModule } from '@angular/common'; +import { Component } from '@angular/core'; +import { AssetsPublicPathDirective } from '../services/assets-public-path.directive'; + +@Component({ + selector: 'custom-example', + standalone: true, + templateUrl: './example.component.html', + styleUrls: ['./example.component.scss'], + imports: [CommonModule, AssetsPublicPathDirective], +}) +export class ExampleComponent {} +``` +If the component is not standalone (NgModule-based), import and export the directive from a shared module, and include that module where your components are declared. + +Use it in HTML +After the directive is imported, you can use plain assets/... paths in templates: + + +```html + +Logo + + +Clock + + +Help +``` +Supported attributes/elements (common cases): + +img[src] + +source[src] + +script[src] + +link[href] + +a[href] + +### Accessing app router + +- You can gain access to the app router service by injecting the SHELL_ROUTER injection token to your component: + +```angular2html +import {SHELL_ROUTER} from "../../injection-tokens"; //the import path may vary on your project +private router = inject(SHELL_ROUTER); +``` + +- Listening for router navigation events. For example: + +```angular2html +this.routerSubscription = this.router.events.subscribe((event) => { + if (event instanceof NavigationEnd) { + console.log('Tracking PageView: ', event.urlAfterRedirects); } +}); +``` - export const PROXY_TARGET = environments['example']; - ``` - - Start the development server with the configured proxy by running: + + +### Translating from code tables + +You can translate codes in your custom component by using ngx-translate (https://github.com/ngx-translate/core). + +- If you are using a stand alone component you will need to add the TranslateModule to your component imports list. +- In your components HTML you can translate a label like so: +```angular2html +This is some translated code: {{'delivery.code.ext_not_restricted' | translate}} +``` + + +--- + +## Creating your own color theme + +The NDE theming is based on Angular Material. +We allow via the view configuration to choose between a number of pre built themes. + +![prebuilt theme image](./readme-files/prebuilt-themes.png "prebuilt themes configuration") + + +If you want to create your own theme instead of using one of our options follow these steps: + +1. Create a material 3 theme by running: ```bash - npm run start:proxy - ``` + ng generate @angular/material:m3-theme + ``` + You will be prompted to answer a number of questions like so: + ``` +? What HEX color should be used to generate the M3 theme? It will represent your primary color palette. (ex. #ffffff) #1eba18 +? What HEX color should be used represent the secondary color palette? (Leave blank to use generated colors from Material) +? What HEX color should be used represent the tertiary color palette? (Leave blank to use generated colors from Material) +? What HEX color should be used represent the neutral color palette? (Leave blank to use generated colors from Material) +? What is the directory you want to place the generated theme file in? (Enter the relative path such as 'src/app/styles/' or leave blank to generate at your project root) src/app/styles/ +? Do you want to use system-level variables in the theme? System-level variables make dynamic theming easier through CSS custom properties, but increase the bundle size. yes +? Choose light, dark, or both to generate the corresponding themes light + +``` +- Note that it is imporant to answer yes when asked if you want to use system-level variables. + +- Also note that I'm only entering the primary color and not secondary or tertiary. They will be selected automatically based on my primary color. + +Once this script completes successfully you will recieve this message: + +`CREATE src/app/styles/m3-theme.scss (2710 bytes)` + +To apply the theme go to `_customized-theme.scss` and uncomment the following lines: +``` +.custom-nde-theme{ + @include mat.all-component-colors(m3-theme.$light-theme); + @include mat.system-level-colors(m3-theme.$light-theme); +} +``` +--- -- **Option 2: Enhancements in Customization**: - - **Local Custom Package Development**: - - To work with your live environment using a custom package, add the following configuration: - ```bash - useLocalCustomPackage=true - ``` - - This setting assumes that your local development environment is running on the default port `4201`. - - When starting your local development environment with the proxy enabled, configure your development customization package by specifying your local URL in the proxy configuration. Example: - ```plaintext - localhost:4201/... - ``` - - This setup allows for real-time testing and development that closely mirrors live environment conditions. +## Developing an Add-On for the NDE UI + +The NDE UI supports loading of custom modules at runtime and also provides infrastructure to dynamically load add-ons developed by vendors, consortia, or community members. This enables seamless integration, allowing institutions to configure and deploy external add-ons through **Add-On Configuration in Alma**. + +The NDE UI add-on framework allows various stakeholders to develop and integrate custom functionality: + +- **Vendors** can create and host services that institutions can seamlessly incorporate into their environment. +- **Institutions and consortia** can develop and share custom components, enabling consistency and collaboration across multiple libraries. + +Library staff can easily add, configure, and manage these add-ons through Alma, following guidelines provided by the stakeholders. These typically include: + +- **Add-on Name** – The identifier used in Alma’s configuration. This must match the add-on name as set when developing the add-on in the [section](#set-add-on-name) below. +- **Add-on URL** – The location where the add-on is hosted (static folder to load the add-on at runtime). +- **Configuration Parameters** – JSON-based config parameters to be referenced at runtime by the add-on. + +![Add-on Overview](./readme-files/addon-overview.png) + +--- + +## Guidelines for Developing an Add-On + +You can download the custom module and modify it to function as an add-on. + +### Set Add-on Name + +This section below should remain the same. + +![Set Addon Name](./readme-files/set-addon-name.png) + +![Example Configuration JSON](./readme-files/example-config-json.png) + +--- + +The add-on infrastructure provides a way to access institution-specific configuration parameters. Institutions can upload their configuration settings in JSON format, which your add-on can reference dynamically within its components. + +### 🔧 Accessing Add-On Configuration Parameters + +Use Angular DI to inject the parameters directly into your component via the `MODULE_PARAMETERS` token: + +```ts +import { Component, Inject } from '@angular/core'; + +@Component({ + selector: 'custom-test-bottom', + host: { 'data-component-id': 'custom-test-bottom-unique' }, + templateUrl: './test-bottom.component.html', + styleUrls: ['./test-bottom.component.scss'] +}) +export class TestBottomComponent { + constructor(@Inject('MODULE_PARAMETERS') public moduleParameters: any) { + console.log('Module parameters TestBottomComponent:', this.moduleParameters); + } + + getKeys(obj: any): string[] { + return Object.keys(obj || {}); + } +} + +``` + +> 📘 `yourParamKey` should match the keys defined in your Alma Add-on JSON configuration. +--- + +If your add-on includes assets such as images, you can ensure a complete separation between the frontend code and asset deployment. To achieve this, set `ASSET_BASE_URL` to point to your designated static folder, allowing your add-on to reference assets independently of the core application. + +![Access Assets via ASSET_BASE_URL](./readme-files/access-assets.png) + + +The `autoAssetSrc` directive automatically prepends `ASSET_BASE_URL` to your `[src]` attribute. + +### Example: +```html + +``` + +With: +```env +ASSET_BASE_URL=http://il-urm08.corp.exlibrisgroup.com:4202/ +``` + +Results in: +```html + +``` + +### Supported Elements: +- `` +- `` +- `