Commit f9b63e9a authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch '15398-bootstrap-registry-settings-app' into 'master'

App for Container Registry Retention & Expiration policies

See merge request gitlab-org/gitlab!20859
parents 14576c8e 63b2dbca
import initSettingsPanels from '~/settings_panels'; import initSettingsPanels from '~/settings_panels';
import SecretValues from '~/behaviors/secret_values'; import SecretValues from '~/behaviors/secret_values';
import AjaxVariableList from '~/ci_variable_list/ajax_variable_list'; import AjaxVariableList from '~/ci_variable_list/ajax_variable_list';
import registrySettingsApp from '~/registry/settings/registry_settings_bundle';
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
// Initialize expandable settings panels // Initialize expandable settings panels
...@@ -32,4 +33,6 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -32,4 +33,6 @@ document.addEventListener('DOMContentLoaded', () => {
if (instanceDefaultBadge) instanceDefaultBadge.style.display = 'none'; if (instanceDefaultBadge) instanceDefaultBadge.style.display = 'none';
autoDevOpsExtraSettings.classList.toggle('hidden', !target.checked); autoDevOpsExtraSettings.classList.toggle('hidden', !target.checked);
}); });
registrySettingsApp();
}); });
<script>
import { mapState } from 'vuex';
import { s__, sprintf } from '~/locale';
export default {
components: {},
computed: {
...mapState({
helpPagePath: 'helpPagePath',
}),
helpText() {
return sprintf(
s__(
'PackageRegistry|Read more about the %{helpLinkStart}Container Registry tag retention policies%{helpLinkEnd}',
),
{
helpLinkStart: `<a href="${this.helpPagePath}" target="_blank">`,
helpLinkEnd: '</a>',
},
false,
);
},
},
};
</script>
<template>
<div>
<p>
{{ s__('PackageRegistry|Tag retention policies are designed to:') }}
</p>
<ul>
<li>{{ s__('PackageRegistry|Keep and protect the images that matter most.') }}</li>
<li>
{{
s__("PackageRegistry|Automatically remove extra images that aren't designed to be kept.")
}}
</li>
</ul>
<p ref="help-link" v-html="helpText"></p>
</div>
</template>
import Vue from 'vue';
import Translate from '~/vue_shared/translate';
import store from './stores/';
import RegistrySettingsApp from './components/registry_settings_app.vue';
Vue.use(Translate);
export default () => {
const el = document.getElementById('js-registry-settings');
if (!el) {
return null;
}
store.dispatch('setInitialState', el.dataset);
return new Vue({
el,
store,
components: {
RegistrySettingsApp,
},
render(createElement) {
return createElement('registry-settings-app', {});
},
});
};
import * as types from './mutation_types';
export const setInitialState = ({ commit }, data) => commit(types.SET_INITIAL_STATE, data);
// to avoid eslint error until more actions are added to the store
export default () => {};
import Vue from 'vue';
import Vuex from 'vuex';
import * as actions from './actions';
import mutations from './mutations';
import state from './state';
Vue.use(Vuex);
export const createStore = () =>
new Vuex.Store({
state,
actions,
mutations,
});
export default createStore();
export const SET_INITIAL_STATE = 'SET_INITIAL_STATE';
// to avoid eslint error until more actions are added to the store
export default () => {};
import * as types from './mutation_types';
export default {
[types.SET_INITIAL_STATE](state, initialState) {
state.helpPagePath = initialState.helpPagePath;
state.registrySettingsEndpoint = initialState.registrySettingsEndpoint;
},
};
export default () => ({
/*
* Help page path to generate the link
*/
helpPagePath: '',
/*
* Settings endpoint to call to fetch and update the settings
*/
registrySettingsEndpoint: '',
});
#js-registry-settings{ data: { registry_settings_endpoint: '',
help_page_path: help_page_path('user/project/operations/linking_to_an_external_dashboard') } }
...@@ -59,3 +59,14 @@ ...@@ -59,3 +59,14 @@
.settings-content .settings-content
= render 'projects/triggers/index' = render 'projects/triggers/index'
- if Feature.enabled?(:registry_retention_policies_settings, @project)
%section.settings.no-animate#js-registry-polcies{ class: ('expanded' if expanded) }
.settings-header
%h4
= _("Container Registry tag expiration policies")
%button.btn.js-settings-toggle{ type: 'button' }
= expanded ? _('Collapse') : _('Expand')
%p
= _("Expiration policies for the Container Registry are a perfect solution for keeping the Registry space down while still enjoying the full power of GitLab CI/CD.")
.settings-content
= render 'projects/registry/settings/index'
...@@ -4615,6 +4615,9 @@ msgstr "" ...@@ -4615,6 +4615,9 @@ msgstr ""
msgid "Container Registry" msgid "Container Registry"
msgstr "" msgstr ""
msgid "Container Registry tag expiration policies"
msgstr ""
msgid "Container Scanning" msgid "Container Scanning"
msgstr "" msgstr ""
...@@ -7092,6 +7095,9 @@ msgstr "" ...@@ -7092,6 +7095,9 @@ msgstr ""
msgid "Expiration date" msgid "Expiration date"
msgstr "" msgstr ""
msgid "Expiration policies for the Container Registry are a perfect solution for keeping the Registry space down while still enjoying the full power of GitLab CI/CD."
msgstr ""
msgid "Expired" msgid "Expired"
msgstr "" msgstr ""
...@@ -12141,6 +12147,9 @@ msgstr "" ...@@ -12141,6 +12147,9 @@ msgstr ""
msgid "Package was removed" msgid "Package was removed"
msgstr "" msgstr ""
msgid "PackageRegistry|Automatically remove extra images that aren't designed to be kept."
msgstr ""
msgid "PackageRegistry|Copy Maven XML" msgid "PackageRegistry|Copy Maven XML"
msgstr "" msgstr ""
...@@ -12180,6 +12189,9 @@ msgstr "" ...@@ -12180,6 +12189,9 @@ msgstr ""
msgid "PackageRegistry|Installation" msgid "PackageRegistry|Installation"
msgstr "" msgstr ""
msgid "PackageRegistry|Keep and protect the images that matter most."
msgstr ""
msgid "PackageRegistry|Learn how to %{noPackagesLinkStart}publish and share your packages%{noPackagesLinkEnd} with GitLab." msgid "PackageRegistry|Learn how to %{noPackagesLinkStart}publish and share your packages%{noPackagesLinkEnd} with GitLab."
msgstr "" msgstr ""
...@@ -12192,12 +12204,18 @@ msgstr "" ...@@ -12192,12 +12204,18 @@ msgstr ""
msgid "PackageRegistry|Package installation" msgid "PackageRegistry|Package installation"
msgstr "" msgstr ""
msgid "PackageRegistry|Read more about the %{helpLinkStart}Container Registry tag retention policies%{helpLinkEnd}"
msgstr ""
msgid "PackageRegistry|Registry Setup" msgid "PackageRegistry|Registry Setup"
msgstr "" msgstr ""
msgid "PackageRegistry|Remove package" msgid "PackageRegistry|Remove package"
msgstr "" msgstr ""
msgid "PackageRegistry|Tag retention policies are designed to:"
msgstr ""
msgid "PackageRegistry|There are no packages yet" msgid "PackageRegistry|There are no packages yet"
msgstr "" msgstr ""
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Registry List renders 1`] = `
<div>
<p>
Tag retention policies are designed to:
</p>
<ul>
<li>
Keep and protect the images that matter most.
</li>
<li>
Automatically remove extra images that aren't designed to be kept.
</li>
</ul>
<p>
Read more about the
<a
href="foo"
target="_blank"
>
Container Registry tag retention policies
</a>
</p>
</div>
`;
import Vuex from 'vuex';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import component from '~/registry/settings/components/registry_settings_app.vue';
import { createStore } from '~/registry/settings/stores/';
const localVue = createLocalVue();
localVue.use(Vuex);
describe('Registry List', () => {
let wrapper;
let store;
const helpPagePath = 'foo';
const findHelpLink = () => wrapper.find({ ref: 'help-link' }).find('a');
const mountComponent = (options = {}) =>
shallowMount(component, {
sync: false,
store,
...options,
});
beforeEach(() => {
store = createStore();
store.dispatch('setInitialState', { helpPagePath });
wrapper = mountComponent();
});
afterEach(() => {
wrapper.destroy();
});
it('renders', () => {
expect(wrapper.element).toMatchSnapshot();
});
it('renders an help link dependant on the helphPagePath', () => {
expect(findHelpLink().attributes('href')).toBe(helpPagePath);
});
});
import * as actions from '~/registry/settings/stores/actions';
import * as types from '~/registry/settings/stores/mutation_types';
import testAction from 'helpers/vuex_action_helper';
jest.mock('~/flash.js');
describe('Actions Registry Store', () => {
describe('setInitialState', () => {
it('should set the initial state', done => {
testAction(
actions.setInitialState,
'foo',
{},
[{ type: types.SET_INITIAL_STATE, payload: 'foo' }],
[],
done,
);
});
});
});
import mutations from '~/registry/settings/stores/mutations';
import * as types from '~/registry/settings/stores/mutation_types';
import createState from '~/registry/settings/stores/state';
describe('Mutations Registry Store', () => {
let mockState;
beforeEach(() => {
mockState = createState();
});
describe('SET_INITIAL_STATE', () => {
it('should set the initial state', () => {
const payload = { helpPagePath: 'foo', registrySettingsEndpoint: 'bar' };
const expectedState = { ...mockState, ...payload };
mutations[types.SET_INITIAL_STATE](mockState, payload);
expect(mockState.endpoint).toEqual(expectedState.endpoint);
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment