Skip to content

Commit cd72dbe

Browse files
authored
V16: Retry requests after timeout (#19495)
* feat: fix a small-ish nitpick where extensions would reload after login this could potentially try to re-register all private extensions after each auth signal, which is being prevented anyway because of duplicate aliases, but still nice to remove and not have to listen to * feat: align login UI extension load with backoffice, i.e. wait for external load before registering core extensions * build(deps): bump @hey-api to newest and re-generate client * chore: adds extra error logging * feat: adds retry logic to the api interceptor * feat: warn about incomplete actions * fix: the body was already plain text, but we need to ensure the headers say so as well * feat: warns the user when actions could not be completed * build(deps): update @hey-api/client-fetch * chore: generate new api * feat: simplify error handling to just UmbApiError and UmbCancelError * feat: moves error notifications from interceptors into tryExecute, so you more easily can opt out of it and everything is gathered in one place * feat: recreate responses with correct 'status' and 'statusText' * build: stop dotnet processes after debug session * feat: extrapolate common logic into helper method to create responses * feat: returns a UmbProblemDetails like object on interceptors to be handled by tryExecute * chore: deprecates duplicate, outdated UmbProblemDetails interface and type guard * feat: uses the 'title' of the problem details object to convey the main message * chore: 401 and 403 uses their own interceptors * feat: show no notification if 401 * feat: uses the real request method and url (instead of the template placeholders) to tell the user what did not succeed * feat: retry requests with no timeout/race * feat: throttle and delay signals and disallow them from being updated from the outside * chore: adds more logging to timeouts * chore: optimise imports * test: ignores any test files left in node_modules folder * feat: uses auditTime to wait a bit before showing the timeout screen * feat: adds 404 handling to error interceptor * chore: cleans up after response modification * feat: preserve only a few headers this mimicks the v15 behavior * feat: lets the UI handle 404 errors instead of notifying directly * test: uses create action menu option instead to find the correct locator, and skips a seemingly unnecessary timeout
1 parent e89e18f commit cd72dbe

File tree

22 files changed

+1183
-972
lines changed

22 files changed

+1183
-972
lines changed

.vscode/launch.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
"cwd": "${workspaceFolder}/src/Umbraco.Web.UI",
6363
"stopAtEntry": false,
6464
"requireExactSource": false,
65+
"postDebugTask": "kill-umbraco-web-ui",
6566
// Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
6667
"serverReadyAction": {
6768
"action": "openExternally",
@@ -96,6 +97,7 @@
9697
"stopAtEntry": false,
9798
"requireExactSource": false,
9899
"checkForDevCert": true,
100+
"postDebugTask": "kill-umbraco-web-ui",
99101
"env": {
100102
"ASPNETCORE_ENVIRONMENT": "Development",
101103
"ASPNETCORE_URLS": "https://localhost:44339",

.vscode/tasks.json

Lines changed: 85 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,87 @@
11
{
2-
"version": "2.0.0",
3-
"tasks": [
4-
{
5-
"label": "Build",
6-
"detail": "Builds the client and SLN",
7-
"promptOnClose": true,
8-
"group": "build",
9-
"dependsOn": [
10-
"Client Build",
11-
"Dotnet build"
12-
],
13-
"problemMatcher": []
14-
},
15-
{
16-
"label": "Client Install",
17-
"detail": "install npm for Umbraco.Web.UI.Client",
18-
"promptOnClose": true,
19-
"type": "npm",
20-
"script": "install",
21-
"path": "src/Umbraco.Web.UI.Client/",
22-
"problemMatcher": []
23-
},
24-
{
25-
"label": "Client Build",
26-
"detail": "runs npm run build for Umbraco.Web.UI.Client",
27-
"promptOnClose": true,
28-
"group": "build",
29-
"type": "npm",
30-
"script": "build:for:cms",
31-
"path": "src/Umbraco.Web.UI.Client/",
32-
"problemMatcher": []
33-
},
34-
{
35-
"label": "Client Watch",
36-
"detail": "runs npm run dev for Umbraco.Web.UI.Client",
37-
"promptOnClose": true,
38-
"group": "build",
39-
"type": "npm",
40-
"script": "dev",
41-
"path": "src/Umbraco.Web.UI.Client/",
42-
"problemMatcher": []
43-
},
44-
{
45-
"label": "Dotnet build",
46-
"detail": "Dotnet build of SLN",
47-
"promptOnClose": true,
48-
"group": "build",
49-
"command": "dotnet",
50-
"type": "process",
51-
"args": [
52-
"build",
53-
"${workspaceFolder}/umbraco.sln",
54-
"/property:GenerateFullPaths=true",
55-
"/consoleloggerparameters:NoSummary"
56-
],
57-
"problemMatcher": "$msCompile"
58-
},
59-
{
60-
"label": "Dotnet watch",
61-
"detail": "Dotnet run and watch of Web.UI",
62-
"promptOnClose": true,
63-
"command": "dotnet",
64-
"type": "process",
65-
"args": [
66-
"watch",
67-
"run",
68-
"--project",
69-
"${workspaceFolder}/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj",
70-
"/property:GenerateFullPaths=true",
71-
"/consoleloggerparameters:NoSummary"
72-
],
73-
"problemMatcher": "$msCompile"
74-
}
75-
]
2+
"version": "2.0.0",
3+
"tasks": [
4+
{
5+
"label": "Build",
6+
"detail": "Builds the client and SLN",
7+
"promptOnClose": true,
8+
"group": "build",
9+
"dependsOn": ["Client Build", "Dotnet build"],
10+
"problemMatcher": []
11+
},
12+
{
13+
"label": "Client Install",
14+
"detail": "install npm for Umbraco.Web.UI.Client",
15+
"promptOnClose": true,
16+
"type": "npm",
17+
"script": "install",
18+
"path": "src/Umbraco.Web.UI.Client/",
19+
"problemMatcher": []
20+
},
21+
{
22+
"label": "Client Build",
23+
"detail": "runs npm run build for Umbraco.Web.UI.Client",
24+
"promptOnClose": true,
25+
"group": "build",
26+
"type": "npm",
27+
"script": "build:for:cms",
28+
"path": "src/Umbraco.Web.UI.Client/",
29+
"problemMatcher": []
30+
},
31+
{
32+
"label": "Client Watch",
33+
"detail": "runs npm run dev for Umbraco.Web.UI.Client",
34+
"promptOnClose": true,
35+
"group": "build",
36+
"type": "npm",
37+
"script": "dev",
38+
"path": "src/Umbraco.Web.UI.Client/",
39+
"problemMatcher": []
40+
},
41+
{
42+
"label": "Dotnet build",
43+
"detail": "Dotnet build of SLN",
44+
"promptOnClose": true,
45+
"group": "build",
46+
"command": "dotnet",
47+
"type": "process",
48+
"args": [
49+
"build",
50+
"${workspaceFolder}/umbraco.sln",
51+
"/property:GenerateFullPaths=true",
52+
"/consoleloggerparameters:NoSummary"
53+
],
54+
"problemMatcher": "$msCompile"
55+
},
56+
{
57+
"label": "Dotnet watch",
58+
"detail": "Dotnet run and watch of Web.UI",
59+
"promptOnClose": true,
60+
"command": "dotnet",
61+
"type": "process",
62+
"args": [
63+
"watch",
64+
"run",
65+
"--project",
66+
"${workspaceFolder}/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj",
67+
"/property:GenerateFullPaths=true",
68+
"/consoleloggerparameters:NoSummary"
69+
],
70+
"problemMatcher": "$msCompile"
71+
},
72+
{
73+
"label": "kill-umbraco-web-ui",
74+
"type": "shell",
75+
"problemMatcher": [],
76+
"osx": {
77+
"command": "pkill -f Umbraco.Web.UI"
78+
},
79+
"linux": {
80+
"command": "pkill -f Umbraco.Web.UI"
81+
},
82+
"windows": {
83+
"command": "taskkill /IM Umbraco.Web.UI.exe /F"
84+
}
85+
}
86+
]
7687
}

src/Umbraco.Web.UI.Client/package-lock.json

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

src/Umbraco.Web.UI.Client/src/apps/app/app-auth.controller.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export class UmbAppAuthController extends UmbControllerBase {
2121
this.observe(
2222
context?.timeoutSignal,
2323
() => {
24+
console.log('[UmbAppAuthController] Authorization timed out, starting authorization flow');
2425
this.makeAuthorizationRequest('timedOut');
2526
},
2627
'_authState',

src/Umbraco.Web.UI.Client/src/apps/backoffice/backoffice.element.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,22 +66,25 @@ export class UmbBackofficeElement extends UmbLitElement {
6666

6767
new UmbBackofficeEntryPointExtensionInitializer(this, umbExtensionsRegistry);
6868
new UmbEntryPointExtensionInitializer(this, umbExtensionsRegistry);
69+
}
70+
71+
override async firstUpdated() {
72+
await this.#extensionsAfterAuth();
6973

70-
// So far local packages are this simple to registerer, so no need for a manager to do that:
74+
// So far local packages are this simple to register, so no need for a manager to do that:
7175
CORE_PACKAGES.forEach(async (packageImport) => {
7276
const packageModule = await packageImport;
7377
umbExtensionsRegistry.registerMany(packageModule.extensions);
7478
});
79+
}
7580

76-
const serverExtensions = new UmbServerExtensionRegistrator(this, umbExtensionsRegistry);
77-
78-
// TODO: We need to ensure this request is called every time the user logs in, but this should be done somewhere across the app and not here [JOV]
79-
this.consumeContext(UMB_AUTH_CONTEXT, (authContext) => {
80-
this.observe(authContext?.isAuthorized, (isAuthorized) => {
81-
if (!isAuthorized) return;
82-
serverExtensions.registerPrivateExtensions();
83-
});
84-
});
81+
async #extensionsAfterAuth() {
82+
const authContext = await this.getContext(UMB_AUTH_CONTEXT, { preventTimeout: true });
83+
if (!authContext) {
84+
throw new Error('UmbBackofficeElement requires the UMB_AUTH_CONTEXT to be set.');
85+
}
86+
await this.observe(authContext.isAuthorized).asPromise();
87+
await new UmbServerExtensionRegistrator(this, umbExtensionsRegistry).registerPrivateExtensions();
8588
}
8689

8790
override render() {

src/Umbraco.Web.UI.Client/src/external/rxjs/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,7 @@ export {
2121
switchMap,
2222
takeUntil,
2323
tap,
24+
delay,
25+
throttleTime,
26+
auditTime,
2427
} from 'rxjs';

0 commit comments

Comments
 (0)