mirror of
https://github.com/Joxit/docker-registry-ui.git
synced 2026-02-17 21:19:51 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19e96ab94c | ||
|
|
4e5b768833 | ||
|
|
c1f6c43e4a | ||
|
|
fb8185907e | ||
|
|
636cb60ca8 | ||
|
|
34fd13d6b7 | ||
|
|
57a1cf919a | ||
|
|
ad7c2698fd | ||
|
|
7032ec9f0f | ||
|
|
3b9a804289 | ||
|
|
49ec1d9938 |
@@ -36,4 +36,7 @@
|
||||
- Ben Jackson [@bjj](https://github.com/bjj)
|
||||
- 三十文 [@xfduan](https://github.com/xfduan)
|
||||
- Aram Akhavan [@kaysond](https://github.com/kaysond)
|
||||
- Jason Tackaberry [@jtackaberry](https://github.com/jtackaberry)
|
||||
- Jason Tackaberry [@jtackaberry](https://github.com/jtackaberry)
|
||||
- Maxime Loliée [@loliee](https://github.com/loliee)
|
||||
- Enrico [@Enrico204](https://github.com/Enrico204)
|
||||
- [@clyvari](https://github.com/clyvari)
|
||||
16
README.md
16
README.md
@@ -7,6 +7,7 @@ title: Docker Registry User Interface
|
||||

|
||||

|
||||
[](https://github.com/sponsors/Joxit)
|
||||
[](https://artifacthub.io/packages/search?repo=joxit)
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -16,7 +17,7 @@ You may need the [migration guide from 1.x to 2.x](https://github.com/Joxit/dock
|
||||
|
||||
This web user interface uses [Riot](https://github.com/Riot/riot) the react-like user interface micro-library and [riot-mui](https://github.com/kysonic/riot-mui) components.
|
||||
|
||||
## [Project Page](https://joxit.dev/docker-registry-ui), [Live Demo](https://joxit.dev/docker-registry-ui/demo/), [Examples](https://github.com/Joxit/docker-registry-ui/tree/main/examples)
|
||||
## [Project Page](https://joxit.dev/docker-registry-ui), [Live Demo](https://joxit.dev/docker-registry-ui/demo/), [Examples](https://github.com/Joxit/docker-registry-ui/tree/main/examples), [Helm Chart](https://helm.joxit.dev/)
|
||||
|
||||

|
||||
|
||||
@@ -54,6 +55,7 @@ If you like my work and want to support it, don't hesitate to [sponsor me](https
|
||||
- Run the container with user nginx instead of root via `--user nginx` and listend on custom port via `NGINX_LISTEN_PORT` (see [#224](https://github.com/Joxit/docker-registry-ui/issues/224)).
|
||||
- Show number of tags per images on catalog page. This will produce + nb images requests, not recommended on large registries via `SHOW_CATALOG_NB_TAGS` (default: `false`) (see [#161](https://github.com/Joxit/docker-registry-ui/issues/161) and [#239](https://github.com/Joxit/docker-registry-ui/pull/239)).
|
||||
- Expose custom labels in history page, custom labels will be processed like maintainer label via `HISTORY_CUSTOM_LABELS` (see [#160](https://github.com/Joxit/docker-registry-ui/issues/160) and [#240](https://github.com/Joxit/docker-registry-ui/pull/240)).
|
||||
- Access to the official Helm Chart: https://helm.joxit.dev/
|
||||
|
||||
## FAQ
|
||||
|
||||
@@ -73,8 +75,8 @@ If you like my work and want to support it, don't hesitate to [sponsor me](https
|
||||
- This means you are using a UI with HTTPS and your registry is using HTTP (unsecured). When you are on a HTTPS site, you can't get HTTP content. Upgrade you registry with a HTTPS connection.
|
||||
- Why the default nginx `Host` is set to `$http_host` ?
|
||||
- This fixes the issue [#88](https://github.com/Joxit/docker-registry-ui/issues/88). More about this in [#113](https://github.com/Joxit/docker-registry-ui/issues/113).
|
||||
- Why DELETE fails with 401 status code (using Basic Auth) ?
|
||||
- This is caused by a bug in docker registry, I suggest to have your UI on the same domain than your registry and use `NGINX_PROXY_PASS_URL` e.g. registry.example.com/ui/. (see [#104](https://github.com/Joxit/docker-registry-ui/issues/104), [#204](https://github.com/Joxit/docker-registry-ui/issues/204), [#207](https://github.com/Joxit/docker-registry-ui/issues/207), [#214](https://github.com/Joxit/docker-registry-ui/issues/214)).
|
||||
- Why OPTIONS (aka preflight requests) and DELETE fails with 401 status code (using Basic Auth) ?
|
||||
- This is caused by a bug in docker registry, it returns 401 status requests on preflight requests, this breaks [W3C preflight-request specification](https://www.w3.org/TR/cors/#preflight-request). I suggest to have your UI on the same domain than your registry e.g. registry.example.com/ui/ **or** use `NGINX_PROXY_PASS_URL` **or** configure a nginx/apache/haproxy in front of your registry that returns 200 on each OPTIONS requests. (see [#104](https://github.com/Joxit/docker-registry-ui/issues/104), [#204](https://github.com/Joxit/docker-registry-ui/issues/204), [#207](https://github.com/Joxit/docker-registry-ui/issues/207), [#214](https://github.com/Joxit/docker-registry-ui/issues/214), [#266](https://github.com/Joxit/docker-registry-ui/issues/266)).
|
||||
- Can I use the docker registry ui as a standalone application (with Electron) ?
|
||||
- Yes, check out the example [here](https://github.com/Joxit/docker-registry-ui/tree/main/examples/electron). (see [#129](https://github.com/Joxit/docker-registry-ui/pull/129))
|
||||
- I deleted images through the UI, but they are still present on the server. How can I delete them?
|
||||
@@ -102,12 +104,13 @@ Some env options are available for use this interface for **only one server**.
|
||||
- `SINGLE_REGISTRY`: Remove the menu that show the dialogs to add, remove and change the endpoint of your docker registry. (default: `false`).
|
||||
- `NGINX_PROXY_PASS_URL`: Update the default Nginx configuration and set the **proxy_pass** to your backend docker registry (this avoid CORS configuration). This is usually the name of your registry container in the form `http://registry:5000`.
|
||||
- `NGINX_PROXY_HEADER_*`: Update the default Nginx configuration and **set custom headers** for your backend docker registry. Only when `NGINX_PROXY_PASS_URL` is used.
|
||||
- `NGINX_PROXY_HEADER_*`: Update the default Nginx configuration and **forward custom headers** to your backend docker registry. Only when `NGINX_PROXY_PASS_URL` is used.
|
||||
- `NGINX_PROXY_PASS_HEADER_*`: Update the default Nginx configuration and **forward custom headers** to your backend docker registry. Only when `NGINX_PROXY_PASS_URL` is used.
|
||||
- `NGINX_LISTEN_PORT`: Listen on a port other than 80. (default: `80` when the user is root, `8080` otherwise).
|
||||
- `DEFAULT_REGISTRIES`: List of comma separated registry URLs (e.g `http://registry.example.com,http://registry:5000`), available only when `SINGLE_REGISTRY=false`. (default: ` `).
|
||||
- `READ_ONLY_REGISTRIES`: Desactivate dialog for remove and add new registries, available only when `SINGLE_REGISTRY=false`. (default: `false`).
|
||||
- `SHOW_CATALOG_NB_TAGS`: Show number of tags per images on catalog page. This will produce + nb images requests, not recommended on large registries. (default: `false`).
|
||||
- `HISTORY_CUSTOM_LABELS`: Expose custom labels in history page, custom labels will be processed like maintainer label.
|
||||
- `USE_CONTROL_CACHE_HEADER`: Use `Control-Cache` header and set to `no-store, no-cache`. This will avoid some issues on multi-arch images (see [#260](https://github.com/Joxit/docker-registry-ui/issues/260)). This option requires registry configuration: `Access-Control-Allow-Headers` with `Cache-Control`. (default: `false`).
|
||||
|
||||
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/).
|
||||
|
||||
@@ -126,7 +129,7 @@ http:
|
||||
headers:
|
||||
Access-Control-Allow-Origin: ['http://registry.example.com']
|
||||
Access-Control-Allow-Credentials: [true]
|
||||
Access-Control-Allow-Headers: ['Authorization', 'Accept']
|
||||
Access-Control-Allow-Headers: ['Authorization', 'Accept', 'Cache-Control']
|
||||
Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS'] # Optional
|
||||
```
|
||||
|
||||
@@ -148,6 +151,7 @@ And you need to add these HEADERS:
|
||||
http:
|
||||
headers:
|
||||
Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE']
|
||||
Access-Control-Allow-Headers: ['Authorization', 'Accept', 'Cache-Control']
|
||||
Access-Control-Expose-Headers: ['Docker-Content-Digest']
|
||||
```
|
||||
|
||||
@@ -175,7 +179,7 @@ http:
|
||||
X-Content-Type-Options: [nosniff]
|
||||
Access-Control-Allow-Origin: ['http://127.0.0.1:8000']
|
||||
Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE']
|
||||
Access-Control-Allow-Headers: ['Authorization', 'Accept']
|
||||
Access-Control-Allow-Headers: ['Authorization', 'Accept', 'Cache-Control']
|
||||
Access-Control-Max-Age: [1728000]
|
||||
Access-Control-Allow-Credentials: [true]
|
||||
Access-Control-Expose-Headers: ['Docker-Content-Digest']
|
||||
|
||||
@@ -10,6 +10,7 @@ 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
|
||||
sed -i "s~\${HISTORY_CUSTOM_LABELS}~${HISTORY_CUSTOM_LABELS}~" index.html
|
||||
sed -i "s~\${USE_CONTROL_CACHE_HEADER}~${USE_CONTROL_CACHE_HEADER}~" index.html
|
||||
|
||||
if [ -z "${DELETE_IMAGES}" ] || [ "${DELETE_IMAGES}" = false ] ; then
|
||||
sed -i "s/\${DELETE_IMAGES}/false/" index.html
|
||||
|
||||
4
dist/docker-registry-ui.js
vendored
4
dist/docker-registry-ui.js
vendored
File diff suppressed because one or more lines are too long
1
dist/index.html
vendored
1
dist/index.html
vendored
@@ -25,4 +25,5 @@
|
||||
read-only-registries="${READ_ONLY_REGISTRIES}"
|
||||
show-catalog-nb-tags="${SHOW_CATALOG_NB_TAGS}"
|
||||
history-custom-labels="${HISTORY_CUSTOM_LABELS}"
|
||||
use-control-cache-header="${USE_CONTROL_CACHE_HEADER}"
|
||||
></docker-registry-ui><script src="docker-registry-ui.js"></script></body></html>
|
||||
@@ -1,22 +0,0 @@
|
||||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
||||
.vscode/
|
||||
@@ -1,11 +0,0 @@
|
||||
apiVersion: v1
|
||||
appVersion: "1.2.1"
|
||||
description: The simplest and most complete UI for your private registry
|
||||
name: docker-registry-ui
|
||||
home: https://github.com/Joxit/docker-registry-ui
|
||||
keywords:
|
||||
- docker
|
||||
- registry
|
||||
sources:
|
||||
- https://github.com/Joxit/docker-registry-ui
|
||||
version: 0.1.0
|
||||
@@ -1,97 +1,23 @@
|
||||
# docker-registry-ui
|
||||
|
||||
[docker-registry-ui](https://joxit.dev/docker-registry-ui/) is the simplest and most complete UI for your private registry!
|
||||
:warning: The official helm chart is now located at https://helm.joxit.dev and on GitHub [github.com/Joxit/helm-charts](https://github.com/Joxit/helm-charts).
|
||||
|
||||
## Usage
|
||||
|
||||
## TL;DR;
|
||||
1. Add my Helm repository (named `joxit`)
|
||||
|
||||
```bash
|
||||
$ helm install .
|
||||
```
|
||||
helm repo add joxit https://helm.joxit.dev
|
||||
```
|
||||
|
||||
## Introduction
|
||||
2. Ensure you have access to the Helm chart and you see the latest chart version listed. If you have previously added the Helm repository, run `helm repo update`.
|
||||
|
||||
This chart bootstraps a [docker-registry-ui](https://joxit.dev/docker-registry-ui/) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager.
|
||||
|
||||
It also may deploy the [docker registry](https://docs.docker.com/registry/) if you havent have one already.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Kubernetes 1.9+ with Beta APIs enabled
|
||||
- PV provisioner support in the underlying infrastructure
|
||||
|
||||
## Installing the Chart
|
||||
|
||||
To install the chart with the release name `my-release`:
|
||||
|
||||
```bash
|
||||
$ helm update --install my-release .
|
||||
```
|
||||
helm search repo joxit/docker-registry-ui
|
||||
```
|
||||
|
||||
The command deploys docker-registry-ui on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists the parameters that can be configured during installation.
|
||||
3. Now you're ready to install the Docker Registry UI! To install Docker Registry UI with the default configuration using Helm 3.2 run the following command below. This will deploy the Docker Registry UI on the default namespace.
|
||||
|
||||
> **Tip**: List all releases using `helm list`
|
||||
|
||||
## Uninstalling the Chart
|
||||
|
||||
To uninstall/delete the `my-release` deployment:
|
||||
|
||||
```bash
|
||||
$ helm delete my-release
|
||||
```
|
||||
|
||||
The command removes all the Kubernetes components associated with the chart and deletes the release.
|
||||
|
||||
## Configuration
|
||||
|
||||
The following table lists the configurable parameters of the Redmine chart and their default values.
|
||||
|
||||
| Parameter | Description | Default |
|
||||
| --------------------------------- | ---------------------------------------- | ------------------------------------------------------- |
|
||||
| `ui.title` | Title of the managed repository | `Docker registry UI` |
|
||||
| `ui.delete_images` | Allow to delete image from the front-end | `false` |
|
||||
| `ui.proxy` | The UI service act as a proxy of the registry | `true` |
|
||||
| `ui.replicaCount` | Number of replicas to start | `1` |
|
||||
| `ui.image.registry` | registry to pull the docker-registry-ui image from | `docker.io` |
|
||||
| `ui.image.repository` | docker-registry-ui image name | `joxit/docker-registry-ui` |
|
||||
| `ui.image.tag` | docker-registry-ui image tag (change to latest to have multi registry support) | `static` |
|
||||
| `ui.image.pullPolicy` | docker-registry-ui image pull policy | `Always` |
|
||||
| `ui.probe.liveness` | Ask kubernetes to check the service port for liveness | `true` |
|
||||
| `ui.probe.readyness ` | Ask kubernetes to check the service port for readyness | `true` |
|
||||
| `ui.service.type` | Desired service type | `ClusterIP` |
|
||||
| `ui.service.port` | Service exposed port | `80` |
|
||||
| `ui.ingress.enabled` | Create an ingress for docker-regstry-ui | `false` |
|
||||
| `registry.external` | Use an already available registry | `false` |
|
||||
| `registry.url` | URL of the existing registry | `http://localhost:5000` |
|
||||
| `registry.replicaCount` | Number of replicas to start | `1` |
|
||||
| `registry.image.registry` | registry to pull the docker-registry image from | `docker.io` |
|
||||
| `registry.image.repository` | docker-registry-ui image name | `registry` |
|
||||
| `registry.image.tag` | docker-registry-ui image tag | `2.6.2` |
|
||||
| `registry.image.pullPolicy` | docker-registry-ui image pull policy | `Always` |
|
||||
| `registry.probe.liveness` | Ask kubernetes to check the service port for liveness | `true` |
|
||||
| `registry.probe.readyness ` | Ask kubernetes to check the service port for readyness | `true` |
|
||||
| `registry.persistence.enabled` | Enable persistence using PVC for the registry | `false` |
|
||||
| `registry.persistence.storageClass` | PVC Storage Class | `-` |
|
||||
| `registry.persistence.size` | PVC Storage Request size | `1Gi` |
|
||||
| `registry.service.type` | Desired service type | `ClusterIP` |
|
||||
| `registry.service.port` | Service exposed port | `5000` |
|
||||
| `registry.ingress.enabled` | Create an ingress for the regstry | `false` |
|
||||
|
||||
|
||||
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example,
|
||||
|
||||
```bash
|
||||
$ helm upgrade --install my-release \
|
||||
--set registry.external=true \
|
||||
--set registry.url=http://registry.example.com:5000 \
|
||||
.
|
||||
helm upgrade --install docker-registry-ui joxit/docker-registry-ui
|
||||
```
|
||||
|
||||
Alternatively, a YAML file that specifies the values for the above parameters can be provided while installing the chart. For example,
|
||||
|
||||
```bash
|
||||
$ helm upgrade --install my-release -f values.yaml .
|
||||
```
|
||||
|
||||
> **Tip**: You can use the default [values.yaml](values.yaml)
|
||||
|
||||
|
||||
@@ -1,147 +0,0 @@
|
||||
{{/* vim: set filetype=mustache: */}}
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "docker-registry-ui.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "docker-registry-ui.fullname" -}}
|
||||
{{- if .Values.ui.fullnameOverride -}}
|
||||
{{- .Values.ui.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
||||
{{- if contains $name .Release.Name -}}
|
||||
{{- printf "%s-ui" .Release.Name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-ui-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "docker-registry.fullname" -}}
|
||||
{{- if .Values.registry.fullnameOverride -}}
|
||||
{{- .Values.registry.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
||||
{{- if contains $name .Release.Name -}}
|
||||
{{- printf "%s-registry" .Release.Name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-registry-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "docker-registry-ui.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "docker-registry-ui.labels" -}}
|
||||
app: registry-ui
|
||||
chart: {{ include "docker-registry-ui.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "docker-registry-ui.matchLabels" -}}
|
||||
app: registry-ui
|
||||
release: {{ .Release.Name }}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "docker-registry.labels" -}}
|
||||
app: registry
|
||||
chart: {{ include "docker-registry-ui.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "docker-registry.matchLabels" -}}
|
||||
app: registry
|
||||
release: {{ .Release.Name }}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "docker-registry-ui.probes" -}}
|
||||
{{- if and .Values.ui.probe.liveness (eq .Values.ui.probe.liveness true) -}}
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
{{- end -}}
|
||||
{{- if and .Values.ui.probe.readiness (eq .Values.ui.probe.readiness true) }}
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "docker-registry.probes" -}}
|
||||
{{- if and .Values.registry.probe.liveness (eq .Values.registry.probe.liveness true) -}}
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /v2/
|
||||
port: registry
|
||||
{{- end -}}
|
||||
{{- if and .Values.registry.probe.readiness (eq .Values.registry.probe.readiness true) }}
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /v2/
|
||||
port: registry
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "docker-registry-ui.url-name" -}}
|
||||
{{- if eq .Values.ui.proxy true -}}
|
||||
REGISTRY_URL
|
||||
{{- else -}}
|
||||
URL
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "docker-registry-ui.url-value" -}}
|
||||
{{- if eq .Values.registry.external true -}}
|
||||
{{ .Values.registry.url }}
|
||||
{{- else -}}
|
||||
{{- $fullName := include "docker-registry.fullname" . -}}
|
||||
{{ printf "http://%s.%s:%.0f" $fullName .Release.Namespace .Values.registry.service.port }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "docker-registry-ui.pull" -}}
|
||||
{{- if eq .Values.registry.external true -}}
|
||||
{{ .Values.registry.url }}
|
||||
{{- else -}}
|
||||
{{- if eq .Values.ui.proxy true -}}
|
||||
{{- if eq .Values.ui.ingress.enabled true -}}
|
||||
{{- $host := index .Values.ui.ingress.hosts 0 -}}
|
||||
{{ $host.host }}
|
||||
{{- else -}}
|
||||
{{- $fullName := include "docker-registry-ui.fullname" . -}}
|
||||
{{ printf "%s.%s:%.0f" $fullName .Release.Namespace .Values.ui.service.port }}
|
||||
{{- end -}}
|
||||
{{- else -}}
|
||||
{{- if eq .Values.registry.ingress.enabled true -}}
|
||||
{{- $host := index .Values.registry.ingress.hosts 0 -}}
|
||||
{{ $host.host }}
|
||||
{{- else -}}
|
||||
{{- $fullName := include "docker-registry.fullname" . -}}
|
||||
{{ printf "%s.%s:%.0f" $fullName .Release.Namespace .Values.registry.service.port }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
@@ -1,31 +0,0 @@
|
||||
{{- if eq .Values.registry.external false -}}
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ include "docker-registry.fullname" . }}
|
||||
labels:
|
||||
{{ include "docker-registry.labels" . | indent 4 }}
|
||||
data:
|
||||
config.yml: |-
|
||||
version: 0.1
|
||||
log:
|
||||
fields:
|
||||
service: registry
|
||||
storage:
|
||||
delete:
|
||||
enabled: true
|
||||
cache:
|
||||
blobdescriptor: inmemory
|
||||
filesystem:
|
||||
rootdirectory: /var/lib/registry
|
||||
http:
|
||||
addr: :5000
|
||||
headers:
|
||||
X-Content-Type-Options: [nosniff]
|
||||
Access-Control-Allow-Origin: ['*']
|
||||
Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE']
|
||||
Access-Control-Allow-Headers: ['Authorization']
|
||||
Access-Control-Max-Age: [1728000]
|
||||
Access-Control-Allow-Credentials: [true]
|
||||
Access-Control-Expose-Headers: ['Docker-Content-Digest']
|
||||
{{- end -}}
|
||||
@@ -1,62 +0,0 @@
|
||||
{{- if eq .Values.registry.external false -}}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "docker-registry.fullname" . }}
|
||||
labels:
|
||||
{{ include "docker-registry.labels" . | indent 4 }}
|
||||
spec:
|
||||
replicas: {{ .Values.registry.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{ include "docker-registry.matchLabels" . | indent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{ include "docker-registry.matchLabels" . | indent 8 }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
defaultMode: 420
|
||||
name: {{ include "docker-registry.fullname" . }}
|
||||
- name: data
|
||||
{{- if .Values.registry.persistence.enabled }}
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ include "docker-registry.fullname" . }}
|
||||
{{- else }}
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: registry
|
||||
image: "{{ .Values.registry.image.registry }}/{{ .Values.registry.image.repository }}:{{ .Values.registry.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.registry.image.pullPolicy }}
|
||||
ports:
|
||||
- name: registry
|
||||
containerPort: 5000
|
||||
protocol: TCP
|
||||
volumeMounts:
|
||||
- mountPath: "/var/lib/registry"
|
||||
name: "data"
|
||||
- mountPath: "/etc/docker/registry"
|
||||
name: "config"
|
||||
{{ include "docker-registry.probes" . | indent 10 }}
|
||||
resources:
|
||||
{{- toYaml .Values.registry.resources | nindent 12 }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
@@ -1,34 +0,0 @@
|
||||
{{- if and (eq .Values.registry.external false) (and (eq .Values.ui.proxy false) .Values.registry.ingress.enabled) -}}
|
||||
{{- $fullName := include "docker-registry.fullname" . -}}
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
labels:
|
||||
{{ include "docker-registry.labels" . | indent 4 }}
|
||||
{{- with .Values.registry.ingress.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.registry.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.registry.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.registry.ingress.hosts }}
|
||||
- host: {{ .host | quote }}
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
backend:
|
||||
serviceName: {{ $fullName }}
|
||||
servicePort: registry
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
@@ -1,23 +0,0 @@
|
||||
{{- if and (eq .Values.registry.external false) .Values.registry.persistence.enabled -}}
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
labels:
|
||||
{{ include "docker-registry.labels" . | indent 4 }}
|
||||
name: {{ include "docker-registry.fullname" . }}
|
||||
spec:
|
||||
accessModes:
|
||||
{{- range .Values.registry.persistence.accessModes }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.registry.persistence.size }}
|
||||
{{- if .Values.registry.persistence.storageClass }}
|
||||
{{- if (eq "-" .Values.registry.persistence.storageClass) }}
|
||||
storageClassName: ""
|
||||
{{- else }}
|
||||
storageClassName: {{ .Values.registry.persistence.storageClass | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
@@ -1,17 +0,0 @@
|
||||
{{- if eq .Values.registry.external false -}}
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "docker-registry.fullname" . }}
|
||||
labels:
|
||||
{{ include "docker-registry.labels" . | indent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.registry.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.registry.service.port }}
|
||||
targetPort: registry
|
||||
protocol: TCP
|
||||
name: registry
|
||||
selector:
|
||||
{{ include "docker-registry.matchLabels" . | indent 6 }}
|
||||
{{- end -}}
|
||||
@@ -1,52 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "docker-registry-ui.fullname" . }}
|
||||
labels:
|
||||
{{ include "docker-registry-ui.labels" . | indent 4 }}
|
||||
spec:
|
||||
replicas: {{ .Values.ui.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{ include "docker-registry-ui.matchLabels" . | indent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{ include "docker-registry-ui.matchLabels" . | indent 8 }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: registry-ui
|
||||
image: "{{ .Values.ui.image.registry }}/{{ .Values.ui.image.repository }}:{{ .Values.ui.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.ui.image.pullPolicy }}
|
||||
env:
|
||||
- name: REGISTRY_TITLE
|
||||
value: {{ .Values.ui.title| quote }}
|
||||
- name: DELETE_IMAGES
|
||||
value: {{ .Values.ui.delete_images| quote }}
|
||||
- name: {{ include "docker-registry-ui.url-name" . }}
|
||||
value: {{ include "docker-registry-ui.url-value" . | quote }}
|
||||
- name: PULL_URL
|
||||
value: {{ include "docker-registry-ui.pull" . | quote }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 80
|
||||
protocol: TCP
|
||||
{{ include "docker-registry-ui.probes" . | indent 10 }}
|
||||
resources:
|
||||
{{- toYaml .Values.ui.resources | nindent 12 }}
|
||||
{{- with .Values.ui.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.ui.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.ui.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
@@ -1,61 +0,0 @@
|
||||
{{- if .Values.ui.ingress.enabled -}}
|
||||
{{- $fullName := include "docker-registry-ui.fullname" . -}}
|
||||
{{- $svcPort := .Values.ui.service.port -}}
|
||||
{{- if and .Values.ui.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
|
||||
{{- if not (hasKey .Values.ui.ingress.annotations "kubernetes.io/ingress.class") }}
|
||||
{{- $_ := set .Values.ui.ingress.annotations "kubernetes.io/ingress.class" .Values.ui.ingress.className}}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
|
||||
apiVersion: networking.k8s.io/v1beta1
|
||||
{{- else -}}
|
||||
apiVersion: extensions/v1beta1
|
||||
{{- end }}
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
labels:
|
||||
{{ include "docker-registry-ui.labels" . | indent 4 }}
|
||||
{{- with .Values.ui.ingress.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if and .Values.ui.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
|
||||
ingressClassName: {{ .Values.ui.ingress.className }}
|
||||
{{- end }}
|
||||
{{- if .Values.ui.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ui.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.ui.ingress.hosts }}
|
||||
- host: {{ .host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .paths }}
|
||||
- path: {{ .path }}
|
||||
{{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }}
|
||||
pathType: {{ .pathType }}
|
||||
{{- end }}
|
||||
backend:
|
||||
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
|
||||
service:
|
||||
name: {{ $fullName }}
|
||||
port:
|
||||
number: {{ $svcPort }}
|
||||
{{- else }}
|
||||
serviceName: {{ $fullName }}
|
||||
servicePort: {{ $svcPort }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -1,15 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "docker-registry-ui.fullname" . }}
|
||||
labels:
|
||||
{{ include "docker-registry-ui.labels" . | indent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.ui.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.ui.service.port }}
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
{{ include "docker-registry-ui.matchLabels" . | indent 6 }}
|
||||
@@ -1,133 +0,0 @@
|
||||
# Default values for docker-registry-ui.
|
||||
# This is a YAML-formatted file.
|
||||
# Declare variables to be passed into your templates.
|
||||
|
||||
|
||||
ui:
|
||||
# title of the registry
|
||||
title: "Docker registry UI"
|
||||
# allow delete of images
|
||||
delete_images: false
|
||||
# UI behave as a proxy of the registry
|
||||
proxy: true
|
||||
|
||||
replicaCount: 1
|
||||
image:
|
||||
registry: docker.io
|
||||
repository: joxit/docker-registry-ui
|
||||
tag: static
|
||||
pullPolicy: Always
|
||||
probe:
|
||||
liveness: true
|
||||
readiness: true
|
||||
|
||||
resources: {}
|
||||
# If you do want to specify resources, uncomment the following
|
||||
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||
# limits:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
nodeSelector: {}
|
||||
tolerations: []
|
||||
affinity: {}
|
||||
fullnameOverride: ""
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 80
|
||||
|
||||
ingress:
|
||||
enabled: false
|
||||
className: "nginx"
|
||||
annotations: {}
|
||||
# kubernetes.io/ingress.class: nginx
|
||||
# kubernetes.io/tls-acme: "true"
|
||||
hosts:
|
||||
- host: docker-registry-ui.local
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
|
||||
tls: []
|
||||
# - secretName: chart-example-tls
|
||||
# hosts:
|
||||
# - chart-example.local
|
||||
|
||||
|
||||
registry:
|
||||
external: false
|
||||
# URL of the registry (requiered. Note: this wont work as localhost is inside the container. Only used if the registry is external)
|
||||
url: http://localhost:5000
|
||||
|
||||
replicaCount: 1
|
||||
# Image definition for the registry (Only used if the registry is not external)
|
||||
image:
|
||||
registry: docker.io
|
||||
repository: registry
|
||||
tag: 2.7.1
|
||||
pullPolicy: Always
|
||||
probe:
|
||||
liveness: true
|
||||
readiness: true
|
||||
resources: {}
|
||||
# If you do want to specify resources, uncomment the following
|
||||
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||
# limits:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
nodeSelector: {}
|
||||
tolerations: []
|
||||
affinity: {}
|
||||
fullnameOverride: ""
|
||||
|
||||
|
||||
persistence:
|
||||
## If true, use a Persistent Volume Claim, If false, use emptyDir
|
||||
##
|
||||
enabled: false
|
||||
## Persistent Volume Storage Class
|
||||
## If defined, storageClassName: <storageClass>
|
||||
## If set to "-", storageClassName: "", which disables dynamic provisioning
|
||||
## If undefined (the default) or set to null, no storageClassName spec is
|
||||
## set, choosing the default provisioner. (gp2 on AWS, standard on
|
||||
## GKE, AWS & OpenStack)
|
||||
##
|
||||
# storageClass: "-"
|
||||
## Persistent Volume Claim annotations
|
||||
##
|
||||
annotations:
|
||||
## Persistent Volume Access Mode
|
||||
##
|
||||
accessModes:
|
||||
# This have to be ReadWriteMany if replicaCount>1
|
||||
- ReadWriteOnce
|
||||
## Persistent Volume size
|
||||
##
|
||||
size: 1Gi
|
||||
##
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 5000
|
||||
|
||||
ingress:
|
||||
enabled: false
|
||||
annotations: {}
|
||||
# kubernetes.io/ingress.class: nginx
|
||||
# kubernetes.io/tls-acme: "true"
|
||||
hosts:
|
||||
- host: docker-registry.local
|
||||
|
||||
tls: []
|
||||
# - secretName: chart-example-tls
|
||||
# hosts:
|
||||
# - chart-example.local
|
||||
|
||||
imagePullSecrets: []
|
||||
nameOverride: ""
|
||||
@@ -26,6 +26,7 @@ server {
|
||||
#! if ($http_user_agent ~ "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*$" ) {
|
||||
#! return 404;
|
||||
#! }
|
||||
#! proxy_http_version 1.1;
|
||||
#! ${NGINX_PROXY_HEADERS}
|
||||
#! ${NGINX_PROXY_PASS_HEADERS}
|
||||
#! proxy_pass ${NGINX_PROXY_PASS_URL};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "docker-registry-ui",
|
||||
"version": "2.2.1",
|
||||
"version": "2.3.2",
|
||||
"scripts": {
|
||||
"format": "npm run format-html && npm run format-js && npm run format-riot",
|
||||
"format-html": "find src rollup rollup.config.js -name '*.html' -exec prettier --config .prettierrc -w --parser html {} \\;",
|
||||
|
||||
@@ -36,13 +36,13 @@
|
||||
import router from '../../scripts/router';
|
||||
export default {
|
||||
displayImagesToDelete(toDelete, tags) {
|
||||
const digests = new Set();
|
||||
const contentDigests = new Set();
|
||||
toDelete.forEach((image) => {
|
||||
if (image.digest) {
|
||||
digests.add(image.digest);
|
||||
if (image.contentDigest) {
|
||||
contentDigests.add(image.contentDigest);
|
||||
}
|
||||
});
|
||||
return tags.filter((image) => digests.has(image.digest));
|
||||
return tags.filter((image) => contentDigests.has(image.contentDigest));
|
||||
},
|
||||
deleteImages() {
|
||||
this.props.toDelete.forEach((image) => this.getContentDigestThenDelete(image, this.props));
|
||||
@@ -53,11 +53,11 @@
|
||||
const self = this;
|
||||
oReq.addEventListener('loadend', function () {
|
||||
if (this.status === 200 || this.status === 202) {
|
||||
oReq.getContentDigest(function (digest) {
|
||||
if (!digest) {
|
||||
oReq.getContentDigest(function (contentDigest) {
|
||||
if (!contentDigest) {
|
||||
onNotify(ERROR_CAN_NOT_READ_CONTENT_DIGEST);
|
||||
} else {
|
||||
self.deleteImage({ name, tag, digest }, opts);
|
||||
self.deleteImage({ name, tag, contentDigest }, opts);
|
||||
}
|
||||
});
|
||||
} else if (this.status === 404) {
|
||||
@@ -73,7 +73,7 @@
|
||||
);
|
||||
oReq.send();
|
||||
},
|
||||
deleteImage({ name, tag, digest }, opts) {
|
||||
deleteImage({ name, tag, contentDigest }, opts) {
|
||||
const { registryUrl, ignoreError, onNotify, onAuthentication, onClick } = opts;
|
||||
const oReq = new Http({ onAuthentication });
|
||||
oReq.addEventListener('loadend', function () {
|
||||
@@ -91,7 +91,7 @@
|
||||
}
|
||||
onClick();
|
||||
});
|
||||
oReq.open('DELETE', `${registryUrl}/v2/${name}/manifests/${digest}`);
|
||||
oReq.open('DELETE', `${registryUrl}/v2/${name}/manifests/${contentDigest}`);
|
||||
oReq.setRequestHeader(
|
||||
'Accept',
|
||||
'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json'
|
||||
|
||||
@@ -52,6 +52,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
on-notify="{ notifySnackbar }"
|
||||
filter-results="{ state.filter }"
|
||||
on-authentication="{ onAuthentication }"
|
||||
use-control-cache-header="{ truthy(props.useControlCacheHeader) }"
|
||||
></tag-list>
|
||||
</route>
|
||||
<route path="{baseRoute}taghistory/(.*)">
|
||||
@@ -65,6 +66,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
on-notify="{ notifySnackbar }"
|
||||
on-authentication="{ onAuthentication }"
|
||||
history-custom-labels="{ stringToArray(props.historyCustomLabels) }"
|
||||
use-control-cache-header="{ truthy(props.useControlCacheHeader) }"
|
||||
></tag-history>
|
||||
</route>
|
||||
</router>
|
||||
@@ -86,7 +88,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
<a href="https://github.com/Joxit/docker-registry-ui">Contribute on GitHub</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/Joxit/docker-registry-ui/blob/main/LICENSE">Privacy & Terms</a>
|
||||
<a href="https://github.com/Joxit/docker-registry-ui/blob/main/LICENSE">License AGPL-3.0</a>
|
||||
</li>
|
||||
</ul>
|
||||
</material-footer>
|
||||
@@ -133,6 +135,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
this.state.name = props.name || stripHttps(props.registryUrl);
|
||||
this.state.catalogElementsLimit = props.catalogElementsLimit || 100000;
|
||||
this.state.pullUrl = this.pullUrl(this.state.registryUrl, props.pullUrl);
|
||||
this.state.useControlCacheHeader = props.useControlCacheHeader;
|
||||
},
|
||||
onServerChange(registryUrl) {
|
||||
this.update({
|
||||
|
||||
@@ -57,6 +57,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
registryUrl: props.registryUrl,
|
||||
onNotify: props.onNotify,
|
||||
onAuthentication: props.onAuthentication,
|
||||
useControlCacheHeader: props.useControlCacheHeader,
|
||||
});
|
||||
state.image.fillInfo();
|
||||
},
|
||||
@@ -66,7 +67,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
},
|
||||
onTabChanged(arch, idx) {
|
||||
const state = this.state;
|
||||
const { registryUrl, onNotify } = this.props;
|
||||
const { registryUrl, onNotify, useControlCacheHeader } = this.props;
|
||||
state.elements = [];
|
||||
state.image.variants[idx] =
|
||||
state.image.variants[idx] ||
|
||||
@@ -74,6 +75,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
list: false,
|
||||
registryUrl,
|
||||
onNotify,
|
||||
useControlCacheHeader,
|
||||
});
|
||||
if (state.image.variants[idx].blobs) {
|
||||
return this.processBlobs(state.image.variants[idx].blobs);
|
||||
|
||||
@@ -40,12 +40,12 @@
|
||||
if (props.target === 'tag') {
|
||||
return `docker pull ${props.pullUrl}/${props.image.name}:${props.image.tag}`;
|
||||
} else {
|
||||
return `docker pull ${props.pullUrl}/${props.image.name}@${props.image.digest}`;
|
||||
return `docker pull ${props.pullUrl}/${props.image.name}@${props.image.contentDigest}`;
|
||||
}
|
||||
},
|
||||
load(props, state) {
|
||||
if (props.target !== 'tag' && !props.image.digest) {
|
||||
props.image.one('content-digest', (digest) => {
|
||||
if (props.target !== 'tag' && !props.image.contentDigest) {
|
||||
props.image.one('content-digest', (contentDigest) => {
|
||||
this.update();
|
||||
});
|
||||
props.image.trigger('get-content-digest');
|
||||
|
||||
@@ -15,7 +15,7 @@ Copyright (C) 2016-2021 Jones Magloire @Joxit
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<image-content-digest>
|
||||
<div title="{ getTitle(props.image, state.chars) }">{ getDigest(props.image, state.chars) }</div>
|
||||
<div title="{ getTitle(props.image, state.chars) }">{ getContentDigest(props.image, state.chars) }</div>
|
||||
<script>
|
||||
export default {
|
||||
onMounted(props, state) {
|
||||
@@ -25,12 +25,12 @@ Copyright (C) 2016-2021 Jones Magloire @Joxit
|
||||
this.load(props, state);
|
||||
},
|
||||
load(props, state) {
|
||||
if (props.image.digest) {
|
||||
if (props.image.contentDigest) {
|
||||
return;
|
||||
}
|
||||
state.chars = -1;
|
||||
props.image.one('content-digest', (digest) => {
|
||||
this.digest = digest;
|
||||
props.image.one('content-digest', (contentDigest) => {
|
||||
this.contentDigest = contentDigest;
|
||||
props.image.on('content-digest-chars', this.onResize);
|
||||
props.image.trigger('get-content-digest-chars');
|
||||
});
|
||||
@@ -44,15 +44,15 @@ Copyright (C) 2016-2021 Jones Magloire @Joxit
|
||||
}
|
||||
},
|
||||
getTitle(image, chars) {
|
||||
return chars >= 70 ? '' : image.digest || '';
|
||||
return chars >= 70 ? '' : image.contentDigest || '';
|
||||
},
|
||||
getDigest(image, chars) {
|
||||
getContentDigest(image, chars) {
|
||||
if (chars >= 70) {
|
||||
return image.digest || '';
|
||||
return image.contentDigest || '';
|
||||
} else if (chars <= 0) {
|
||||
return '';
|
||||
} else {
|
||||
return image.digest && image.digest.slice(0, chars) + '...';
|
||||
return image.contentDigest && image.contentDigest.slice(0, chars) + '...';
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -18,10 +18,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
<div class="conatianer">
|
||||
<div class="pagination-centered">
|
||||
<material-button
|
||||
aria-label="page-{ p.page }"
|
||||
waves-color="rgba(158,158,158,.4)"
|
||||
each="{p in props.pages}"
|
||||
each="{ (p, idx) in props.pages}"
|
||||
class="{ p.current ? 'current' : ''} { p['space-left'] ? 'space-left' : '' } { p['space-right'] ? 'space-right' : ''}"
|
||||
onClick="{() => props.onPageUpdate(p.page)}"
|
||||
onClick="{() => props.onPageUpdate(idx)}"
|
||||
>
|
||||
<i if="{ p.icon }" class="material-icons">{ p.icon }</i>
|
||||
<div if="{ !p.icon }">{ p.page }</div>
|
||||
|
||||
@@ -21,7 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
waves-color="#ddd"
|
||||
title="This will delete the image."
|
||||
if="{ !props.multiDelete }"
|
||||
disabled="{ !state.digest }"
|
||||
disabled="{ !state.contentDigest }"
|
||||
onClick="{ deleteImage }"
|
||||
>
|
||||
<i class="material-icons">delete</i>
|
||||
@@ -29,7 +29,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
<material-checkbox
|
||||
if="{ props.multiDelete }"
|
||||
title="Select this tag to delete it."
|
||||
disabled="{ !state.digest }"
|
||||
disabled="{ !state.contentDigest }"
|
||||
onChange="{ handleCheckboxChange }"
|
||||
checked="{ state.checked }"
|
||||
>
|
||||
@@ -41,9 +41,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
export default {
|
||||
onBeforeMount(props, state) {
|
||||
state.checked = props.checked;
|
||||
props.image.one('content-digest', (digest) => {
|
||||
props.image.one('content-digest', (contentDigest) => {
|
||||
this.update({
|
||||
digest,
|
||||
contentDigest,
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
@@ -92,9 +92,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
.map(
|
||||
(tag) =>
|
||||
new DockerImage(props.image, tag, {
|
||||
list: true,
|
||||
registryUrl: props.registryUrl,
|
||||
onNotify: props.onNotify,
|
||||
onAuthentication: props.onAuthentication,
|
||||
useControlCacheHeader: props.useControlCacheHeader,
|
||||
})
|
||||
)
|
||||
.sort(compare);
|
||||
@@ -123,7 +125,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
state.asc = true;
|
||||
},
|
||||
|
||||
onPageUpdate(page) {
|
||||
onPageUpdate(idx) {
|
||||
const labels = getPageLabels(this.state.page, getNumPages(this.state.tags));
|
||||
const page = labels[idx].page;
|
||||
this.update({
|
||||
page: page,
|
||||
});
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
read-only-registries="${READ_ONLY_REGISTRIES}"
|
||||
show-catalog-nb-tags="${SHOW_CATALOG_NB_TAGS}"
|
||||
history-custom-labels="${HISTORY_CUSTOM_LABELS}"
|
||||
use-control-cache-header="${USE_CONTROL_CACHE_HEADER}"
|
||||
>
|
||||
</docker-registry-ui>
|
||||
<!-- endbuild -->
|
||||
@@ -60,6 +61,7 @@
|
||||
single-registry="false"
|
||||
show-catalog-nb-tags="true"
|
||||
history-custom-labels="first_custom_labels,second_custom_labels"
|
||||
use-control-cache-header="false"
|
||||
>
|
||||
</docker-registry-ui>
|
||||
<!-- endbuild -->
|
||||
|
||||
@@ -46,7 +46,7 @@ export function compare(e1, e2) {
|
||||
}
|
||||
|
||||
export class DockerImage {
|
||||
constructor(name, tag, { list, registryUrl, onNotify, onAuthentication }) {
|
||||
constructor(name, tag, { list, registryUrl, onNotify, onAuthentication, useControlCacheHeader }) {
|
||||
this.name = name;
|
||||
this.tag = tag;
|
||||
this.chars = 0;
|
||||
@@ -55,6 +55,7 @@ export class DockerImage {
|
||||
registryUrl,
|
||||
onNotify,
|
||||
onAuthentication,
|
||||
useControlCacheHeader,
|
||||
};
|
||||
this.ociImage = false;
|
||||
observable(this);
|
||||
@@ -83,8 +84,8 @@ export class DockerImage {
|
||||
return this.trigger('content-digest-chars', this.chars);
|
||||
});
|
||||
this.on('get-content-digest', function () {
|
||||
if (this.digest !== undefined) {
|
||||
return this.trigger('content-digest', this.digest);
|
||||
if (this.contentDigest !== undefined) {
|
||||
return this.trigger('content-digest', this.contentDigest);
|
||||
}
|
||||
return this.fillInfo();
|
||||
});
|
||||
@@ -109,17 +110,17 @@ export class DockerImage {
|
||||
return;
|
||||
}
|
||||
self.ociImage = response.mediaType === 'application/vnd.oci.image.index.v1+json';
|
||||
self.layers = self.ociImage ? response.manifests : response.layers;
|
||||
self.layers = response.layers || response.manifests;
|
||||
self.size = self.layers.reduce(function (acc, e) {
|
||||
return acc + e.size;
|
||||
}, 0);
|
||||
self.sha256 = response.config && response.config.digest;
|
||||
self.trigger('size', self.size);
|
||||
self.trigger('sha256', self.sha256);
|
||||
oReq.getContentDigest(function (digest) {
|
||||
self.digest = digest;
|
||||
self.trigger('content-digest', digest);
|
||||
if (!digest) {
|
||||
oReq.getContentDigest(function (contentDigest) {
|
||||
self.contentDigest = contentDigest;
|
||||
self.trigger('content-digest', contentDigest);
|
||||
if (!contentDigest) {
|
||||
self.opts.onNotify(ERROR_CAN_NOT_READ_CONTENT_DIGEST);
|
||||
}
|
||||
});
|
||||
@@ -143,6 +144,9 @@ export class DockerImage {
|
||||
'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json, application/vnd.oci.image.index.v1+json' +
|
||||
(self.opts.list ? ', application/vnd.docker.distribution.manifest.list.v2+json' : '')
|
||||
);
|
||||
if (self.opts.useControlCacheHeader) {
|
||||
oReq.setRequestHeader('Cache-Control', 'no-store, no-cache');
|
||||
}
|
||||
oReq.send();
|
||||
}
|
||||
getBlobs(blob) {
|
||||
@@ -165,7 +169,12 @@ export class DockerImage {
|
||||
self.trigger('creation-date', self.creationDate);
|
||||
self.trigger('blobs', self.blobs);
|
||||
} else if (this.status === 404) {
|
||||
self.opts.onNotify(`Blobs for ${self.name}:${self.tag} not found`, true);
|
||||
self.opts.onNotify(`Blobs for ${self.name}:${self.tag} not found: blob '${self.blobs}'`, true);
|
||||
} else if (!this.responseText) {
|
||||
self.opts.onNotify(
|
||||
`Can"t get blobs for ${self.name}:${self.tag}: blob '${self.blobs}' (no message error)`,
|
||||
true
|
||||
);
|
||||
} else {
|
||||
self.opts.onNotify(this.responseText);
|
||||
}
|
||||
|
||||
@@ -136,8 +136,13 @@ export function stripHttps(url) {
|
||||
return url.replace(/^https?:\/\//, '');
|
||||
}
|
||||
|
||||
function kebabToCamelCase(s) {
|
||||
return s.replace(/-[a-z]/, (x) => x[1].toUpperCase());
|
||||
}
|
||||
|
||||
export function eventTransfer(from, to) {
|
||||
from.on('*', function (event, param) {
|
||||
to[kebabToCamelCase(event)] = param;
|
||||
to.trigger(event, param);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user