Skip to content

Commit 3a90401

Browse files
committed
Merge branch 'main' into dependabot/npm_and_yarn/hey-api/openapi-ts-0.48.1
2 parents 14a725f + 1e85b22 commit 3a90401

File tree

177 files changed

+629
-492
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

177 files changed

+629
-492
lines changed

.github/workflows/build_test.yml

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,30 @@ env:
2525
jobs:
2626
build:
2727
runs-on: ubuntu-latest
28-
29-
strategy:
30-
matrix:
31-
node-version: [20]
32-
3328
steps:
3429
- uses: actions/checkout@v4
35-
- name: Use Node.js ${{ matrix.node-version }}
30+
- name: Use Node.js
3631
uses: actions/setup-node@v4
3732
with:
38-
node-version: ${{ matrix.node-version }}
33+
node-version-file: .nvmrc
3934
cache: npm
40-
cache-dependency-path: package-lock.json
35+
cache-dependency-path: ./package-lock.json
4136
- run: npm ci --no-audit --no-fund --prefer-offline
4237
- run: npm run lint:errors
43-
- run: npm run build
38+
- run: npm run build:for:cms
4439
- run: npm run generate:jsonschema:dist
40+
41+
test:
42+
runs-on: ubuntu-latest
43+
steps:
44+
- uses: actions/checkout@v4
45+
- name: Use Node.js
46+
uses: actions/setup-node@v4
47+
with:
48+
node-version-file: .nvmrc
49+
cache: npm
50+
cache-dependency-path: ./package-lock.json
51+
- run: npm ci --no-audit --no-fund --prefer-offline
4552
- run: npx playwright install --with-deps
4653
- run: npm test
4754
- name: Upload Code Coverage reports
@@ -51,13 +58,3 @@ jobs:
5158
name: code-coverage
5259
path: coverage/
5360
retention-days: 30
54-
# Commented out since it is outdated and is quite spammy
55-
# - name: Report code coverage
56-
# uses: zgosalvez/github-actions-report-lcov@v2
57-
# if: always()
58-
# continue-on-error: true
59-
# with:
60-
# coverage-files: coverage/lcov.info
61-
# artifact-name: code-coverage-report
62-
# github-token: ${{ secrets.GITHUB_TOKEN }}
63-
# working-directory: ./

.github/workflows/devskim.yml

Lines changed: 0 additions & 38 deletions
This file was deleted.

devops/icons/index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { readFileSync, writeFile, mkdir } from 'fs';
1+
import { readFileSync, writeFile, mkdir, rmSync } from 'fs';
22
import * as globModule from 'tiny-glob';
33
import * as pathModule from 'path';
44

@@ -15,6 +15,9 @@ const lucideSvgDirectory = 'node_modules/lucide-static/icons';
1515
const simpleIconsSvgDirectory = 'node_modules/simple-icons/icons';
1616

1717
const run = async () => {
18+
// Empty output directory:
19+
rmSync(iconsOutputDirectory, { recursive: true });
20+
1821
var icons = await collectDictionaryIcons();
1922
icons = await collectDiskIcons(icons);
2023
writeIconsToDisk(icons);

package-lock.json

Lines changed: 13 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,8 @@
138138
"./src/packages/umbraco-news",
139139
"./src/packages/webhook",
140140
"./src/packages/health-check",
141-
"./src/packages/tags"
141+
"./src/packages/tags",
142+
"./src/packages/templating"
142143
],
143144
"scripts": {
144145
"backoffice:test:e2e": "npx playwright test",
@@ -256,7 +257,7 @@
256257
"rollup-plugin-esbuild": "^6.1.1",
257258
"rollup-plugin-import-css": "^3.5.0",
258259
"rollup-plugin-web-worker-loader": "^1.6.1",
259-
"simple-icons": "^12.0.0",
260+
"simple-icons": "^13.0.0",
260261
"storybook": "^7.6.17",
261262
"tiny-glob": "^0.2.9",
262263
"tsc-alias": "^1.8.8",

src/apps/backoffice/components/backoffice-main.element.ts

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { UmbBackofficeContext } from '../backoffice.context.js';
22
import { UMB_BACKOFFICE_CONTEXT } from '../backoffice.context.js';
33
import { css, html, customElement, state, nothing } from '@umbraco-cms/backoffice/external/lit';
44
import { UmbSectionContext, UMB_SECTION_CONTEXT, UMB_SECTION_PATH_PATTERN } from '@umbraco-cms/backoffice/section';
5-
import type { UmbRoute, UmbRouterSlotChangeEvent } from '@umbraco-cms/backoffice/router';
5+
import type { PageComponent, UmbRoute, UmbRouterSlotChangeEvent } from '@umbraco-cms/backoffice/router';
66
import type { ManifestSection, UmbSectionElement } from '@umbraco-cms/backoffice/extension-registry';
77
import type { UmbExtensionManifestInitializer } from '@umbraco-cms/backoffice/extension-api';
88
import { createExtensionElement } from '@umbraco-cms/backoffice/extension-api';
@@ -11,7 +11,7 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
1111
@customElement('umb-backoffice-main')
1212
export class UmbBackofficeMainElement extends UmbLitElement {
1313
@state()
14-
private _routes: Array<UmbRoute & { alias: string }> = [];
14+
private _routes: Array<UmbRoute> = [];
1515

1616
@state()
1717
private _sections: Array<UmbExtensionManifestInitializer<ManifestSection>> = [];
@@ -43,28 +43,41 @@ export class UmbBackofficeMainElement extends UmbLitElement {
4343

4444
private _createRoutes() {
4545
if (!this._sections) return;
46-
const oldValue = this._routes;
4746

4847
// TODO: Refactor this for re-use across the app where the routes are re-generated at any time.
49-
this._routes = this._sections
48+
const newRoutes = this._sections
5049
.filter((x) => x.manifest)
5150
.map((section) => {
52-
const existingRoute = this._routes.find((r) => r.alias === section.alias);
51+
const existingRoute = this._routes.find(
52+
(r) => r.path === UMB_SECTION_PATH_PATTERN.generateLocal({ sectionName: section.manifest!.meta.pathname }),
53+
);
5354
if (existingRoute) {
5455
return existingRoute;
5556
} else {
5657
return {
57-
alias: section.alias,
58+
//alias: section.alias,
5859
path: UMB_SECTION_PATH_PATTERN.generateLocal({ sectionName: section.manifest!.meta.pathname }),
5960
component: () => createExtensionElement(section.manifest!, 'umb-section-default'),
60-
setup: (component) => {
61-
(component as UmbSectionElement).manifest = section.manifest as ManifestSection;
61+
setup: (component: PageComponent) => {
62+
(component as UmbSectionElement).manifest = section.manifest;
6263
},
6364
};
6465
}
6566
});
6667

67-
this.requestUpdate('_routes', oldValue);
68+
if (newRoutes.length > 0) {
69+
newRoutes.push({
70+
path: ``,
71+
redirectTo: newRoutes[0].path,
72+
});
73+
74+
newRoutes.push({
75+
path: `**`,
76+
component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement,
77+
});
78+
}
79+
80+
this._routes = newRoutes;
6881
}
6982

7083
private _onRouteChange = async (event: UmbRouterSlotChangeEvent) => {

src/assets/lang/da-dk.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2521,4 +2521,8 @@ export default {
25212521
detailedLevelDescription:
25222522
'\n We will send:\n <ul>\n <li>Anonymized site ID, Umbraco version, and packages installed.</li>\n <li>Number of: Root nodes, Content nodes, Media, Document Types, Templates, Languages, Domains, User Group, Users, Members, Backoffice external login providers, and Property Editors in use.</li>\n <li>System information: Webserver, server OS, server framework, server OS language, and database provider.</li>\n <li>Configuration settings: Modelsbuilder mode, if custom Umbraco path exists, ASP environment, whether the delivery API is enabled, and allows public access, and if you are in debug mode.</li>\n </ul>\n <em>We might change what we send on the Detailed level in the future. If so, it will be listed above.\n <br>By choosing "Detailed" you agree to current and future anonymized information being collected.</em>\n ',
25232523
},
2524+
routing: {
2525+
routeNotFoundTitle: 'Ikke fundet',
2526+
routeNotFoundDescription: 'Den side du leder efter kunne ikke findes. Kontroller adressen og prøv igen.',
2527+
},
25242528
} as UmbLocalizationDictionary;

src/assets/lang/en-us.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2522,4 +2522,8 @@ export default {
25222522
detailedLevelDescription:
25232523
'\n We will send:\n <ul>\n <li>Anonymized site ID, Umbraco version, and packages installed.</li>\n <li>Number of: Root nodes, Content nodes, Media, Document Types, Templates, Languages, Domains, User Group, Users, Members, Backoffice external login providers, and Property Editors in use.</li>\n <li>System information: Webserver, server OS, server framework, server OS language, and database provider.</li>\n <li>Configuration settings: Modelsbuilder mode, if custom Umbraco path exists, ASP environment, whether the delivery API is enabled, and allows public access, and if you are in debug mode.</li>\n </ul>\n <em>We might change what we send on the Detailed level in the future. If so, it will be listed above.\n <br>By choosing "Detailed" you agree to current and future anonymized information being collected.</em>\n ',
25242524
},
2525+
routing: {
2526+
routeNotFoundTitle: 'Not found',
2527+
routeNotFoundDescription: 'The requested route could not be found. Please check the URL and try again.',
2528+
},
25252529
} as UmbLocalizationDictionary;

src/assets/lang/en.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2591,4 +2591,8 @@ export default {
25912591
detailedLevelDescription:
25922592
'We will send:\n<ul>\n <li>Anonymized site ID, Umbraco version, and packages installed.</li>\n <li>Number of: Root nodes, Content nodes, Macros, Media, Document Types, Templates, Languages, Domains, User Group, Users, Members, Backoffice external login providers, and Property Editors in use.</li>\n <li>System information: Webserver, server OS, server framework, server OS language, and database provider.</li>\n <li>Configuration settings: Modelsbuilder mode, if custom Umbraco path exists, ASP environment, whether the delivery API is enabled, and allows public access, and if you are in debug mode.</li>\n</ul>\n<em>We might change what we send on the Detailed level in the future. If so, it will be listed above.\n<br>By choosing "Detailed" you agree to current and future anonymized information being collected.</em>',
25932593
},
2594+
routing: {
2595+
routeNotFoundTitle: 'Not found',
2596+
routeNotFoundDescription: 'The requested route could not be found. Please check the URL and try again.',
2597+
},
25942598
} as UmbLocalizationDictionary;

src/external/router-slot/router-slot.ts

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ ensureAnchorHistory();
4545
* @event changestate - Dispatched when the router slot state changes.
4646
*/
4747
export class RouterSlot<D = any, P = any> extends HTMLElement implements IRouterSlot<D, P> {
48+
/**
49+
* Method to cancel navigation if changed.
50+
*/
51+
private _cancelNavigation ?:() => void;
52+
4853
/**
4954
* Listeners on the router.
5055
*/
@@ -197,8 +202,17 @@ export class RouterSlot<D = any, P = any> extends HTMLElement implements IRouter
197202
this._routes.push(...routes);
198203

199204
if (navigate === undefined) {
200-
// If navigate is not determined, then we will check if we have a route match. If not then we will re-render.
205+
// If navigate is not determined, then we will check if we have a route match. If not then we will re-render. [NL]
201206
navigate = this._routeMatch === null;
207+
if (navigate === false) {
208+
if (this.isConnected) {
209+
const newMatch = this.getRouteMatch();
210+
// Check if this match matches the current match (aka. If the path has changed), if so we should navigate. [NL]
211+
if(newMatch) {
212+
navigate = shouldNavigate(this.match, newMatch);
213+
}
214+
}
215+
}
202216
}
203217

204218
// Navigate fallback:
@@ -232,13 +246,21 @@ export class RouterSlot<D = any, P = any> extends HTMLElement implements IRouter
232246

233247
// Either choose the parent fragment or the current path if no parent exists.
234248
// The root router slot will always use the entire path.
235-
const pathFragment =
236-
this.parent != null && this.parent.fragments != null ? this.parent.fragments.rest : pathWithoutBasePath();
249+
const pathFragment = this.getPathFragment();
237250

238251
// Route to the path
239252
await this.renderPath(pathFragment);
240253
}
241254

255+
protected getPathFragment() {
256+
return this.parent != null && this.parent.fragments != null ? this.parent.fragments.rest : pathWithoutBasePath();
257+
}
258+
259+
protected getRouteMatch() {
260+
// Find the corresponding route.
261+
return matchRoutes(this._routes, this.getPathFragment());
262+
}
263+
242264
/**
243265
* Attaches listeners, either globally or on the parent router.
244266
*/
@@ -296,6 +318,8 @@ export class RouterSlot<D = any, P = any> extends HTMLElement implements IRouter
296318
* Returns true if a navigation was made to a new page.
297319
*/
298320
protected async renderPath(path: string | PathFragment): Promise<boolean> {
321+
322+
// Notice: Since this is never called from any other place than one higher in this file(when writing this...), we could just retrieve the path and find a match by using this.getRouteMatch() [NL]
299323
// Find the corresponding route.
300324
const match = matchRoutes(this._routes, path);
301325

@@ -312,10 +336,17 @@ export class RouterSlot<D = any, P = any> extends HTMLElement implements IRouter
312336
// Only change route if its a new route.
313337
const navigate = shouldNavigate(this.match, match);
314338
if (navigate) {
339+
340+
// If another navigation is still begin resolved in this very moment, then we need to cancel that so it does not end up overriding this new navigation.[NL]
341+
this._cancelNavigation?.();
315342
// Listen for another push state event. If another push state event happens
316343
// while we are about to navigate we have to cancel.
317344
let navigationInvalidated = false;
318-
const cancelNavigation = () => (navigationInvalidated = true);
345+
const cancelNavigation = () => {
346+
navigationInvalidated = true;
347+
this._cancelNavigation = undefined;
348+
};
349+
this._cancelNavigation = cancelNavigation;
319350
const removeChangeListener: EventListenerSubscription = addListener<Event, GlobalRouterEvent>(
320351
GLOBAL_ROUTER_EVENTS_TARGET,
321352
'changestate',
@@ -378,16 +409,23 @@ export class RouterSlot<D = any, P = any> extends HTMLElement implements IRouter
378409
return cancel();
379410
}
380411

381-
// Remove the old page by clearing the slot
382-
this.clearChildren();
412+
// We have some routes that share the same component instance, those should not be removed and re-appended [NL]
413+
const isTheSameComponent = this.firstChild === page;
414+
415+
if(!isTheSameComponent) {
416+
// Remove the old page by clearing the slot
417+
this.clearChildren();
418+
}
383419

384420
// Store the new route match before we append the new page to the DOM.
385421
// We do this to ensure that we can find the match in the connectedCallback of the page.
386422
this._routeMatch = match;
387423

388-
if (page) {
389-
// Append the new page
390-
this.appendChild(page);
424+
if(!isTheSameComponent) {
425+
if (page) {
426+
// Append the new page
427+
this.appendChild(page);
428+
}
391429
}
392430
}
393431

0 commit comments

Comments
 (0)