Compare commits
8 Commits
Author | SHA1 | Date |
---|---|---|
silverwind | a36e3aac57 | |
Lukas Engelter | 7025df687c | |
Lukas Engelter | cfbc6e76a8 | |
toinux | dc9bdcbedd | |
Joxit | 6c3c27e215 | |
Jones Magloire | 6318ccfdf5 | |
Christian | 686b1709b2 | |
Joxit | e79a20a5e5 |
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
name: Custom issue template
|
||||
about: Describe this issue template's purpose here.
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
17
README.md
17
README.md
|
@ -119,7 +119,7 @@ Some env options are available for use this interface for **only one server** (w
|
|||
- `CATALOG_MAX_BRANCHES`: Set the maximum repository/namespace to expand (e.g. `joxit/docker-registry-ui` `joxit/` is the repository/namespace). Can be 0 to disable branching. (see [#319](https://github.com/Joxit/docker-registry-ui/pull/319)). (default: `1`). Since 2.5.0
|
||||
- `TAGLIST_PAGE_SIZE`: Set the number of tags to display in one page. (default: `100`). Since 2.5.0
|
||||
- `REGISTRY_SECURED`: By default, the UI will check on every requests if your registry is secured or not (you will see `401` responses in your console). Set to `true` if your registry uses Basic Authentication and divide by two the number of call to your registry. (default `false`). Since 2.5.0
|
||||
|
||||
- `SHOW_TAG_HISTORY`: Whether to show the tag history feature or not. Allows to simplify the user interface by hiding it form the tag list if set to `false`. (default: `true`).
|
||||
There are some examples with [docker-compose](https://docs.docker.com/compose/) and docker-registry-ui as proxy [here](https://github.com/Joxit/docker-registry-ui/tree/main/examples/ui-as-proxy/) or docker-registry-ui as standalone [here](https://github.com/Joxit/docker-registry-ui/tree/main/examples/ui-as-standalone/).
|
||||
|
||||
### Theme options
|
||||
|
@ -128,16 +128,17 @@ This featureswas added to version 2.4.0. See more about this in [#283](https://g
|
|||
|
||||
| Environment variable | light theme value | dark theme value |
|
||||
| --- | --- | --- |
|
||||
| `THEME_PRIMARY_TEXT` | `#25313b` | `#8A9EBA` |
|
||||
| `THEME_NEUTRAL_TEXT` | `#777777` | `#36527A` |
|
||||
| `THEME_PRIMARY_TEXT` | `#25313b` | `#98a8bd` |
|
||||
| `THEME_NEUTRAL_TEXT` | `#777777` | `#6d7fab` |
|
||||
| `THEME_BACKGROUND` | `#ffffff` | `#22272e` |
|
||||
| `THEME_HOVER_BACKGROUND` | `#eeeeee` | `#30404D` |
|
||||
| `THEME_ACCENT_TEXT` | `#6680a1` | `#5684FF` |
|
||||
| `THEME_HOVER_BACKGROUND` | `#eeeeee` | `#343a4b` |
|
||||
| `THEME_ACCENT_TEXT` | `#5f7796` | `#5c88ff` |
|
||||
| `THEME_HEADER_TEXT` | `#ffffff` | `#ffffff` |
|
||||
| `THEME_HEADER_BACKGROUND` | `#25313b` | `#333A45` |
|
||||
| `THEME_HEADER_ACCENT_TEXT` | `#7b9ac2` | `#7ea1ff` |
|
||||
| `THEME_HEADER_BACKGROUND` | `#25313b` | `#333a45` |
|
||||
| `THEME_FOOTER_TEXT` | `#ffffff` | `#ffffff` |
|
||||
| `THEME_FOOTER_NEUTRAL_TEXT` | `#999999` | `#999999` |
|
||||
| `THEME_FOOTER_BACKGROUND` | `#555555` | `#555555` |
|
||||
| `THEME_FOOTER_NEUTRAL_TEXT` | `#adbacd` | `#98afcf` |
|
||||
| `THEME_FOOTER_BACKGROUND` | `#344251` | `#344251` |
|
||||
|
||||
## Recommended Docker Registry Usage
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ sed -i "s~\${PULL_URL}~${PULL_URL}~" index.html
|
|||
sed -i "s~\${SINGLE_REGISTRY}~${SINGLE_REGISTRY}~" index.html
|
||||
sed -i "s~\${CATALOG_ELEMENTS_LIMIT}~${CATALOG_ELEMENTS_LIMIT}~" index.html
|
||||
sed -i "s~\${SHOW_CONTENT_DIGEST}~${SHOW_CONTENT_DIGEST}~" index.html
|
||||
sed -i "s~\${SHOW_TAG_HISTORY}~${SHOW_TAG_HISTORY}~" index.html
|
||||
sed -i "s~\${DEFAULT_REGISTRIES}~${DEFAULT_REGISTRIES}~" index.html
|
||||
sed -i "s~\${READ_ONLY_REGISTRIES}~${READ_ONLY_REGISTRIES}~" index.html
|
||||
sed -i "s~\${SHOW_CATALOG_NB_TAGS}~${SHOW_CATALOG_NB_TAGS}~" index.html
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -2,9 +2,12 @@
|
|||
|
||||
This example will override the original nginx conf with read only access to the registry. You will need to rewrite all the project configuration (replaces `proxy_pass` with your own value, in this example `http://registry:5000` is fine).
|
||||
|
||||
There are two htpasswd files. `read-write.htpasswd` a read and write access to the registry and `read-only.htpasswd` for a read only access.
|
||||
There are two htpasswd files:
|
||||
|
||||
All users in `read-only.htpasswd` should be in `read-write.htpasswd`.
|
||||
- `write.htpasswd` for write access
|
||||
- `read.htpasswd` for read access
|
||||
|
||||
All users in `write.htpasswd` should also be in `read.htpasswd` so that they can read and write.
|
||||
|
||||
Read only user: login: `read` password: `registry`.
|
||||
Read and write user: login: `write` password: `registry`.
|
||||
|
|
|
@ -17,11 +17,11 @@ services:
|
|||
- SINGLE_REGISTRY=true
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/conf.d/default.conf
|
||||
- ./read-write.htpasswd:/etc/nginx/auth/read-write.htpasswd:ro
|
||||
- ./read-only.htpasswd:/etc/nginx/auth/read-only.htpasswd
|
||||
- ./read-write.htpasswd:/etc/nginx/auth/write.htpasswd:ro
|
||||
- ./read-only.htpasswd:/etc/nginx/auth/read.htpasswd:ro
|
||||
depends_on:
|
||||
- registry
|
||||
networks:
|
||||
- registry-ui-net
|
||||
networks:
|
||||
registry-ui-net:
|
||||
registry-ui-net:
|
||||
|
|
|
@ -28,10 +28,10 @@ server {
|
|||
}
|
||||
# To add basic authentication to v2 use auth_basic setting.
|
||||
auth_basic "Registry realm";
|
||||
auth_basic_user_file /etc/nginx/auth/read-write.htpasswd;
|
||||
# For requests that *aren't* a PUT, POST, or DELETE
|
||||
limit_except PUT POST DELETE {
|
||||
auth_basic_user_file /etc/nginx/auth/read-only.htpasswd;
|
||||
auth_basic_user_file /etc/nginx/auth/read.htpasswd;
|
||||
# For requests that *aren't* a GET, HEAD or OPTIONS use the write file instead
|
||||
limit_except GET HEAD OPTIONS {
|
||||
auth_basic_user_file /etc/nginx/auth/write.htpasswd;
|
||||
}
|
||||
|
||||
proxy_pass http://registry:5000;
|
||||
|
|
|
@ -5,8 +5,11 @@ server {
|
|||
# charset koi8-r;
|
||||
# access_log /var/log/nginx/host.access.log main;
|
||||
|
||||
# disable any limits to avoid HTTP 413 for large image uploads
|
||||
# disable any limits to avoid HTTP 413 for large image uploads and 400 on large headers (eg: cookie)
|
||||
client_max_body_size 0;
|
||||
client_body_buffer_size 32k;
|
||||
client_header_buffer_size 8k;
|
||||
large_client_header_buffers 8 64k;
|
||||
|
||||
# required to avoid HTTP 411: see Issue #1486 (https://github.com/moby/moby/issues/1486)
|
||||
chunked_transfer_encoding on;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "docker-registry-ui",
|
||||
"version": "2.5.5",
|
||||
"version": "2.5.7",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"format": "npm run format-html && npm run format-js && npm run format-riot",
|
||||
|
|
|
@ -72,6 +72,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
pull-url="{ state.pullUrl }"
|
||||
image="{ router.getTagListImage() }"
|
||||
show-content-digest="{ truthy(props.showContentDigest) }"
|
||||
show-tag-history="{ falsy(props.showTagHistory) }"
|
||||
is-image-remove-activated="{ truthy(props.isImageRemoveActivated) }"
|
||||
on-notify="{ notifySnackbar }"
|
||||
filter-results="{ state.filter }"
|
||||
|
@ -146,7 +147,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
import SearchBar from './search-bar.riot';
|
||||
import ErrorPage from './error-page.riot';
|
||||
import VersionNotification from './version-notification.riot';
|
||||
import { stripHttps, getRegistryServers, setRegistryServers, truthy, stringToArray } from '../scripts/utils';
|
||||
import { stripHttps, getRegistryServers, setRegistryServers, truthy, falsy, stringToArray } from '../scripts/utils';
|
||||
import router from '../scripts/router';
|
||||
import { loadTheme } from '../scripts/theme';
|
||||
|
||||
|
@ -262,6 +263,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
version,
|
||||
latest,
|
||||
truthy,
|
||||
falsy,
|
||||
stringToArray,
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<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
|
||||
`<span>NGINX_PROXY_PASS_URL</span>`. It's usually the name of your container, and it should be on the same
|
||||
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>
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
<material-input
|
||||
label="Search in page"
|
||||
text-color="var(--header-text)"
|
||||
label-color="var(--neutral-text)"
|
||||
color="var(--accent-text)"
|
||||
label-color="var(--header-accent-text)"
|
||||
color="var(--header-accent-text)"
|
||||
></material-input>
|
||||
<script>
|
||||
import { router } from '@riotjs/route';
|
||||
|
|
|
@ -287,5 +287,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
h2 .material-icons {
|
||||
margin-left: .25em;
|
||||
}
|
||||
</style>
|
||||
</tag-history>
|
||||
|
|
|
@ -50,6 +50,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
asc="{state.asc}"
|
||||
page="{ state.page }"
|
||||
show-content-digest="{props.showContentDigest}"
|
||||
show-tag-history="{props.showTagHistory}"
|
||||
is-image-remove-activated="{props.isImageRemoveActivated}"
|
||||
onReverseOrder="{ onReverseOrder }"
|
||||
registry-url="{ props.registryUrl }"
|
||||
|
@ -129,7 +130,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
.sort(self.tagComparator);
|
||||
window.requestAnimationFrame(self.onResize);
|
||||
self.update({
|
||||
page: Math.min(state.page, getNumPages(tags)),
|
||||
page: Math.min(state.page, getNumPages(tags, props.tagsPerPage)),
|
||||
tags,
|
||||
});
|
||||
} else if (this.status === 404) {
|
||||
|
@ -153,7 +154,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
},
|
||||
|
||||
onPageUpdate(idx) {
|
||||
const labels = getPageLabels(this.state.page, getNumPages(this.state.tags));
|
||||
const labels = getPageLabels(this.state.page, getNumPages(this.state.tags, this.props.tagsPerPage));
|
||||
const page = labels[idx].page;
|
||||
this.update({
|
||||
page: page,
|
||||
|
|
|
@ -52,7 +52,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
Tag
|
||||
</th>
|
||||
<th class="architectures">Arch</th>
|
||||
<th class="show-tag-history">History</th>
|
||||
<th class="show-tag-history" if="{ props.showTagHistory }">History</th>
|
||||
<th
|
||||
class="remove-tag { state.toDelete.size > 0 && !state.singleDeleteAction ? 'delete' : '' }"
|
||||
if="{ props.isImageRemoveActivated }"
|
||||
|
@ -109,7 +109,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
<td class="architectures">
|
||||
<architectures image="{ image }"></architectures>
|
||||
</td>
|
||||
<td class="show-tag-history">
|
||||
<td class="show-tag-history" if="{ props.showTagHistory }">
|
||||
<tag-history-button image="{ image }"></tag-history-button>
|
||||
</td>
|
||||
<td if="{ props.isImageRemoveActivated }" class="remove-tag">
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
if (latest && latest.tag_name) {
|
||||
this.update({ tag_name: latest.tag_name, latest });
|
||||
}
|
||||
if (!latest || isNaN(expires) || new Date().getTime() > expires) {
|
||||
if (isNaN(expires) || new Date().getTime() > expires) {
|
||||
this.checkForUpdates(props, state);
|
||||
}
|
||||
},
|
||||
|
@ -64,16 +64,22 @@
|
|||
const self = this;
|
||||
|
||||
oReq.addEventListener('load', function () {
|
||||
localStorage.setItem(EXPIRES, new Date().getTime() + ONE_DAY);
|
||||
if (this.status === 200) {
|
||||
const latest = parseJSON(this.responseText);
|
||||
if (latest && self.tag_name !== latest.tag_name && !isNewestVersion(props.version, latest.tag_name)) {
|
||||
props.onNotify('A new version of Docker Registry UI is available!');
|
||||
}
|
||||
localStorage.setItem(LATEST, this.responseText);
|
||||
localStorage.setItem(EXPIRES, new Date().getTime() + ONE_DAY);
|
||||
self.update({ tag_name: latest.tag_name, latest });
|
||||
} else {
|
||||
props.onNotify('Cannot check for new updates. See the browser console.');
|
||||
} else if (this.status !== 404) {
|
||||
// Should not notify if the project is not found.
|
||||
props.onNotify('Cannot check for new updates. Will try again in 24 hours. See the browser console.');
|
||||
|
||||
console.error(
|
||||
`Cannot check for new Docker Registry UI updates. This is most likely a GitHub issue. You don't need to worry about it.`
|
||||
);
|
||||
|
||||
console.error(`Got status code ${this.status} from Github API with response ${this.responseText}`);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
name="${REGISTRY_TITLE}"
|
||||
pull-url="${PULL_URL}"
|
||||
show-content-digest="${SHOW_CONTENT_DIGEST}"
|
||||
show-tag-history="${SHOW_TAG_HISTORY}"
|
||||
is-image-remove-activated="${DELETE_IMAGES}"
|
||||
catalog-elements-limit="${CATALOG_ELEMENTS_LIMIT}"
|
||||
single-registry="${SINGLE_REGISTRY}"
|
||||
|
@ -58,10 +59,11 @@
|
|||
theme-background="${THEME_BACKGROUND}"
|
||||
theme-hover-background="${THEME_HOVER_BACKGROUND}"
|
||||
theme-accent-text="${THEME_ACCENT_TEXT}"
|
||||
theme-header-accent-text="${THEME_HEADER_ACCENT_TEXT}"
|
||||
theme-header-text="${THEME_HEADER_TEXT}"
|
||||
theme-header-background="${THEME_HEADER_BACKGROUND}"
|
||||
theme-footer-text="${THEME_FOOTER_TEXT}"
|
||||
theme-footer-neutra-text="${THEME_FOOTER_NEUTRAL_TEXT}"
|
||||
theme-footer-neutral-text="${THEME_FOOTER_NEUTRAL_TEXT}"
|
||||
theme-footer-background="${THEME_FOOTER_BACKGROUND}"
|
||||
tags-per-page="${TAGLIST_PAGE_SIZE}"
|
||||
>
|
||||
|
@ -70,9 +72,10 @@
|
|||
<!-- build:keep developement -->
|
||||
<docker-registry-ui
|
||||
registry-url=""
|
||||
name="Developement Registry"
|
||||
name="Development Registry"
|
||||
pull-url=""
|
||||
show-content-digest="true"
|
||||
show-tag-history="true"
|
||||
is-image-remove-activated="true"
|
||||
catalog-elements-limit="1000"
|
||||
single-registry="false"
|
||||
|
@ -90,10 +93,11 @@
|
|||
theme-background=""
|
||||
theme-hover-background=""
|
||||
theme-accent-text=""
|
||||
theme-header-accent-text=""
|
||||
theme-header-text=""
|
||||
theme-header-background=""
|
||||
theme-footer-text=""
|
||||
theme-footer-neutra-text=""
|
||||
theme-footer-neutral-text=""
|
||||
theme-footer-background=""
|
||||
tags-per-page=""
|
||||
>
|
||||
|
|
|
@ -1,26 +1,28 @@
|
|||
const LIGHT_THEME = {
|
||||
'primary-text': '#25313b',
|
||||
'neutral-text': '#777',
|
||||
'background': '#fff',
|
||||
'hover-background': '#eee',
|
||||
'accent-text': '#6680a1',
|
||||
'header-text': '#fff',
|
||||
'neutral-text': '#777777',
|
||||
'background': '#ffffff',
|
||||
'hover-background': '#eeeeee',
|
||||
'accent-text': '#5f7796',
|
||||
'header-text': '#ffffff',
|
||||
'header-accent-text': '#7b9ac2',
|
||||
'header-background': '#25313b',
|
||||
'footer-text': '#fff',
|
||||
'footer-neutral-text': '#999',
|
||||
'footer-background': '#555',
|
||||
'footer-text': '#ffffff',
|
||||
'footer-neutral-text': '#adbacd',
|
||||
'footer-background': '#344251',
|
||||
};
|
||||
const DARK_THEME = {
|
||||
'primary-text': '#8A9EBA',
|
||||
'neutral-text': '#36527A',
|
||||
'primary-text': '#98a8bd',
|
||||
'neutral-text': '#6d7fab',
|
||||
'background': '#22272e',
|
||||
'hover-background': '#30404D',
|
||||
'accent-text': '#5684FF',
|
||||
'header-text': '#fff',
|
||||
'header-background': '#333A45',
|
||||
'footer-text': '#fff',
|
||||
'footer-neutral-text': '#999',
|
||||
'footer-background': '#555',
|
||||
'hover-background': '#343a4b',
|
||||
'accent-text': '#5c88ff',
|
||||
'header-text': '#ffffff',
|
||||
'header-accent-text': '#7ea1ff',
|
||||
'header-background': '#333a45',
|
||||
'footer-text': '#ffffff',
|
||||
'footer-neutral-text': '#98afcf',
|
||||
'footer-background': '#344251',
|
||||
};
|
||||
|
||||
const LOCAL_STORAGE_THEME = 'registryUiTheme';
|
||||
|
|
|
@ -217,6 +217,17 @@ export function truthy(value) {
|
|||
return value === true || value === 'true';
|
||||
}
|
||||
|
||||
/**
|
||||
* only is false if explicitly set to boolean false or string 'false'.
|
||||
* defaults to true in any other case, e.g. if empty.
|
||||
*
|
||||
* @param {string|boolean} value the input value to check
|
||||
* @returns {boolean} false if explicity set, true otherwise
|
||||
*/
|
||||
export function falsy(value) {
|
||||
return value !== false && value !== 'false';
|
||||
}
|
||||
|
||||
export function stringToArray(value) {
|
||||
return value && typeof value === 'string' ? value.split(',') : [];
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue