mirror of
https://github.com/Joxit/docker-registry-ui.git
synced 2025-04-30 17:09:55 +03:00
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:
parent
b9a157c943
commit
6314e8b11e
5 changed files with 94 additions and 12 deletions
|
@ -69,6 +69,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
state.registryUrl = props.registryUrl;
|
state.registryUrl = props.registryUrl;
|
||||||
let repositories = [];
|
let repositories = [];
|
||||||
const self = this;
|
const self = this;
|
||||||
|
const catalogUrl = `${props.registryUrl}/v2/_catalog?n=${state.catalogElementsLimit}`;
|
||||||
const oReq = new Http({
|
const oReq = new Http({
|
||||||
onAuthentication: this.props.onAuthentication,
|
onAuthentication: this.props.onAuthentication,
|
||||||
});
|
});
|
||||||
|
@ -93,7 +94,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
return acc;
|
return acc;
|
||||||
}, []);
|
}, []);
|
||||||
} else if (this.status === 404) {
|
} else if (this.status === 404) {
|
||||||
self.props.onNotify('Server not found', true);
|
self.props.onNotify({ code: 'CATALOG_NOT_FOUND', url: catalogUrl }, true);
|
||||||
} else {
|
} else {
|
||||||
self.props.onNotify(this.responseText);
|
self.props.onNotify(this.responseText);
|
||||||
}
|
}
|
||||||
|
@ -109,7 +110,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
loadend: true,
|
loadend: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
oReq.open('GET', `${props.registryUrl}/v2/_catalog?n=${state.catalogElementsLimit}`);
|
oReq.open('GET', catalogUrl);
|
||||||
oReq.send();
|
oReq.send();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -109,9 +109,13 @@
|
||||||
'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json'
|
'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json'
|
||||||
);
|
);
|
||||||
oReq.addEventListener('error', function () {
|
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({
|
onNotify({
|
||||||
message:
|
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,
|
isError: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -80,6 +80,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
on-authenticated="{ state.onAuthenticated }"
|
on-authenticated="{ state.onAuthenticated }"
|
||||||
opened="{ state.authenticationDialogOpened }"
|
opened="{ state.authenticationDialogOpened }"
|
||||||
></registry-authentication>
|
></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>
|
<material-snackbar message="{ state.snackbarMessage }" is-error="{ state.snackbarIsError }"></material-snackbar>
|
||||||
</main>
|
</main>
|
||||||
<footer>
|
<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 TagHistory from './tag-history/tag-history.riot';
|
||||||
import DialogsMenu from './dialogs/dialogs-menu.riot';
|
import DialogsMenu from './dialogs/dialogs-menu.riot';
|
||||||
import SearchBar from './search-bar.riot';
|
import SearchBar from './search-bar.riot';
|
||||||
|
import ErrorPage from './error-page.riot';
|
||||||
import { stripHttps, getRegistryServers, setRegistryServers, truthy, stringToArray } from '../scripts/utils';
|
import { stripHttps, getRegistryServers, setRegistryServers, truthy, stringToArray } from '../scripts/utils';
|
||||||
import router from '../scripts/router';
|
import router from '../scripts/router';
|
||||||
import { loadTheme } from '../scripts/theme';
|
import { loadTheme } from '../scripts/theme';
|
||||||
|
@ -118,6 +126,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
SearchBar,
|
SearchBar,
|
||||||
Router,
|
Router,
|
||||||
Route,
|
Route,
|
||||||
|
ErrorPage,
|
||||||
},
|
},
|
||||||
onUpdated(props, state) {
|
onUpdated(props, state) {
|
||||||
state.snackbarIsError = false;
|
state.snackbarIsError = false;
|
||||||
|
@ -184,6 +193,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
snackbarMessage: message,
|
snackbarMessage: message,
|
||||||
snackbarIsError: isError || false,
|
snackbarIsError: isError || false,
|
||||||
});
|
});
|
||||||
|
} else if (message && message.code) {
|
||||||
|
this.update({
|
||||||
|
pageError: message,
|
||||||
|
});
|
||||||
|
setTimeout(() => delete this.state['pageError'], 1000);
|
||||||
} else if (message && message.message) {
|
} else if (message && message.message) {
|
||||||
this.update({
|
this.update({
|
||||||
snackbarMessage: message.message,
|
snackbarMessage: message.message,
|
||||||
|
|
69
src/components/error-page.riot
Normal file
69
src/components/error-page.riot
Normal 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>
|
|
@ -71,7 +71,7 @@ export class Http {
|
||||||
req.withCredentials = true;
|
req.withCredentials = true;
|
||||||
}
|
}
|
||||||
req.hasHeader = hasHeader;
|
req.hasHeader = hasHeader;
|
||||||
req.getErrorMessage = Http.getErrorMessage;
|
req.getErrorMessage = getErrorMessage;
|
||||||
self.oReq = req;
|
self.oReq = req;
|
||||||
req.send();
|
req.send();
|
||||||
});
|
});
|
||||||
|
@ -128,15 +128,9 @@ const hasHeader = function (header) {
|
||||||
|
|
||||||
const getErrorMessage = function () {
|
const getErrorMessage = function () {
|
||||||
if (this._url.match('^http://') && window.location.protocol === 'https:') {
|
if (this._url.match('^http://') && window.location.protocol === 'https:') {
|
||||||
return (
|
return { code: 'MIXED_CONTENT', url: this._url };
|
||||||
'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.'
|
|
||||||
);
|
|
||||||
} else if (!this._url || !this._url.match('^http')) {
|
} 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')) {
|
} else if (this.withCredentials && !this.hasHeader('Access-Control-Allow-Credentials')) {
|
||||||
return (
|
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 `" +
|
"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 `" +
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue