mirror of
https://github.com/Joxit/docker-registry-ui.git
synced 2025-04-30 00:49:53 +03:00
feat(riot-v5): export docker image class and utils function
This commit is contained in:
parent
ea21483346
commit
7beac85f25
4 changed files with 210 additions and 31 deletions
|
@ -17,6 +17,7 @@
|
||||||
"@babel/core": "^7.12.9",
|
"@babel/core": "^7.12.9",
|
||||||
"@babel/preset-env": "^7.12.7",
|
"@babel/preset-env": "^7.12.7",
|
||||||
"@riotjs/compiler": "^5.3.1",
|
"@riotjs/compiler": "^5.3.1",
|
||||||
|
"@riotjs/observable": "^4.0.4",
|
||||||
"@riotjs/route": "^7.0.0",
|
"@riotjs/route": "^7.0.0",
|
||||||
"@rollup/plugin-babel": "^5.2.2",
|
"@rollup/plugin-babel": "^5.2.2",
|
||||||
"@rollup/plugin-commonjs": "^17.0.0",
|
"@rollup/plugin-commonjs": "^17.0.0",
|
||||||
|
|
150
src/scripts/docker-image.js
Normal file
150
src/scripts/docker-image.js
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
import { Http } from './http';
|
||||||
|
import { isDigit, eventTransfer } from './utils';
|
||||||
|
import observable from '@riotjs/observable';
|
||||||
|
|
||||||
|
const tagReduce = (acc, e) => {
|
||||||
|
if (acc.length > 0 && isDigit(acc[acc.length - 1].charAt(0)) == isDigit(e)) {
|
||||||
|
acc[acc.length - 1] += e;
|
||||||
|
} else {
|
||||||
|
acc.push(e);
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function compare(e1, e2) {
|
||||||
|
const tag1 = e1.tag.match(/./g).reduce(tagReduce, []);
|
||||||
|
const tag2 = e2.tag.match(/./g).reduce(tagReduce, []);
|
||||||
|
|
||||||
|
for (var i = 0; i < tag1.length && i < tag2.length; i++) {
|
||||||
|
const compare = tag1[i].localeCompare(tag2[i]);
|
||||||
|
if (isDigit(tag1[i].charAt(0)) && isDigit(tag2[i].charAt(0))) {
|
||||||
|
const diff = tag1[i] - tag2[i];
|
||||||
|
if (diff != 0) {
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
} else if (compare != 0) {
|
||||||
|
return compare;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return e1.tag.length - e2.tag.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DockerImage {
|
||||||
|
constructor(name, tag, list) {
|
||||||
|
this.name = name;
|
||||||
|
this.tag = tag;
|
||||||
|
this.list = list;
|
||||||
|
this.chars = 0;
|
||||||
|
observable(this);
|
||||||
|
this.on('get-size', function () {
|
||||||
|
if (this.size !== undefined) {
|
||||||
|
return this.trigger('size', this.size);
|
||||||
|
}
|
||||||
|
return this.fillInfo();
|
||||||
|
});
|
||||||
|
this.on('get-sha256', function () {
|
||||||
|
if (this.size !== undefined) {
|
||||||
|
return this.trigger('sha256', this.sha256);
|
||||||
|
}
|
||||||
|
return this.fillInfo();
|
||||||
|
});
|
||||||
|
this.on('get-date', function () {
|
||||||
|
if (this.creationDate !== undefined) {
|
||||||
|
return this.trigger('creation-date', this.creationDate);
|
||||||
|
}
|
||||||
|
return this.fillInfo();
|
||||||
|
});
|
||||||
|
this.on('content-digest-chars', function (chars) {
|
||||||
|
this.chars = chars;
|
||||||
|
});
|
||||||
|
this.on('get-content-digest-chars', function () {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
return this.fillInfo();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fillInfo() {
|
||||||
|
if (this._fillInfoWaiting) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._fillInfoWaiting = true;
|
||||||
|
const oReq = new Http();
|
||||||
|
const self = this;
|
||||||
|
oReq.addEventListener('loadend', function () {
|
||||||
|
if (this.status == 200 || this.status == 202) {
|
||||||
|
const response = JSON.parse(this.responseText);
|
||||||
|
if (response.mediaType === 'application/vnd.docker.distribution.manifest.list.v2+json') {
|
||||||
|
self.trigger('list', response);
|
||||||
|
const manifest = response.manifests[0];
|
||||||
|
const image = new DockerImage(self.name, manifest.digest);
|
||||||
|
eventTransfer(image, self);
|
||||||
|
image.fillInfo();
|
||||||
|
self.variants = [image];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.size = response.layers.reduce(function (acc, e) {
|
||||||
|
return acc + e.size;
|
||||||
|
}, 0);
|
||||||
|
self.sha256 = response.config.digest;
|
||||||
|
self.layers = response.layers;
|
||||||
|
self.trigger('size', self.size);
|
||||||
|
self.trigger('sha256', self.sha256);
|
||||||
|
oReq.getContentDigest(function (digest) {
|
||||||
|
self.digest = digest;
|
||||||
|
self.trigger('content-digest', digest);
|
||||||
|
if (!digest) {
|
||||||
|
// registryUI.showErrorCanNotReadContentDigest();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
self.getBlobs(response.config.digest);
|
||||||
|
} else if (this.status == 404) {
|
||||||
|
// registryUI.errorSnackbar('Manifest for ' + self.name + ':' + self.tag + ' not found');
|
||||||
|
} else {
|
||||||
|
// registryUI.snackbar(this.responseText);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
oReq.open('GET', registryUI.url() + '/v2/' + self.name + '/manifests/' + self.tag);
|
||||||
|
oReq.setRequestHeader(
|
||||||
|
'Accept',
|
||||||
|
'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json' +
|
||||||
|
(self.list ? ', application/vnd.docker.distribution.manifest.list.v2+json' : '')
|
||||||
|
);
|
||||||
|
oReq.send();
|
||||||
|
}
|
||||||
|
getBlobs() {
|
||||||
|
const oReq = new Http();
|
||||||
|
const self = this;
|
||||||
|
oReq.addEventListener('loadend', function () {
|
||||||
|
if (this.status == 200 || this.status == 202) {
|
||||||
|
const response = JSON.parse(this.responseText);
|
||||||
|
self.creationDate = new Date(response.created);
|
||||||
|
self.blobs = response;
|
||||||
|
self.blobs.history
|
||||||
|
.filter(function (e) {
|
||||||
|
return !e.empty_layer;
|
||||||
|
})
|
||||||
|
.forEach(function (e, i) {
|
||||||
|
e.size = self.layers[i].size;
|
||||||
|
e.id = self.layers[i].digest.replace('sha256:', '');
|
||||||
|
});
|
||||||
|
self.blobs.id = blob.replace('sha256:', '');
|
||||||
|
self.trigger('creation-date', self.creationDate);
|
||||||
|
self.trigger('blobs', self.blobs);
|
||||||
|
} else if (this.status == 404) {
|
||||||
|
registryUI.errorSnackbar('Blobs for ' + self.name + ':' + self.tag + ' not found');
|
||||||
|
} else {
|
||||||
|
registryUI.snackbar(this.responseText);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
oReq.open('GET', registryUI.url() + '/v2/' + self.name + '/blobs/' + blob);
|
||||||
|
oReq.setRequestHeader(
|
||||||
|
'Accept',
|
||||||
|
'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json'
|
||||||
|
);
|
||||||
|
oReq.send();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import { route, router, getCurrentRoute } from '@riotjs/route';
|
import { router, getCurrentRoute } from '@riotjs/route';
|
||||||
|
|
||||||
function baseUrl() {
|
function baseUrl() {
|
||||||
return getCurrentRoute().replace(/#!(.*)/, '');
|
return getCurrentRoute().replace(/#!(.*)/, '');
|
||||||
|
@ -11,4 +11,7 @@ export default {
|
||||||
taglist(image) {
|
taglist(image) {
|
||||||
router.push(`${baseUrl()}#!/taglist/${image}`);
|
router.push(`${baseUrl()}#!/taglist/${image}`);
|
||||||
},
|
},
|
||||||
|
getTagListImage() {
|
||||||
|
return getCurrentRoute().replace(/^.*(#!)?\/?taglist\//, '');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
|
export function bytesToSize(bytes) {
|
||||||
registryUI.bytesToSize = function (bytes) {
|
|
||||||
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
||||||
if (bytes == undefined || isNaN(bytes)) {
|
if (bytes == undefined || isNaN(bytes)) {
|
||||||
return '?';
|
return '?';
|
||||||
|
@ -8,13 +7,26 @@ registryUI.bytesToSize = function (bytes) {
|
||||||
}
|
}
|
||||||
const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
|
const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
|
||||||
return Math.ceil(bytes / Math.pow(1024, i)) + ' ' + sizes[i];
|
return Math.ceil(bytes / Math.pow(1024, i)) + ' ' + sizes[i];
|
||||||
};
|
}
|
||||||
|
|
||||||
registryUI.dateFormat = function(date) {
|
export function dateFormat(date) {
|
||||||
if (date === undefined) {
|
if (date === undefined) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
const labels = ['a second', 'seconds', 'a minute', 'minutes', 'an hour', 'hours', 'a day', 'days', 'a month', 'months', 'a year', 'years'];
|
const labels = [
|
||||||
|
'a second',
|
||||||
|
'seconds',
|
||||||
|
'a minute',
|
||||||
|
'minutes',
|
||||||
|
'an hour',
|
||||||
|
'hours',
|
||||||
|
'a day',
|
||||||
|
'days',
|
||||||
|
'a month',
|
||||||
|
'months',
|
||||||
|
'a year',
|
||||||
|
'years',
|
||||||
|
];
|
||||||
const maxSeconds = [1, 60, 3600, 86400, 2592000, 31104000, Infinity];
|
const maxSeconds = [1, 60, 3600, 86400, 2592000, 31104000, Infinity];
|
||||||
const diff = (new Date() - date) / 1000;
|
const diff = (new Date() - date) / 1000;
|
||||||
for (var i = 0; i < maxSeconds.length - 1; i++) {
|
for (var i = 0; i < maxSeconds.length - 1; i++) {
|
||||||
|
@ -24,10 +36,9 @@ registryUI.dateFormat = function(date) {
|
||||||
return Math.floor(diff / maxSeconds[i]) + ' ' + labels[i * 2 + 1];
|
return Math.floor(diff / maxSeconds[i]) + ' ' + labels[i * 2 + 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
export function getHistoryIcon(attribute) {
|
||||||
registryUI.getHistoryIcon = function(attribute) {
|
|
||||||
switch (attribute) {
|
switch (attribute) {
|
||||||
case 'architecture':
|
case 'architecture':
|
||||||
return 'memory';
|
return 'memory';
|
||||||
|
@ -63,29 +74,39 @@ registryUI.getHistoryIcon = function(attribute) {
|
||||||
case 'ExposedPorts':
|
case 'ExposedPorts':
|
||||||
return 'router';
|
return 'router';
|
||||||
default:
|
default:
|
||||||
''
|
'';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
registryUI.getPage = function(elts, page, limit) {
|
export function getPage(elts, page, limit) {
|
||||||
if (!limit) { limit = 100; }
|
if (!limit) {
|
||||||
if (!elts) { return []; }
|
limit = 100;
|
||||||
|
}
|
||||||
|
if (!elts) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
return elts.slice((page - 1) * limit, limit * page);
|
return elts.slice((page - 1) * limit, limit * page);
|
||||||
}
|
}
|
||||||
|
|
||||||
registryUI.getNumPages = function(elts, limit) {
|
export function getNumPages(elts, limit) {
|
||||||
if (!limit) { limit = 100; }
|
if (!limit) {
|
||||||
if (!elts) { return 0; }
|
limit = 100;
|
||||||
|
}
|
||||||
|
if (!elts) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return Math.trunc(elts.length / limit) + 1;
|
return Math.trunc(elts.length / limit) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
registryUI.getPageLabels = function(page, nPages) {
|
export function getPageLabels(page, nPages) {
|
||||||
var pageLabels = [];
|
var pageLabels = [];
|
||||||
var maxItems = 10;
|
var maxItems = 10;
|
||||||
if (nPages === 1) { return pageLabels; }
|
if (nPages === 1) {
|
||||||
|
return pageLabels;
|
||||||
|
}
|
||||||
if (page !== 1 && nPages >= maxItems) {
|
if (page !== 1 && nPages >= maxItems) {
|
||||||
pageLabels.push({'icon': 'first_page', page: 1});
|
pageLabels.push({ 'icon': 'first_page', page: 1 });
|
||||||
pageLabels.push({'icon': 'chevron_left', page: page - 1});
|
pageLabels.push({ 'icon': 'chevron_left', page: page - 1 });
|
||||||
}
|
}
|
||||||
var start = Math.round(Math.max(1, Math.min(page - maxItems / 2, nPages - maxItems + 1)));
|
var start = Math.round(Math.max(1, Math.min(page - maxItems / 2, nPages - maxItems + 1)));
|
||||||
for (var i = start; i < Math.min(nPages + 1, start + maxItems); i++) {
|
for (var i = start; i < Math.min(nPages + 1, start + maxItems); i++) {
|
||||||
|
@ -93,35 +114,39 @@ registryUI.getPageLabels = function(page, nPages) {
|
||||||
page: i,
|
page: i,
|
||||||
current: i === page,
|
current: i === page,
|
||||||
'space-left': page === 1 && nPages > maxItems,
|
'space-left': page === 1 && nPages > maxItems,
|
||||||
'space-right': page === nPages && nPages > maxItems
|
'space-right': page === nPages && nPages > maxItems,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (page !== nPages && nPages >= maxItems) {
|
if (page !== nPages && nPages >= maxItems) {
|
||||||
pageLabels.push({'icon': 'chevron_right', page: page + 1});
|
pageLabels.push({ 'icon': 'chevron_right', page: page + 1 });
|
||||||
pageLabels.push({'icon': 'last_page', page: nPages});
|
pageLabels.push({ 'icon': 'last_page', page: nPages });
|
||||||
}
|
}
|
||||||
return pageLabels;
|
return pageLabels;
|
||||||
}
|
}
|
||||||
|
|
||||||
registryUI.updateQueryString = function(qs) {
|
export function updateQueryString(qs) {
|
||||||
var search = '';
|
var search = '';
|
||||||
for (var key in qs) {
|
for (var key in qs) {
|
||||||
if (qs[key] !== undefined) {
|
if (qs[key] !== undefined) {
|
||||||
search += (search.length > 0 ? '&' : '?') +key + '=' + qs[key];
|
search += (search.length > 0 ? '&' : '?') + key + '=' + qs[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
history.pushState(null, '', search + window.location.hash);
|
history.pushState(null, '', search + window.location.hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
registryUI.stripHttps = function (url) {
|
export function stripHttps(url) {
|
||||||
if (!url) {
|
if (!url) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
return url.replace(/^https?:\/\//, '');
|
return url.replace(/^https?:\/\//, '');
|
||||||
};
|
|
||||||
|
|
||||||
registryUI.eventTransfer = function(from, to) {
|
|
||||||
from.on('*', function(event, param) {
|
|
||||||
to.trigger(event, param);
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function eventTransfer(from, to) {
|
||||||
|
from.on('*', function (event, param) {
|
||||||
|
to.trigger(event, param);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isDigit(char) {
|
||||||
|
return char >= '0' && char <= '9';
|
||||||
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue