Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 17 additions & 17 deletions .github/workflows/publish-npm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Publish @sdcorejs/angular to npm
on:
push:
tags:
- 'v2.7'
- 'v2.8'
workflow_dispatch:
inputs:
artifact_run_id:
Expand All @@ -15,7 +15,7 @@ on:
permissions: {}

concurrency:
group: publish-npm-v2.7
group: publish-npm-v2.8
cancel-in-progress: false

jobs:
Expand All @@ -33,7 +33,7 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ github.event_name == 'workflow_dispatch' && 'refs/tags/v2.7' || github.ref }}
ref: ${{ github.event_name == 'workflow_dispatch' && 'refs/tags/v2.8' || github.ref }}

- name: Require the release tag commit to be on main
run: |
Expand All @@ -52,7 +52,7 @@ jobs:
id: release_plan
run: |
echo "source_sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
node --input-type=module -e "import {releaseTargets} from './scripts/release-package-contract.mjs';process.stdout.write('targets_json='+JSON.stringify(releaseTargets('2.7'))+'\n')" >> "$GITHUB_OUTPUT"
node --input-type=module -e "import {releaseTargets} from './scripts/release-package-contract.mjs';process.stdout.write('targets_json='+JSON.stringify(releaseTargets('2.8'))+'\n')" >> "$GITHUB_OUTPUT"

- name: Pin npm used by the release contract
run: |
Expand Down Expand Up @@ -227,7 +227,7 @@ jobs:
if: ${{ inputs.artifact_run_id != '' }}
uses: actions/download-artifact@v4
with:
name: sdcorejs-angular-${{ matrix.version }}-2.7
name: sdcorejs-angular-${{ matrix.version }}-2.8
path: release-stage
github-token: ${{ github.token }}
repository: ${{ github.repository }}
Expand All @@ -236,7 +236,7 @@ jobs:
- name: Upload immutable package artifact
uses: actions/upload-artifact@v4
with:
name: sdcorejs-angular-${{ matrix.version }}-2.7
name: sdcorejs-angular-${{ matrix.version }}-2.8
path: release-stage
if-no-files-found: error
retention-days: 14
Expand Down Expand Up @@ -268,15 +268,15 @@ jobs:
- name: Download every package artifact
uses: actions/download-artifact@v4
with:
pattern: sdcorejs-angular-v*-2.7
pattern: sdcorejs-angular-v*-2.8
path: release-artifacts
merge-multiple: true

- name: Declare the complete verification set
run: echo "verify artifact workspaces v19 v20 v21 v22 with sha256 integrity shasum"

- name: Validate baselines and compile unchanged strict consumers
run: node scripts/release-package-contract.mjs --artifact-root release-artifacts --suffix 2.7 --baseline-suffix 2.6 --datetime-version 1.0.4 --compile-consumers
run: node scripts/release-package-contract.mjs --artifact-root release-artifacts --suffix 2.8 --baseline-suffix 2.7 --datetime-version 1.0.4 --compile-consumers

publish-packages:
name: Publish the verified transaction
Expand Down Expand Up @@ -311,12 +311,12 @@ jobs:
- name: Download the already verified package artifacts
uses: actions/download-artifact@v4
with:
pattern: sdcorejs-angular-v*-2.7
pattern: sdcorejs-angular-v*-2.8
path: release-artifacts
merge-multiple: true

- name: Execute one fail-closed publish transaction
run: node scripts/release-package-contract.mjs --artifact-root release-artifacts --suffix 2.7 --baseline-suffix 2.6 --datetime-version 1.0.4 --publish --require-provenance
run: node scripts/release-package-contract.mjs --artifact-root release-artifacts --suffix 2.8 --baseline-suffix 2.7 --datetime-version 1.0.4 --publish --require-provenance

publish-docs-and-page:
name: Publish verified docs and static page
Expand Down Expand Up @@ -346,15 +346,15 @@ jobs:
- name: Download the verified package artifacts
uses: actions/download-artifact@v4
with:
pattern: sdcorejs-angular-v*-2.7
pattern: sdcorejs-angular-v*-2.8
path: release-artifacts
merge-multiple: true

- name: Revalidate and materialize the verified v19 package
shell: bash
run: |
set -euo pipefail
node scripts/release-package-contract.mjs --artifact-root release-artifacts --suffix 2.7 --baseline-suffix 2.6 --datetime-version 1.0.4 > verified-release.json
node scripts/release-package-contract.mjs --artifact-root release-artifacts --suffix 2.8 --baseline-suffix 2.7 --datetime-version 1.0.4 > verified-release.json
V19_TARBALL="$(find release-artifacts/v19 -type f -name '*.tgz' -print -quit)"
test -n "$V19_TARBALL"
sha256sum "$V19_TARBALL"
Expand All @@ -366,15 +366,15 @@ jobs:
run: npm --prefix showcase ci --legacy-peer-deps

- name: Generate all four API-doc archives
run: npm run collect-release-docs -- --patch 2.7 --date "$(date -u +%F)" --commit "${{ needs.verify_source.outputs.source_sha }}" --skip-existing
run: npm run collect-release-docs -- --patch 2.8 --date "$(date -u +%F)" --commit "${{ needs.verify_source.outputs.source_sha }}" --skip-existing

- name: Build and retain static release page
shell: bash
run: |
npm run build:page -- --suffix 2.7
test -d published-pages/2.7
npm run build:page -- --suffix 2.8
test -d published-pages/2.8
test ! -d published-pages/2.2
node -e "const p=require('./published-pages/pages.json');const retained2x=p.suffixes.filter(s=>s.startsWith('2.'));if(p.latest!=='2.7'||retained2x.join(',')!=='2.7,2.6,2.5,2.4,2.3'||!p.suffixes.some(s=>s.startsWith('1.')))throw new Error('published-pages retention mismatch')"
node -e "const p=require('./published-pages/pages.json');const retained2x=p.suffixes.filter(s=>s.startsWith('2.'));if(p.latest!=='2.8'||retained2x.join(',')!=='2.8,2.7,2.6,2.5,2.4'||!p.suffixes.some(s=>s.startsWith('1.')))throw new Error('published-pages retention mismatch')"

- name: Commit generated docs and page
shell: bash
Expand All @@ -383,7 +383,7 @@ jobs:
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add published-docs published-pages
git commit -m "docs: publish Angular 22 release 2.7"
git commit -m "docs: publish Angular 22 release 2.8"
SOURCE_SHA="${{ needs.verify_source.outputs.source_sha }}"
test "$(git rev-parse HEAD^)" = "$SOURCE_SHA"
git fetch origin main --no-tags
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
diff --git a/node_modules/@sdcorejs/angular/configurations/index.d.ts b/node_modules/@sdcorejs/angular/configurations/index.d.ts
index 1156d4f..54cb6a4 100644
--- a/node_modules/@sdcorejs/angular/configurations/index.d.ts
+++ b/node_modules/@sdcorejs/angular/configurations/index.d.ts
@@ -1,5 +1,6 @@
import { InjectionToken } from '@angular/core';
import { Language } from '@sdcorejs/utils/models';
+import type { ISdLayoutConfiguration } from '@sdcorejs/angular/modules/layout';

interface ISdCoreConfiguration {
format?: {
@@ -8,6 +9,7 @@ interface ISdCoreConfiguration {
language?: Language | (() => Record<string, string>);
}
declare const SD_CORE_CONFIGURATION: InjectionToken<ISdCoreConfiguration>;
+declare const SD_LAYOUT_CONFIGURATION: InjectionToken<ISdLayoutConfiguration>;

-export { SD_CORE_CONFIGURATION };
+export { SD_CORE_CONFIGURATION, SD_LAYOUT_CONFIGURATION };
export type { ISdCoreConfiguration };
diff --git a/node_modules/@sdcorejs/angular/fesm2022/sdcorejs-angular-components-tab-router.mjs b/node_modules/@sdcorejs/angular/fesm2022/sdcorejs-angular-components-tab-router.mjs
index fe3a185..cc9246f 100644
--- a/node_modules/@sdcorejs/angular/fesm2022/sdcorejs-angular-components-tab-router.mjs
+++ b/node_modules/@sdcorejs/angular/fesm2022/sdcorejs-angular-components-tab-router.mjs
@@ -420,6 +420,12 @@ class SdTabRouterOutletComponent {
await this.#activeRoute(fullUrl, route, state);
});
};
+ // A route may opt into one tab per path when query parameters are view state.
+ // Other routes retain the package's URL + query-parameter identity.
+ #tabKey = (url, route) => Utilities.hash({
+ url,
+ queryParams: route.data?.['tabIdentity'] === 'path' ? {} : { ...(route.queryParams || {}) },
+ });
// Bù initial navigation nếu NavigationEnd đã fire trước khi outlet subscribe.
#syncCurrentRoute = () => {
if (this.disabled() || !this.#router.navigated) {
@@ -430,10 +436,7 @@ class SdTabRouterOutletComponent {
return Promise.resolve();
}
const [urlPath] = this.#router.url.split('?');
- const key = Utilities.hash({
- url: urlPath,
- queryParams: { ...(route.queryParams || {}) },
- });
+ const key = this.#tabKey(urlPath, route);
if (this.tabs().some(tab => tab.key === key)) {
return Promise.resolve();
}
@@ -492,8 +495,8 @@ class SdTabRouterOutletComponent {
const params = { ...(route.params || {}) };
const data = { ...(route.data || {}) };
const [url] = fullUrl.split('?');
- // Tab identity = hash(url + queryParams). Cùng key mặc định giữ tab cũ; forceReload mới tạo lại.
- const key = Utilities.hash({ url, queryParams });
+ // Query identity is unchanged unless this route explicitly opts into path identity.
+ const key = this.#tabKey(url, route);
let existedIndex = -1;
let activatedIndex = -1;
const currentTabs = this.tabs();
@@ -578,8 +581,12 @@ class SdTabRouterOutletComponent {
// re-evaluate không cần thiết). Với tab cần đổi isActive: tạo object mới qua spread,
// các nested fields (component, injector) vẫn giữ same reference nên component không bị recreate.
let updatedTabs = currentTabs.map(tab => {
- if (tab.key === key)
+ if (tab.key === key) {
+ // Preserve the component injector and its view state while keeping tab links current.
+ if (data['tabIdentity'] === 'path')
+ return { ...tab, isActive: true, queryParams };
return tab.isActive ? tab : { ...tab, isActive: true };
+ }
return tab.isActive ? { ...tab, isActive: false } : tab;
});
// replaceTab: thay vì mở tab mới song song, xoá tab đang active rồi mở tab mới ở cuối.
diff --git a/node_modules/@sdcorejs/angular/fesm2022/sdcorejs-angular-configurations.mjs b/node_modules/@sdcorejs/angular/fesm2022/sdcorejs-angular-configurations.mjs
index a634ad1..177373e 100644
--- a/node_modules/@sdcorejs/angular/fesm2022/sdcorejs-angular-configurations.mjs
+++ b/node_modules/@sdcorejs/angular/fesm2022/sdcorejs-angular-configurations.mjs
@@ -1,10 +1,11 @@
import { InjectionToken } from '@angular/core';

const SD_CORE_CONFIGURATION = new InjectionToken('sd-core.configuration');
+const SD_LAYOUT_CONFIGURATION = new InjectionToken('sd.layout.configuration');

/**
* Generated bundle index. Do not edit.
*/

-export { SD_CORE_CONFIGURATION };
+export { SD_CORE_CONFIGURATION, SD_LAYOUT_CONFIGURATION };
//# sourceMappingURL=sdcorejs-angular-configurations.mjs.map
diff --git a/node_modules/@sdcorejs/angular/fesm2022/sdcorejs-angular-modules-layout.mjs b/node_modules/@sdcorejs/angular/fesm2022/sdcorejs-angular-modules-layout.mjs
index bcc004f..17464fa 100644
--- a/node_modules/@sdcorejs/angular/fesm2022/sdcorejs-angular-modules-layout.mjs
+++ b/node_modules/@sdcorejs/angular/fesm2022/sdcorejs-angular-modules-layout.mjs
@@ -28,7 +28,8 @@ import { SdIcon } from '@sdcorejs/angular/modules/icon';
import { isObservable } from 'rxjs';
import { SdInput } from '@sdcorejs/angular/forms';
import * as i1$2 from '@angular/cdk/a11y';
import { A11yModule } from '@angular/cdk/a11y';
+import { SD_LAYOUT_CONFIGURATION } from '@sdcorejs/angular/configurations';

class SdPageComponent {
el = inject(ElementRef);
@@ -336,7 +337,6 @@ function normalizeSidebarConfiguration(sidebar) {
}
return sidebar;
}
-const SD_LAYOUT_CONFIGURATION = new InjectionToken('sd.layout.configuration');

const SD_LAYOUT_VIEWPORT = SD_VIEWPORT;
/** @deprecated Prefer `SdViewportService` from `@sdcorejs/angular/services/viewport`. */
diff --git a/node_modules/@sdcorejs/angular/modules/layout/index.d.ts b/node_modules/@sdcorejs/angular/modules/layout/index.d.ts
index 06f2ad0..5248797 100644
--- a/node_modules/@sdcorejs/angular/modules/layout/index.d.ts
+++ b/node_modules/@sdcorejs/angular/modules/layout/index.d.ts
@@ -1,5 +1,6 @@
import * as _angular_core from '@angular/core';
import { InjectionToken, Signal, PipeTransform } from '@angular/core';
+import { SD_LAYOUT_CONFIGURATION } from '@sdcorejs/angular/configurations';
import * as i1$1 from '@angular/common';
import * as i1 from '@angular/router';
import { Params } from '@angular/router';
@@ -272,7 +273,6 @@ declare function resolveSidebarV3Recent(sidebar: SidebarConfigurationV3): Resolv
declare function normalizeSidebarConfiguration(_sidebar: SidebarConfigurationV1): SidebarConfigurationV1;
declare function normalizeSidebarConfiguration(_sidebar: SidebarConfigurationV2): SidebarConfigurationV2;
declare function normalizeSidebarConfiguration(_sidebar: SidebarConfigurationV3): SidebarConfigurationV3;
-declare const SD_LAYOUT_CONFIGURATION: InjectionToken<ISdLayoutConfiguration>;

declare class SdLayoutNavigationStateService {
#private;
Loading
Loading