Commit 63b2dbca authored by Nicolò Maria Mezzopera's avatar Nicolò Maria Mezzopera Committed by Natalia Tepluhina

Add vuex store for registry settings

- actions
- mutations

Add vue app for registry settings and load it

 - app
- bundle file
- load bundle in index
Add tests for vue and vuex registry settings

- main app
- actions
- mutations

Add partial to load vue app

Add new section to CI/CD settings

- add feature flag
- add header as haml
- load partial for vue app

Update translations strings

Add helper and vuex to test file

Apply suggestion to registry_settings_app_spec.js

Apply suggestion to ci_cd/show.html.haml
Apply suggestion to registry_settings_app.vue
Update snapshot with new copy
parent 14576c8e
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