Skip to content

Commit 6314e8b

Browse files
committed
feat(error-page): add a full page for specific errors
This may help people to save their issues fixes #230
1 parent b9a157c commit 6314e8b

File tree

5 files changed

+94
-12
lines changed

5 files changed

+94
-12
lines changed

src/components/catalog/catalog.riot

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
6969
state.registryUrl = props.registryUrl;
7070
let repositories = [];
7171
const self = this;
72+
const catalogUrl = `${props.registryUrl}/v2/_catalog?n=${state.catalogElementsLimit}`;
7273
const oReq = new Http({
7374
onAuthentication: this.props.onAuthentication,
7475
});
@@ -93,7 +94,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
9394
return acc;
9495
}, []);
9596
} else if (this.status === 404) {
96-
self.props.onNotify('Server not found', true);
97+
self.props.onNotify({ code: 'CATALOG_NOT_FOUND', url: catalogUrl }, true);
9798
} else {
9899
self.props.onNotify(this.responseText);
99100
}
@@ -109,7 +110,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
109110
loadend: true,
110111
});
111112
});
112-
oReq.open('GET', `${props.registryUrl}/v2/_catalog?n=${state.catalogElementsLimit}`);
113+
oReq.open('GET', catalogUrl);
113114
oReq.send();
114115
},
115116
};

src/components/dialogs/confirm-delete-image.riot

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,13 @@
109109
'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json'
110110
);
111111
oReq.addEventListener('error', function () {
112+
const credMsg = this.withCredentials
113+
? ' When you use credentials on a different hostname, the registry server may fail preflight requests. Check FAQ and issue #104.'
114+
: '';
112115
onNotify({
113116
message:
114-
"An error occurred when deleting image. Check if your server accept DELETE methods Access-Control-Allow-Methods: ['DELETE'].",
117+
"An error occurred when deleting image. Check if your server accept DELETE methods Access-Control-Allow-Methods: ['DELETE']." +
118+
credMsg,
115119
isError: true,
116120
});
117121
});

src/components/docker-registry-ui.riot

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
8080
on-authenticated="{ state.onAuthenticated }"
8181
opened="{ state.authenticationDialogOpened }"
8282
></registry-authentication>
83+
<error-page
84+
if="{ state.pageError }"
85+
code="{ state.pageError.code }"
86+
status="{ state.pageError.status }"
87+
message="{ state.pageError.message }"
88+
url="{ state.pageError.url }"
89+
></error-page>
8390
<material-snackbar message="{ state.snackbarMessage }" is-error="{ state.snackbarIsError }"></material-snackbar>
8491
</main>
8592
<footer>
@@ -105,6 +112,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
105112
import TagHistory from './tag-history/tag-history.riot';
106113
import DialogsMenu from './dialogs/dialogs-menu.riot';
107114
import SearchBar from './search-bar.riot';
115+
import ErrorPage from './error-page.riot';
108116
import { stripHttps, getRegistryServers, setRegistryServers, truthy, stringToArray } from '../scripts/utils';
109117
import router from '../scripts/router';
110118
import { loadTheme } from '../scripts/theme';
@@ -118,6 +126,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
118126
SearchBar,
119127
Router,
120128
Route,
129+
ErrorPage,
121130
},
122131
onUpdated(props, state) {
123132
state.snackbarIsError = false;
@@ -184,6 +193,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
184193
snackbarMessage: message,
185194
snackbarIsError: isError || false,
186195
});
196+
} else if (message && message.code) {
197+
this.update({
198+
pageError: message,
199+
});
200+
setTimeout(() => delete this.state['pageError'], 1000);
187201
} else if (message && message.message) {
188202
this.update({
189203
snackbarMessage: message.message,

src/components/error-page.riot

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<error-page>
2+
<div class="content">
3+
<h1 if="{ getStatusCode() }">{ getStatusCode() }</h1>
4+
<h2>{ props.code }</h2>
5+
<template if="{ props.code === 'CATALOG_NOT_FOUND' }">
6+
<p>We received a 404 status code from your registry.</p>
7+
<p>The contact point was <a href="{ props.url }">{ props.url }</a></p>
8+
<p>
9+
This may be caused by a misconfiguration of Docker Registry UI. Check the
10+
<a href="https://joxit.dev/docker-registry-ui/#faq">FAQ</a> and
11+
<a href="https://joxit.dev/docker-registry-ui/#available-options">Available options</a>
12+
</p>
13+
</template>
14+
<template if="{ props.code === 'MIXED_CONTENT' }">
15+
<p>
16+
<span>Mixed Content</span>: The page at `<a href="{ window.location.origin }">{ window.location.origin }</a>`
17+
was loaded over HTTPS, but requested an insecure server endpoint `<a href="{ new URL(props.url).origin }"
18+
>{ new URL(props.url).origin }</a
19+
>`.
20+
</p>
21+
<p>This request <span>may</span> has been blocked; the content must be served over HTTPS.</p>
22+
<p>
23+
You may unset the option `<span>REGISTRY_URL</span>` and set the registry server container URL in
24+
`<span>NGINX_PROXY_PASS_URL</span>`. It's usually the name of your container, and it should be on the shame
25+
network as the UI.
26+
</p>
27+
<p>You can check the issue <a href="https://github.com/Joxit/docker-registry-ui/issues/277">#277</a>.</p>
28+
</template>
29+
<template if="{ props.code === 'INCORRECT_URL' }">
30+
<p>`{ props.url }` does not seems to be a correct URL, should starts with http:// or https://.</p>
31+
</template>
32+
</div>
33+
<script>
34+
export default {
35+
getStatusCode() {
36+
const { props } = this;
37+
switch (props.code) {
38+
case 'CATALOG_NOT_FOUND':
39+
return '404';
40+
}
41+
},
42+
URL: window.URL,
43+
};
44+
</script>
45+
<style>
46+
:host {
47+
display: flex;
48+
flex-direction: row;
49+
margin-top: 20px;
50+
}
51+
:host .content {
52+
margin: auto;
53+
text-align: center;
54+
}
55+
:host .content a {
56+
color: var(--accent-text);
57+
}
58+
:host .content a:visited {
59+
color: var(--accent-text);
60+
}
61+
:host .content p span {
62+
color: var(--accent-text);
63+
font-weight: 700;
64+
}
65+
:host .content h2 {
66+
font-weight: 700;
67+
}
68+
</style>
69+
</error-page>

src/scripts/http.js

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export class Http {
7171
req.withCredentials = true;
7272
}
7373
req.hasHeader = hasHeader;
74-
req.getErrorMessage = Http.getErrorMessage;
74+
req.getErrorMessage = getErrorMessage;
7575
self.oReq = req;
7676
req.send();
7777
});
@@ -128,15 +128,9 @@ const hasHeader = function (header) {
128128

129129
const getErrorMessage = function () {
130130
if (this._url.match('^http://') && window.location.protocol === 'https:') {
131-
return (
132-
'Mixed Content: The page at `' +
133-
window.location.origin +
134-
'` was loaded over HTTPS, but requested an insecure server endpoint `' +
135-
new URL(this._url).origin +
136-
'`. This request has been blocked; the content must be served over HTTPS.'
137-
);
131+
return { code: 'MIXED_CONTENT', url: this._url };
138132
} else if (!this._url || !this._url.match('^http')) {
139-
return 'Incorrect server endpoint.';
133+
return { code: 'INCORRECT_URL', url: this._url };
140134
} else if (this.withCredentials && !this.hasHeader('Access-Control-Allow-Credentials')) {
141135
return (
142136
"The `Access-Control-Allow-Credentials` header in the response is missing and must be set to `true` when the request's credentials mode is on. Origin `" +

0 commit comments

Comments
 (0)