mirror of
https://github.com/Joxit/docker-registry-ui.git
synced 2025-04-26 06:59:52 +03:00
feat: expose some custom labels
This commit is contained in:
parent
19e72e4a5f
commit
ba6d817b41
7 changed files with 182 additions and 129 deletions
|
@ -100,6 +100,7 @@ Some env options are available for use this interface for **only one server**.
|
|||
- `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.
|
||||
|
||||
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/).
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ sed -i "s~\${SHOW_CONTENT_DIGEST}~${SHOW_CONTENT_DIGEST}~" 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
|
||||
sed -i "s~\${HISTORY_CUSTOM_LABELS}~${HISTORY_CUSTOM_LABELS}~" index.html
|
||||
|
||||
if [ -z "${DELETE_IMAGES}" ] || [ "${DELETE_IMAGES}" = false ] ; then
|
||||
sed -i "s/\${DELETE_IMAGES}/false/" index.html
|
||||
|
@ -64,4 +65,4 @@ if [ "$(whoami)" != "root" ]; then
|
|||
sed -i "s,/var/run/nginx.pid,/tmp/nginx.pid," /etc/nginx/nginx.conf
|
||||
fi
|
||||
|
||||
sed -i "s,listen 80;,listen $NGINX_LISTEN_PORT;," /etc/nginx/conf.d/default.conf
|
||||
sed -i "s,listen 80;,listen $NGINX_LISTEN_PORT;," /etc/nginx/conf.d/default.conf
|
||||
|
|
|
@ -42,7 +42,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
<tag-history registry-url="{ state.registryUrl }" registry-name="{ state.name }" pull-url="{ state.pullUrl }"
|
||||
image="{ router.getTagHistoryImage() }" tag="{ router.getTagHistoryTag() }"
|
||||
is-image-remove-activated="{ truthy(props.isImageRemoveActivated) }" on-notify="{ notifySnackbar }"
|
||||
on-authentication="{ onAuthentication }"></tag-history>
|
||||
on-authentication="{ onAuthentication }" history-custom-labels="{ stringToArray(props.historyCustomLabels) }"></tag-history>
|
||||
</route>
|
||||
</router>
|
||||
<registry-authentication realm="{ state.realm }" scope="{ state.scope }" service="{ state.service }"
|
||||
|
@ -80,7 +80,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
stripHttps,
|
||||
getRegistryServers,
|
||||
setRegistryServers,
|
||||
truthy
|
||||
truthy,
|
||||
stringToArray
|
||||
} from '../scripts/utils';
|
||||
import router from '../scripts/router';
|
||||
|
||||
|
@ -175,7 +176,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
baseRoute: '([^#]*?)/(\\?[^#]*?)?(#!)?(/?)',
|
||||
router,
|
||||
version,
|
||||
truthy
|
||||
truthy,
|
||||
stringToArray
|
||||
}
|
||||
</script>
|
||||
</docker-registry-ui>
|
|
@ -15,17 +15,16 @@ You should have received a copy of the GNU Affero General Public License
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<tag-history-element class="{ state.key }">
|
||||
<div class="headline"><i class="material-icons">{ state.icon }</i>
|
||||
<div class="headline">
|
||||
<i class="material-icons">{ state.icon }</i>
|
||||
<p>{ state.name }</p>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="value" if="{ state.value }"> { state.value }</div>
|
||||
<div class="values value" each="{ value in state.values }" if="{ state.values }"> { value }</div>
|
||||
<div class="value" if="{ state.value }">{ state.value }</div>
|
||||
<div class="values value" each="{ value in state.values }" if="{ state.values }">{ value }</div>
|
||||
</div>
|
||||
<script>
|
||||
import {
|
||||
getHistoryIcon
|
||||
} from '../../scripts/utils';
|
||||
import { getHistoryIcon } from '../../scripts/utils';
|
||||
export default {
|
||||
onBeforeStart(props, state) {
|
||||
state.key = props.entry.key;
|
||||
|
@ -48,14 +47,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
return name;
|
||||
} else if (name === 'os') {
|
||||
return 'OS';
|
||||
} else if (name.startsWith('custom-label-')) {
|
||||
name = name.replace('custom-label-', '');
|
||||
}
|
||||
return name.replace(/([a-z])([A-Z])/g, '$1 $2')
|
||||
.replace('_', ' ')
|
||||
return name
|
||||
.replace(/([a-z])([A-Z])/g, '$1 $2')
|
||||
.replace(/[_-]/g, ' ')
|
||||
.split(' ')
|
||||
.map(word => `${word.charAt(0).toUpperCase()}${word.slice(1)}`)
|
||||
.map((word) => `${word.charAt(0).toUpperCase()}${word.slice(1)}`)
|
||||
.join(' ');
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
:host.Labels .value,
|
||||
|
@ -70,7 +72,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
:host.docker_version .headline .material-icons {
|
||||
background-size: 24px auto;
|
||||
background-image: url("images/docker-logo.svg");
|
||||
background-image: url('images/docker-logo.svg');
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
|
@ -103,4 +105,4 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
</tag-history-element>
|
||||
</tag-history-element>
|
||||
|
|
|
@ -20,33 +20,35 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
<material-button waves-center="true" rounded="true" waves-color="#ddd" onClick="{ toTaglist }">
|
||||
<i class="material-icons">arrow_back</i>
|
||||
</material-button>
|
||||
<h2>
|
||||
History of { props.image }:{ props.tag } <i class="material-icons">history</i>
|
||||
</h2>
|
||||
<h2>History of { props.image }:{ props.tag } <i class="material-icons">history</i></h2>
|
||||
</div>
|
||||
</material-card>
|
||||
<div if="{ !state.loadend }" class="spinner-wrapper">
|
||||
<material-spinner />
|
||||
<material-spinner></material-spinner>
|
||||
</div>
|
||||
|
||||
<material-tabs if="{ state.archs && state.loadend }" useLine="{ true }" tabs="{ state.archs }"
|
||||
onTabChanged="{ onTabChanged }" />
|
||||
<material-tabs
|
||||
if="{ state.archs && state.loadend }"
|
||||
useLine="{ true }"
|
||||
tabs="{ state.archs }"
|
||||
onTabChanged="{ onTabChanged }"
|
||||
></material-tabs>
|
||||
|
||||
<material-card each="{ element in state.elements }" class="tag-history-element">
|
||||
<tag-history-element each="{ entry in element }" if="{ entry.value && entry.value.length > 0}" entry="{ entry }" />
|
||||
<tag-history-element
|
||||
each="{ entry in element }"
|
||||
if="{ entry.value && entry.value.length > 0}"
|
||||
entry="{ entry }"
|
||||
></tag-history-element>
|
||||
</material-card>
|
||||
<script>
|
||||
import {
|
||||
DockerImage
|
||||
} from '../../scripts/docker-image';
|
||||
import {
|
||||
bytesToSize
|
||||
} from '../../scripts/utils';
|
||||
import { DockerImage } from '../../scripts/docker-image';
|
||||
import { bytesToSize } from '../../scripts/utils';
|
||||
import router from '../../scripts/router';
|
||||
import TagHistoryElement from './tag-history-element.riot'
|
||||
import TagHistoryElement from './tag-history-element.riot';
|
||||
export default {
|
||||
components: {
|
||||
TagHistoryElement
|
||||
TagHistoryElement,
|
||||
},
|
||||
onBeforeMount(props, state) {
|
||||
state.elements = [];
|
||||
|
@ -54,9 +56,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
list: true,
|
||||
registryUrl: props.registryUrl,
|
||||
onNotify: props.onNotify,
|
||||
onAuthentication: props.onAuthentication
|
||||
onAuthentication: props.onAuthentication,
|
||||
});
|
||||
state.image.fillInfo()
|
||||
state.image.fillInfo();
|
||||
},
|
||||
onMounted(props, state) {
|
||||
state.image.on('blobs', this.processBlobs);
|
||||
|
@ -64,16 +66,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
},
|
||||
onTabChanged(arch, idx) {
|
||||
const state = this.state;
|
||||
const {
|
||||
registryUrl,
|
||||
onNotify
|
||||
} = this.props;
|
||||
state.elements = []
|
||||
state.image.variants[idx] = state.image.variants[idx] ||
|
||||
const { registryUrl, onNotify } = this.props;
|
||||
state.elements = [];
|
||||
state.image.variants[idx] =
|
||||
state.image.variants[idx] ||
|
||||
new DockerImage(this.props.image, arch.digest, {
|
||||
list: false,
|
||||
registryUrl,
|
||||
onNotify
|
||||
onNotify,
|
||||
});
|
||||
if (state.image.variants[idx].blobs) {
|
||||
return this.processBlobs(state.image.variants[idx].blobs);
|
||||
|
@ -83,6 +83,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
},
|
||||
processBlobs(blobs) {
|
||||
const state = this.state;
|
||||
const { historyCustomLabels } = this.props;
|
||||
|
||||
function exec(elt) {
|
||||
const guiElements = [];
|
||||
|
@ -90,8 +91,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
if (elt.hasOwnProperty(attribute) && attribute != 'empty_layer') {
|
||||
const value = elt[attribute];
|
||||
const guiElement = {
|
||||
"key": attribute,
|
||||
"value": modifySpecificAttributeTypes(attribute, value)
|
||||
'key': attribute,
|
||||
'value': modifySpecificAttributeTypes(attribute, value),
|
||||
};
|
||||
guiElements.push(guiElement);
|
||||
}
|
||||
|
@ -99,32 +100,35 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
return guiElements.sort(eltSort);
|
||||
}
|
||||
const elements = new Array(blobs.history.length + 1);
|
||||
elements[0] = exec(getConfig(blobs));
|
||||
elements[0] = exec(getConfig(blobs, { historyCustomLabels }));
|
||||
blobs.history.forEach(function (elt, i) {
|
||||
elements[blobs.history.length - i] = exec(elt)
|
||||
elements[blobs.history.length - i] = exec(elt);
|
||||
});
|
||||
this.update({
|
||||
elements,
|
||||
loadend: true
|
||||
loadend: true,
|
||||
});
|
||||
},
|
||||
multiArchList(manifests) {
|
||||
manifests = manifests.manifests || manifests;
|
||||
const archs = manifests.map(function (manifest) {
|
||||
return {
|
||||
title: manifest.platform.os + '/' + manifest.platform.architecture + (manifest.platform.variant ?
|
||||
manifest.platform.variant : ''),
|
||||
digest: manifest.digest
|
||||
}
|
||||
title:
|
||||
manifest.platform.os +
|
||||
'/' +
|
||||
manifest.platform.architecture +
|
||||
(manifest.platform.variant ? manifest.platform.variant : ''),
|
||||
digest: manifest.digest,
|
||||
};
|
||||
});
|
||||
this.update({
|
||||
archs
|
||||
archs,
|
||||
});
|
||||
},
|
||||
toTaglist() {
|
||||
router.taglist(this.props.image);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
const eltIdx = function (e) {
|
||||
switch (e) {
|
||||
case 'created':
|
||||
|
@ -158,7 +162,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
return new Date(value).toLocaleString();
|
||||
case 'created_by':
|
||||
const cmd = value.match(/\/bin\/sh *-c *#\(nop\) *([A-Z]+)/);
|
||||
return (cmd && cmd[1]) || 'RUN'
|
||||
return (cmd && cmd[1]) || 'RUN';
|
||||
case 'size':
|
||||
return bytesToSize(value);
|
||||
case 'Entrypoint':
|
||||
|
@ -175,26 +179,47 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
return value || '';
|
||||
};
|
||||
|
||||
const getConfig = function (blobs) {
|
||||
const res = ['architecture', 'User', 'created', 'docker_version', 'os', 'Cmd', 'Entrypoint', 'Env', 'Labels',
|
||||
'User', 'Volumes', 'WorkingDir', 'author', 'id', 'ExposedPorts'
|
||||
]
|
||||
.reduce(function (acc, e) {
|
||||
const value = blobs[e] || blobs.config[e];
|
||||
if (value && e === 'architecture' && blobs.variant) {
|
||||
acc[e] = value + blobs.variant;
|
||||
} else if (value) {
|
||||
acc[e] = value;
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
const getConfig = function (blobs, { historyCustomLabels }) {
|
||||
console.log(this);
|
||||
const res = [
|
||||
'architecture',
|
||||
'User',
|
||||
'created',
|
||||
'docker_version',
|
||||
'os',
|
||||
'Cmd',
|
||||
'Entrypoint',
|
||||
'Env',
|
||||
'Labels',
|
||||
'User',
|
||||
'Volumes',
|
||||
'WorkingDir',
|
||||
'author',
|
||||
'id',
|
||||
'ExposedPorts',
|
||||
].reduce(function (acc, e) {
|
||||
const value = blobs[e] || blobs.config[e];
|
||||
if (value && e === 'architecture' && blobs.variant) {
|
||||
acc[e] = value + blobs.variant;
|
||||
} else if (value) {
|
||||
acc[e] = value;
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
if (!res.author && (res.Labels && res.Labels.maintainer)) {
|
||||
if (!res.author && res.Labels && res.Labels.maintainer) {
|
||||
res.author = blobs.config.Labels.maintainer;
|
||||
delete res.Labels.maintainer;
|
||||
}
|
||||
|
||||
historyCustomLabels
|
||||
.filter((label) => res.Labels[label])
|
||||
.forEach((label) => {
|
||||
res[`custom-label-${label}`] = res.Labels[label];
|
||||
delete res.Labels[label];
|
||||
});
|
||||
|
||||
return res;
|
||||
};
|
||||
</script>
|
||||
</tag-history>
|
||||
</tag-history>
|
||||
|
|
133
src/index.html
133
src/index.html
|
@ -16,63 +16,78 @@
|
|||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<!-- build:css docker-registry-ui.css -->
|
||||
<link href="../node_modules/riot-mui/build/styles/riot-mui.min.css" rel="stylesheet" type="text/css" />
|
||||
<link href="style.css" rel="stylesheet" type="text/css" />
|
||||
<link href="material-icons.css" rel="stylesheet" type="text/css" />
|
||||
<link href="roboto.css" rel="stylesheet" type="text/css" />
|
||||
<!-- endbuild -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta property="og:site_name" content="Docker Registry UI" />
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<meta name="twitter:site" content="@Joxit" />
|
||||
<meta name="twitter:creator" content="@Jones Magloire" />
|
||||
<title>Docker Registry UI</title>
|
||||
</head>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<!-- build:css docker-registry-ui.css -->
|
||||
<link href="../node_modules/riot-mui/build/styles/riot-mui.min.css" rel="stylesheet" type="text/css">
|
||||
<link href="style.css" rel="stylesheet" type="text/css">
|
||||
<link href="material-icons.css" rel="stylesheet" type="text/css">
|
||||
<link href="roboto.css" rel="stylesheet" type="text/css">
|
||||
<!-- endbuild -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta property="og:site_name" content="Docker Registry UI" />
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<meta name="twitter:site" content="@Joxit" />
|
||||
<meta name="twitter:creator" content="@Jones Magloire" />
|
||||
<title>Docker Registry UI</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- build:keep production -->
|
||||
<docker-registry-ui registry-url="${REGISTRY_URL}" name="${REGISTRY_TITLE}" pull-url="${PULL_URL}"
|
||||
show-content-digest="${SHOW_CONTENT_DIGEST}" is-image-remove-activated="${DELETE_IMAGES}"
|
||||
catalog-elements-limit="${CATALOG_ELEMENTS_LIMIT}" single-registry="${SINGLE_REGISTRY}"
|
||||
default-registries="${DEFAULT_REGISTRIES}" read-only-registries="${READ_ONLY_REGISTRIES}"
|
||||
show-catalog-nb-tags="${SHOW_CATALOG_NB_TAGS}">
|
||||
</docker-registry-ui>
|
||||
<!-- endbuild -->
|
||||
<!-- build:keep developement -->
|
||||
<docker-registry-ui registry-url="" name="Developement Registry" pull-url="" show-content-digest="true"
|
||||
is-image-remove-activated="true" catalog-elements-limit="1000" single-registry="false" show-catalog-nb-tags="true">
|
||||
</docker-registry-ui>
|
||||
<!-- endbuild -->
|
||||
<!-- build:js docker-registry-ui.js -->
|
||||
<script src="../node_modules/riot/riot+compiler.min.js"></script>
|
||||
<script src="../node_modules/riot-route/dist/route.js"></script>
|
||||
<script src="../node_modules/riot-mui/build/js/riot-mui.js"></script>
|
||||
<script src="tags/catalog.riot" type="riot/tag"></script>
|
||||
<script src="tags/catalog-element.riot" type="riot/tag"></script>
|
||||
<script src="tags/tag-history-button.riot" type="riot/tag"></script>
|
||||
<script src="tags/tag-history.riot" type="riot/tag"></script>
|
||||
<script src="tags/tag-history-element.riot" type="riot/tag"></script>
|
||||
<script src="tags/taglist.riot" type="riot/tag"></script>
|
||||
<script src="tags/image-tag.riot" type="riot/tag"></script>
|
||||
<script src="tags/remove-image.riot" type="riot/tag"></script>
|
||||
<script src="tags/copy-to-clipboard.riot" type="riot/tag"></script>
|
||||
<script src="tags/dialogs/add.riot" type="riot/tag"></script>
|
||||
<script src="tags/dialogs/change.riot" type="riot/tag"></script>
|
||||
<script src="tags/dialogs/remove.riot" type="riot/tag"></script>
|
||||
<script src="tags/dialogs/menu.riot" type="riot/tag"></script>
|
||||
<script src="tags/image-size.riot" type="riot/tag"></script>
|
||||
<script src="tags/image-date.riot" type="riot/tag"></script>
|
||||
<script src="tags/image-content-digest.riot" type="riot/tag"></script>
|
||||
<script src="tags/pagination.riot" type="riot/tag"></script>
|
||||
<script src="tags/app.riot" type="riot/tag"></script>
|
||||
<script src="scripts/http.js"></script>
|
||||
<script src="scripts/script.js"></script>
|
||||
<script src="scripts/utils.js"></script>
|
||||
<!-- endbuild -->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
<body>
|
||||
<!-- build:keep production -->
|
||||
<docker-registry-ui
|
||||
registry-url="${REGISTRY_URL}"
|
||||
name="${REGISTRY_TITLE}"
|
||||
pull-url="${PULL_URL}"
|
||||
show-content-digest="${SHOW_CONTENT_DIGEST}"
|
||||
is-image-remove-activated="${DELETE_IMAGES}"
|
||||
catalog-elements-limit="${CATALOG_ELEMENTS_LIMIT}"
|
||||
single-registry="${SINGLE_REGISTRY}"
|
||||
default-registries="${DEFAULT_REGISTRIES}"
|
||||
read-only-registries="${READ_ONLY_REGISTRIES}"
|
||||
show-catalog-nb-tags="${SHOW_CATALOG_NB_TAGS}"
|
||||
history-custom-labels="${HISTORY_CUSTOM_LABELS}"
|
||||
>
|
||||
</docker-registry-ui>
|
||||
<!-- endbuild -->
|
||||
<!-- build:keep developement -->
|
||||
<docker-registry-ui
|
||||
registry-url=""
|
||||
name="Developement Registry"
|
||||
pull-url=""
|
||||
show-content-digest="true"
|
||||
is-image-remove-activated="true"
|
||||
catalog-elements-limit="1000"
|
||||
single-registry="false"
|
||||
show-catalog-nb-tags="true"
|
||||
history-custom-labels="first_custom_labels,second_custom_labels"
|
||||
>
|
||||
</docker-registry-ui>
|
||||
<!-- endbuild -->
|
||||
<!-- build:js docker-registry-ui.js -->
|
||||
<script src="../node_modules/riot/riot+compiler.min.js"></script>
|
||||
<script src="../node_modules/riot-route/dist/route.js"></script>
|
||||
<script src="../node_modules/riot-mui/build/js/riot-mui.js"></script>
|
||||
<script src="tags/catalog.riot" type="riot/tag"></script>
|
||||
<script src="tags/catalog-element.riot" type="riot/tag"></script>
|
||||
<script src="tags/tag-history-button.riot" type="riot/tag"></script>
|
||||
<script src="tags/tag-history.riot" type="riot/tag"></script>
|
||||
<script src="tags/tag-history-element.riot" type="riot/tag"></script>
|
||||
<script src="tags/taglist.riot" type="riot/tag"></script>
|
||||
<script src="tags/image-tag.riot" type="riot/tag"></script>
|
||||
<script src="tags/remove-image.riot" type="riot/tag"></script>
|
||||
<script src="tags/copy-to-clipboard.riot" type="riot/tag"></script>
|
||||
<script src="tags/dialogs/add.riot" type="riot/tag"></script>
|
||||
<script src="tags/dialogs/change.riot" type="riot/tag"></script>
|
||||
<script src="tags/dialogs/remove.riot" type="riot/tag"></script>
|
||||
<script src="tags/dialogs/menu.riot" type="riot/tag"></script>
|
||||
<script src="tags/image-size.riot" type="riot/tag"></script>
|
||||
<script src="tags/image-date.riot" type="riot/tag"></script>
|
||||
<script src="tags/image-content-digest.riot" type="riot/tag"></script>
|
||||
<script src="tags/pagination.riot" type="riot/tag"></script>
|
||||
<script src="tags/app.riot" type="riot/tag"></script>
|
||||
<script src="scripts/http.js"></script>
|
||||
<script src="scripts/script.js"></script>
|
||||
<script src="scripts/utils.js"></script>
|
||||
<!-- endbuild -->
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -76,7 +76,10 @@ export function getHistoryIcon(attribute) {
|
|||
case 'ExposedPorts':
|
||||
return 'router';
|
||||
default:
|
||||
'';
|
||||
if (attribute.startsWith('custom-label-')) {
|
||||
return 'label';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,3 +204,7 @@ export function decodeURI(url) {
|
|||
export function truthy(value) {
|
||||
return value === true || value === 'true';
|
||||
}
|
||||
|
||||
export function stringToArray(value) {
|
||||
return value && typeof value === 'string' ? value.split(',') : [];
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue