feat(error-page): add a full page for specific errors

This may help people to save their issues

fixes #230
This commit is contained in:
Joxit 2023-02-01 21:54:18 +01:00
parent b9a157c943
commit 6314e8b11e
No known key found for this signature in database
GPG Key ID: F526592B8E012263
5 changed files with 94 additions and 12 deletions

View File

@ -69,6 +69,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
state.registryUrl = props.registryUrl;
let repositories = [];
const self = this;
const catalogUrl = `${props.registryUrl}/v2/_catalog?n=${state.catalogElementsLimit}`;
const oReq = new Http({
onAuthentication: this.props.onAuthentication,
});
@ -93,7 +94,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
return acc;
}, []);
} else if (this.status === 404) {
self.props.onNotify('Server not found', true);
self.props.onNotify({ code: 'CATALOG_NOT_FOUND', url: catalogUrl }, true);
} else {
self.props.onNotify(this.responseText);
}
@ -109,7 +110,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
loadend: true,
});
});
oReq.open('GET', `${props.registryUrl}/v2/_catalog?n=${state.catalogElementsLimit}`);
oReq.open('GET', catalogUrl);
oReq.send();
},
};

View File

@ -109,9 +109,13 @@
'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json'
);
oReq.addEventListener('error', function () {
const credMsg = this.withCredentials
? ' When you use credentials on a different hostname, the registry server may fail preflight requests. Check FAQ and issue #104.'
: '';
onNotify({
message:
"An error occurred when deleting image. Check if your server accept DELETE methods Access-Control-Allow-Methods: ['DELETE'].",
"An error occurred when deleting image. Check if your server accept DELETE methods Access-Control-Allow-Methods: ['DELETE']." +
credMsg,
isError: true,
});
});

View File

@ -80,6 +80,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
on-authenticated="{ state.onAuthenticated }"
opened="{ state.authenticationDialogOpened }"
></registry-authentication>
<error-page
if="{ state.pageError }"
code="{ state.pageError.code }"
status="{ state.pageError.status }"
message="{ state.pageError.message }"
url="{ state.pageError.url }"
></error-page>
<material-snackbar message="{ state.snackbarMessage }" is-error="{ state.snackbarIsError }"></material-snackbar>
</main>
<footer>
@ -105,6 +112,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import TagHistory from './tag-history/tag-history.riot';
import DialogsMenu from './dialogs/dialogs-menu.riot';
import SearchBar from './search-bar.riot';
import ErrorPage from './error-page.riot';
import { stripHttps, getRegistryServers, setRegistryServers, truthy, stringToArray } from '../scripts/utils';
import router from '../scripts/router';
import { loadTheme } from '../scripts/theme';
@ -118,6 +126,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
SearchBar,
Router,
Route,
ErrorPage,
},
onUpdated(props, state) {
state.snackbarIsError = false;
@ -184,6 +193,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
snackbarMessage: message,
snackbarIsError: isError || false,
});
} else if (message && message.code) {
this.update({
pageError: message,
});
setTimeout(() => delete this.state['pageError'], 1000);
} else if (message && message.message) {
this.update({
snackbarMessage: message.message,

View File

@ -0,0 +1,69 @@
<error-page>
<div class="content">
<h1 if="{ getStatusCode() }">{ getStatusCode() }</h1>
<h2>{ props.code }</h2>
<template if="{ props.code === 'CATALOG_NOT_FOUND' }">
<p>We received a 404 status code from your registry.</p>
<p>The contact point was <a href="{ props.url }">{ props.url }</a></p>
<p>
This may be caused by a misconfiguration of Docker Registry UI. Check the
<a href="https://joxit.dev/docker-registry-ui/#faq">FAQ</a> and
<a href="https://joxit.dev/docker-registry-ui/#available-options">Available options</a>
</p>
</template>
<template if="{ props.code === 'MIXED_CONTENT' }">
<p>
<span>Mixed Content</span>: The page at `<a href="{ window.location.origin }">{ window.location.origin }</a>`
was loaded over HTTPS, but requested an insecure server endpoint `<a href="{ new URL(props.url).origin }"
>{ new URL(props.url).origin }</a
>`.
</p>
<p>This request <span>may</span> has been blocked; the content must be served over HTTPS.</p>
<p>
You may unset the option `<span>REGISTRY_URL</span>` and set the registry server container URL in
`<span>NGINX_PROXY_PASS_URL</span>`. It's usually the name of your container, and it should be on the shame
network as the UI.
</p>
<p>You can check the issue <a href="https://github.com/Joxit/docker-registry-ui/issues/277">#277</a>.</p>
</template>
<template if="{ props.code === 'INCORRECT_URL' }">
<p>`{ props.url }` does not seems to be a correct URL, should starts with http:// or https://.</p>
</template>
</div>
<script>
export default {
getStatusCode() {
const { props } = this;
switch (props.code) {
case 'CATALOG_NOT_FOUND':
return '404';
}
},
URL: window.URL,
};
</script>
<style>
:host {
display: flex;
flex-direction: row;
margin-top: 20px;
}
:host .content {
margin: auto;
text-align: center;
}
:host .content a {
color: var(--accent-text);
}
:host .content a:visited {
color: var(--accent-text);
}
:host .content p span {
color: var(--accent-text);
font-weight: 700;
}
:host .content h2 {
font-weight: 700;
}
</style>
</error-page>

View File

@ -71,7 +71,7 @@ export class Http {
req.withCredentials = true;
}
req.hasHeader = hasHeader;
req.getErrorMessage = Http.getErrorMessage;
req.getErrorMessage = getErrorMessage;
self.oReq = req;
req.send();
});
@ -128,15 +128,9 @@ const hasHeader = function (header) {
const getErrorMessage = function () {
if (this._url.match('^http://') && window.location.protocol === 'https:') {
return (
'Mixed Content: The page at `' +
window.location.origin +
'` was loaded over HTTPS, but requested an insecure server endpoint `' +
new URL(this._url).origin +
'`. This request has been blocked; the content must be served over HTTPS.'
);
return { code: 'MIXED_CONTENT', url: this._url };
} else if (!this._url || !this._url.match('^http')) {
return 'Incorrect server endpoint.';
return { code: 'INCORRECT_URL', url: this._url };
} else if (this.withCredentials && !this.hasHeader('Access-Control-Allow-Credentials')) {
return (
"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 `" +