mirror of
https://github.com/Joxit/docker-registry-ui.git
synced 2025-04-25 22:49:54 +03:00
feat(branching): add configuration for catalog arborescence
This commit is contained in:
parent
398fa65fa1
commit
1031034bc4
11 changed files with 80 additions and 43 deletions
|
@ -13,6 +13,8 @@ sed -i "s~\${HISTORY_CUSTOM_LABELS}~${HISTORY_CUSTOM_LABELS}~" index.html
|
|||
sed -i "s~\${USE_CONTROL_CACHE_HEADER}~${USE_CONTROL_CACHE_HEADER}~" index.html
|
||||
sed -i "s~\${TAGLIST_ORDER}~${TAGLIST_ORDER}~" index.html
|
||||
sed -i "s~\${CATALOG_DEFAULT_EXPANDED}~${CATALOG_DEFAULT_EXPANDED}~" index.html
|
||||
sed -i "s~\${CATALOG_MIN_BRANCHES}~${CATALOG_MIN_BRANCHES}~" index.html
|
||||
sed -i "s~\${CATALOG_MAX_BRANCHES}~${CATALOG_MAX_BRANCHES}~" index.html
|
||||
|
||||
grep -o 'THEME[A-Z_]*' index.html | while read e; do
|
||||
sed -i "s~\${$e}~$(printenv $e)~" index.html
|
||||
|
|
|
@ -52,6 +52,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
show-catalog-nb-tags="{ props.showCatalogNbTags }"
|
||||
class="animated {!state.expanded && !props.filterResults ? 'hide' : ''} {state.expanding ? 'expanding' : ''}"
|
||||
each="{item in state.images}"
|
||||
z-index="{ props.zIndex - 1 }"
|
||||
item="{ item }"
|
||||
></catalog-element>
|
||||
</div>
|
||||
|
@ -76,6 +77,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
this.getNbTags(props, state);
|
||||
}
|
||||
},
|
||||
onMounted(props, state) {
|
||||
const materialCard = this.$('material-card');
|
||||
if (materialCard) {
|
||||
materialCard.style['z-index'] = props.zIndex;
|
||||
}
|
||||
},
|
||||
onBeforeUpdate(props, state) {
|
||||
if (props.filterResults && state.images) {
|
||||
state.nImages = state.images.filter((image) => matchSearch(props.filterResults, image)).length;
|
||||
|
|
|
@ -35,10 +35,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
on-authentication="{ props.onAuthentication }"
|
||||
show-catalog-nb-tags="{ props.showCatalogNbTags }"
|
||||
catalog-default-expanded="{ props.catalogDefaultExpanded || state.nRepositories === 1 }"
|
||||
z-index="{ props.catalogMaxBranches - props.catalogMinBranches + 2 }"
|
||||
></catalog-element>
|
||||
<script>
|
||||
import CatalogElement from './catalog-element.riot';
|
||||
import { Http } from '../../scripts/http';
|
||||
import { getBranching } from '../../scripts/repositories';
|
||||
import { getRegistryServers } from '../../scripts/utils';
|
||||
|
||||
export default {
|
||||
|
@ -56,6 +58,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
onBeforeMount(props) {
|
||||
this.state.registryName = props.registryName;
|
||||
this.state.catalogElementsLimit = props.catalogElementsLimit;
|
||||
try {
|
||||
this.state.branching = getBranching(props.catalogMinBranches, props.catalogMaxBranches);
|
||||
} catch (e) {
|
||||
props.onNotify(e);
|
||||
}
|
||||
},
|
||||
onMounted(props, state) {
|
||||
this.display(props, state);
|
||||
|
@ -69,6 +76,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
}
|
||||
state.registryUrl = props.registryUrl;
|
||||
let repositories = [];
|
||||
let nImages = 0;
|
||||
const self = this;
|
||||
const catalogUrl = `${props.registryUrl}/v2/_catalog?n=${state.catalogElementsLimit}`;
|
||||
const oReq = new Http({
|
||||
|
@ -78,22 +86,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
if (this.status === 200) {
|
||||
repositories = JSON.parse(this.responseText).repositories || [];
|
||||
repositories.sort();
|
||||
repositories = repositories.reduce(function (acc, e) {
|
||||
const slash = e.indexOf('/');
|
||||
if (slash > 0) {
|
||||
const repoName = e.substring(0, slash) + '/';
|
||||
if (acc.length === 0 || acc[acc.length - 1].repo != repoName) {
|
||||
acc.push({
|
||||
repo: repoName,
|
||||
images: [],
|
||||
});
|
||||
}
|
||||
acc[acc.length - 1].images.push(e);
|
||||
return acc;
|
||||
}
|
||||
acc.push(e);
|
||||
return acc;
|
||||
}, []);
|
||||
nImages = repositories.length;
|
||||
if (typeof state.branching === 'function') {
|
||||
repositories = state.branching(repositories);
|
||||
}
|
||||
} else if (this.status === 404) {
|
||||
self.props.onNotify({ code: 'CATALOG_NOT_FOUND', url: catalogUrl }, true);
|
||||
} else if (this.status === 400) {
|
||||
|
@ -116,7 +112,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
self.update({
|
||||
repositories,
|
||||
nRepositories: repositories.length,
|
||||
nImages: repositories.reduce((acc, e) => acc + ((e.images && e.images.length) || 1), 0),
|
||||
nImages,
|
||||
loadend: true,
|
||||
});
|
||||
});
|
||||
|
@ -125,4 +121,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
catalog {
|
||||
display: block;
|
||||
margin: auto;
|
||||
}
|
||||
catalog > material-card {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
</catalog>
|
||||
|
|
|
@ -31,6 +31,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
</material-navbar>
|
||||
</header>
|
||||
<main>
|
||||
<error-page
|
||||
if="{ state.pageError && !Array.isArray(state.pageError.errors) }"
|
||||
code="{ state.pageError.code }"
|
||||
status="{ state.pageError.status }"
|
||||
message="{ state.pageError.message }"
|
||||
url="{ state.pageError.url }"
|
||||
></error-page>
|
||||
<error-page
|
||||
if="{ state.pageError && Array.isArray(state.pageError.errors) }"
|
||||
each="{ error in (state.pageError && state.pageError.errors) }"
|
||||
code="{ error.code }"
|
||||
detail="{ error.detail }"
|
||||
message="{ error.message }"
|
||||
url="{ state.pageError.url }"
|
||||
></error-page>
|
||||
<router base="#!">
|
||||
<route path="{baseRoute}">
|
||||
<catalog
|
||||
|
@ -42,6 +57,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
on-authentication="{ onAuthentication }"
|
||||
show-catalog-nb-tags="{ truthy(props.showCatalogNbTags) }"
|
||||
catalog-default-expanded="{ truthy(props.catalogDefaultExpanded) }"
|
||||
catalog-min-branches="{ props.catalogMinBranches }"
|
||||
catalog-max-branches="{ props.catalogMaxBranches }"
|
||||
></catalog>
|
||||
</route>
|
||||
<route path="{baseRoute}taglist/(.*)">
|
||||
|
@ -82,21 +99,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
on-authenticated="{ state.onAuthenticated }"
|
||||
opened="{ state.authenticationDialogOpened }"
|
||||
></registry-authentication>
|
||||
<error-page
|
||||
if="{ state.pageError && !Array.isArray(state.pageError.errors) }"
|
||||
code="{ state.pageError.code }"
|
||||
status="{ state.pageError.status }"
|
||||
message="{ state.pageError.message }"
|
||||
url="{ state.pageError.url }"
|
||||
></error-page>
|
||||
<error-page
|
||||
if="{ state.pageError && Array.isArray(state.pageError.errors) }"
|
||||
each="{ error in (state.pageError && state.pageError.errors) }"
|
||||
code="{ error.code }"
|
||||
detail="{ error.detail }"
|
||||
message="{ error.message }"
|
||||
url="{ state.pageError.url }"
|
||||
></error-page>
|
||||
<material-snackbar message="{ state.snackbarMessage }" is-error="{ state.snackbarIsError }"></material-snackbar>
|
||||
</main>
|
||||
<footer>
|
||||
|
|
|
@ -61,6 +61,10 @@
|
|||
<a href="https://github.com/Joxit/docker-registry-ui/issues/306">Joxit/docker-registry-ui#306</a>.
|
||||
</p>
|
||||
</template>
|
||||
<template if="{ props.code === 'CATALOG_BRANCHING_CONFIGURATION' }">
|
||||
<p>Wrong configuration for the branching feature: { props.message }</p>
|
||||
<p>Configuration environment variables are : CATALOG_MIN_BRANCH and CATALOG_MAX_BRANCH</p>
|
||||
</template>
|
||||
</div>
|
||||
<script>
|
||||
export default {
|
||||
|
|
|
@ -159,7 +159,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
return router.taglist(this.props.image);
|
||||
},
|
||||
showDockerfile() {
|
||||
console.log(this);
|
||||
this.update({ showDockerfile: true });
|
||||
},
|
||||
onDockerfileClose() {
|
||||
|
|
|
@ -49,6 +49,8 @@
|
|||
use-control-cache-header="${USE_CONTROL_CACHE_HEADER}"
|
||||
taglist-order="${TAGLIST_ORDER}"
|
||||
catalog-default-expanded="${CATALOG_DEFAULT_EXPANDED}"
|
||||
catalog-min-branches="${CATALOG_MIN_BRANCHES}"
|
||||
catalog-max-branches="${CATALOG_MAX_BRANCHES}"
|
||||
theme="${THEME}"
|
||||
theme-primary-text="${THEME_PRIMARY_TEXT}"
|
||||
theme-neutral-text="${THEME_NEUTRAL_TEXT}"
|
||||
|
@ -77,6 +79,8 @@
|
|||
use-control-cache-header="false"
|
||||
taglist-order=""
|
||||
catalog-default-expanded=""
|
||||
catalog-min-branches="1"
|
||||
catalog-max-branches="1"
|
||||
theme="auto"
|
||||
theme-primary-text=""
|
||||
theme-neutral-text=""
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
export class DockerRegistryUIError extends Error {
|
||||
constructor(msg) {
|
||||
constructor(msg, code) {
|
||||
super(msg);
|
||||
this.isError = true;
|
||||
this.code = code;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { DockerRegistryUIError } from './error.js';
|
||||
const ERROR_CODE = 'CATALOG_BRANCHING_CONFIGURATION';
|
||||
|
||||
const getRepositoryName = (split, max) => {
|
||||
let repositoryName = '';
|
||||
|
@ -29,14 +30,24 @@ const getLatestRepository = (repo, repoName) => {
|
|||
}
|
||||
};
|
||||
|
||||
const cleanInt = (n) => (n === '' ? 1 : parseInt(n));
|
||||
|
||||
export const getBranching = (min = 1, max = 1) => {
|
||||
if (min > max) {
|
||||
throw new DockerRegistryUIError(`min must be inferior to max (min: ${min} <= max: ${max})`);
|
||||
min = cleanInt(min);
|
||||
max = cleanInt(max);
|
||||
if (isNaN(min) || isNaN(max)) {
|
||||
throw new DockerRegistryUIError(`min and max must be integers: (min: ${min} and max: ${max}))`, ERROR_CODE);
|
||||
} else if (min > max) {
|
||||
throw new DockerRegistryUIError(`min must be inferior to max (min: ${min} <= max: ${max})`, ERROR_CODE);
|
||||
} else if (max < 0 || min < 0) {
|
||||
throw new DockerRegistryUIError(
|
||||
`min and max must be greater than equals to 0 (min: ${min} >= 0 and max: ${max} >= 0)`
|
||||
`min and max must be greater than equals to 0 (min: ${min} >= 0 and max: ${max} >= 0)`,
|
||||
ERROR_CODE
|
||||
);
|
||||
}
|
||||
if (max == 1) {
|
||||
min = 1;
|
||||
}
|
||||
return (repositories) =>
|
||||
repositories.sort().reduce(function (acc, image) {
|
||||
const split = image.split('/');
|
||||
|
|
|
@ -69,17 +69,18 @@ material-card {
|
|||
material-card,
|
||||
material-tabs,
|
||||
pagination .container {
|
||||
max-width: 95%;
|
||||
margin: auto;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
/* 1515px * 0.95 = 1440px */
|
||||
@media screen and (min-width: 1515px) {
|
||||
material-card,
|
||||
material-tabs,
|
||||
pagination .container {
|
||||
material-card,
|
||||
material-tabs,
|
||||
pagination .container,
|
||||
catalog {
|
||||
max-width: 95%;
|
||||
/* 1515px * 0.95 = 1440px */
|
||||
@media screen and (min-width: 1515px) {
|
||||
max-width: 1440px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,5 +117,6 @@ describe('repositories', () => {
|
|||
assert.throws(() => getBranching(2, 1), DockerRegistryUIError, `Did not throw on min > max`);
|
||||
assert.throws(() => getBranching(-2, 1), DockerRegistryUIError, `Did not throw on min < 0`);
|
||||
assert.throws(() => getBranching(2, -1), DockerRegistryUIError, `Did not throw on max < 0`);
|
||||
assert.throws(() => getBranching('foo', 'bar'), DockerRegistryUIError, `Did not throw on max < 0`);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue