feat(branching): add configuration for catalog arborescence

This commit is contained in:
Joxit 2023-05-30 07:49:18 +02:00
parent 398fa65fa1
commit 1031034bc4
No known key found for this signature in database
GPG Key ID: F526592B8E012263
11 changed files with 80 additions and 43 deletions

View File

@ -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

View File

@ -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;

View File

@ -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>

View File

@ -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>

View File

@ -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 {

View File

@ -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() {

View File

@ -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=""

View File

@ -1,6 +1,7 @@
export class DockerRegistryUIError extends Error {
constructor(msg) {
constructor(msg, code) {
super(msg);
this.isError = true;
this.code = code;
}
}

View File

@ -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('/');

View File

@ -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;
}
}

View File

@ -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`);
});
});