Commit 3efae6f3 authored by Zack Cuddy's avatar Zack Cuddy

Geo Package Files - Initialize

This splits off from:
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/32872

This is an attempt at MVC to avoid a
massive MR.

This commit implements the files required
to hook up the Route, View, and Controller.

There will be future commits/MRs to implement the rest of the above
listed MR.

The navigational elements to get here are hidden behind
the FF :geo_self_service_framework
parent 34b6fe75
<script>
import { mapState } from 'vuex';
import { mapGetters } from 'vuex';
import { GlEmptyState } from '@gitlab/ui';
import { s__, sprintf } from '~/locale';
......@@ -19,7 +19,7 @@ export default {
},
},
computed: {
...mapState(['replicableType']),
...mapGetters(['replicableTypeName']),
linkText() {
return sprintf(
s__(
......@@ -38,7 +38,7 @@ export default {
<template>
<gl-empty-state
:title="sprintf(__('There are no %{replicableType} to show'), { replicableType })"
:title="sprintf(__('There are no %{replicableTypeName} to show'), { replicableTypeName })"
:svg-path="geoReplicableEmptySvgPath"
>
<template #description>
......
<script>
import { mapActions, mapState } from 'vuex';
import { mapActions, mapState, mapGetters } from 'vuex';
import { debounce } from 'lodash';
import { GlSearchBoxByType, GlDropdown, GlDropdownItem, GlButton } from '@gitlab/ui';
import { __, sprintf } from '~/locale';
import { DEFAULT_SEARCH_DELAY, ACTION_TYPES } from '../store/constants';
import { DEFAULT_SEARCH_DELAY, ACTION_TYPES, FILTER_STATES } from '../store/constants';
export default {
name: 'GeoReplicableFilterBar',
......@@ -14,7 +14,8 @@ export default {
GlButton,
},
computed: {
...mapState(['currentFilterIndex', 'filterOptions', 'searchFilter', 'replicableType']),
...mapState(['currentFilterIndex', 'filterOptions', 'searchFilter']),
...mapGetters(['replicableTypeName']),
search: {
get() {
return this.searchFilter;
......@@ -25,7 +26,9 @@ export default {
}, DEFAULT_SEARCH_DELAY),
},
resyncText() {
return sprintf(__('Resync all %{replicableType}'), { replicableType: this.replicableType });
return sprintf(__('Resync all %{replicableType}'), {
replicableType: this.replicableTypeName,
});
},
},
methods: {
......@@ -36,6 +39,7 @@ export default {
},
},
actionTypes: ACTION_TYPES,
filterStates: FILTER_STATES,
};
</script>
......@@ -51,10 +55,10 @@ export default {
:class="{ 'bg-secondary-100': index === currentFilterIndex }"
@click="filterChange(index)"
>
<span
>{{ filter.label }}
<span v-if="filter.label === 'All'">{{ replicableType }}</span></span
<span v-if="filter === $options.filterStates.ALL"
>{{ filter.label }} {{ replicableTypeName }}</span
>
<span v-else>{{ filter.label }}</span>
</gl-dropdown-item>
</gl-dropdown>
<gl-search-box-by-type
......
// eslint-disable-next-line import/prefer-default-export
export const replicableTypeName = state => state.replicableType.split('_').join(' ');
import Vue from 'vue';
import Vuex from 'vuex';
import * as actions from './actions';
import * as getters from './getters';
import mutations from './mutations';
import createState from './state';
......@@ -9,6 +10,7 @@ Vue.use(Vuex);
const createStore = replicableType =>
new Vuex.Store({
actions,
getters,
mutations,
state: createState(replicableType),
});
......
import initGeoReplicable from 'ee/geo_replicable';
if (gon?.features?.geoSelfServiceFramework) {
document.addEventListener('DOMContentLoaded', initGeoReplicable);
}
# frozen_string_literal: true
class Admin::Geo::PackageFilesController < Admin::Geo::ApplicationController
before_action :check_license!
before_action do
push_frontend_feature_flag(:geo_self_service_framework)
end
def index
end
end
= render "admin/geo/shared/replication_nav"
- if Feature.enabled?(:geo_self_service_framework)
#js-geo-replicable{ data: { "geo-replicable-empty-svg-path" => image_path("illustrations/empty-state/geo-replication-empty.svg"),
"geo-troubleshooting-link" => help_page_path("administration/geo/replication/troubleshooting.html"),
"replicable-type" => "package_files",
"graphql" => "true" } }
......@@ -6,16 +6,21 @@
%p
= s_('Geo|Review replication status, and resynchronize and reverify items with the primary node.')
%ul.nav-links.nav.nav-tabs.border-top.border-bottom.border-secondary-100
= nav_link(path: 'admin/geo/projects#index', html_options: { class: 'pr-2' }) do
= nav_link(path: 'admin/geo/projects#index', html_options: { class: 'gl-pr-2' }) do
= link_to admin_geo_projects_path, title: _('Projects') do
%span
= _('Projects')
= nav_link(path: 'admin/geo/uploads#index', html_options: { class: 'pr-2' }) do
= nav_link(path: 'admin/geo/uploads#index', html_options: { class: 'gl-pr-2' }) do
= link_to admin_geo_uploads_path, title: _('Uploads') do
%span
= _('Uploads')
= nav_link(path: 'admin/geo/designs#index', html_options: { class: 'pr-2' }) do
= nav_link(path: 'admin/geo/designs#index', html_options: { class: 'gl-pr-2' }) do
= link_to admin_geo_designs_path, title: _('Designs') do
%span
= _('Designs')
- if Feature.enabled?(:geo_self_service_framework)
= nav_link(path: 'admin/geo/package_files#index', html_options: { class: 'gl-pr-2' }) do
= link_to admin_geo_package_files_path, title: _('Package Files') do
%span
= _('Package Files')
= nav_link(controller: %w(admin/geo/nodes admin/geo/projects admin/geo/uploads admin/geo/settings admin/geo/designs)) do
= nav_link(controller: %w(admin/geo/nodes admin/geo/projects admin/geo/uploads admin/geo/settings admin/geo/designs admin/geo/package_files)) do
= link_to admin_geo_nodes_path, class: "qa-link-geo-menu" do
.nav-icon-container
= sprite_icon('location-dot')
......@@ -14,7 +14,7 @@
%span
= _('Nodes')
- if Gitlab::Geo.secondary?
= nav_link(controller: %w(admin/geo/projects admin/geo/uploads admin/geo/designs)) do
= nav_link(controller: %w(admin/geo/projects admin/geo/uploads admin/geo/designs admin/geo/package_files)) do
= link_to admin_geo_projects_path, title: _('Replication') do
%span
= _('Replication')
......
......@@ -60,6 +60,7 @@ namespace :admin do
end
resources :designs, only: [:index]
resources :package_files, only: [:index]
resources :uploads, only: [:index, :destroy]
end
......
......@@ -43,4 +43,23 @@ describe 'admin Geo Replication Nav', :js, :geo do
let(:path) { admin_geo_designs_path }
end
end
describe 'visit admin/geo/replication/package_files' do
it_behaves_like 'active sidebar link', 'Package Files' do
let(:path) { admin_geo_package_files_path }
end
context 'when geo_self_service_framework feature is disabled' do
before do
stub_feature_flags(geo_self_service_framework: false)
visit admin_geo_projects_path
wait_for_requests
end
it 'does not render navigational element' do
expect(page).not_to have_selector("a[title=\"Package Files\"]")
end
end
end
end
......@@ -63,5 +63,11 @@ describe 'admin Geo Sidebar', :js, :geo do
let(:path) { admin_geo_uploads_path }
end
end
describe 'visiting geo package files' do
it_behaves_like 'active sidebar link', 'Replication' do
let(:path) { admin_geo_package_files_path }
end
end
end
end
import Vuex from 'vuex';
import { createLocalVue, shallowMount } from '@vue/test-utils';
import { GlEmptyState } from '@gitlab/ui';
import store from 'ee/geo_replicable/store';
import createStore from 'ee/geo_replicable/store';
import GeoReplicableEmptyState from 'ee/geo_replicable/components/geo_replicable_empty_state.vue';
import { MOCK_GEO_REPLICATION_SVG_PATH, MOCK_GEO_TROUBLESHOOTING_LINK } from '../mock_data';
import {
MOCK_GEO_REPLICATION_SVG_PATH,
MOCK_GEO_TROUBLESHOOTING_LINK,
MOCK_REPLICABLE_TYPE,
} from '../mock_data';
const localVue = createLocalVue();
localVue.use(Vuex);
......@@ -19,7 +23,7 @@ describe('GeoReplicableEmptyState', () => {
const createComponent = () => {
wrapper = shallowMount(GeoReplicableEmptyState, {
localVue,
store,
store: createStore(MOCK_REPLICABLE_TYPE),
propsData,
});
};
......
......@@ -2,8 +2,9 @@ import Vuex from 'vuex';
import { createLocalVue, mount } from '@vue/test-utils';
import { GlDropdown, GlDropdownItem, GlSearchBoxByType, GlButton } from '@gitlab/ui';
import GeoReplicableFilterBar from 'ee/geo_replicable/components/geo_replicable_filter_bar.vue';
import store from 'ee/geo_replicable/store';
import createStore from 'ee/geo_replicable/store';
import { DEFAULT_SEARCH_DELAY } from 'ee/geo_replicable/store/constants';
import { MOCK_REPLICABLE_TYPE } from '../mock_data';
const localVue = createLocalVue();
localVue.use(Vuex);
......@@ -21,7 +22,7 @@ describe('GeoReplicableFilterBar', () => {
const createComponent = () => {
wrapper = mount(GeoReplicableFilterBar, {
localVue,
store,
store: createStore(MOCK_REPLICABLE_TYPE),
methods: {
...actionSpies,
},
......@@ -54,7 +55,15 @@ describe('GeoReplicableFilterBar', () => {
describe('Filter options', () => {
it('renders a dropdown item for each filterOption', () => {
expect(findDropdownItemsText()).toStrictEqual(wrapper.vm.filterOptions.map(n => n.label));
expect(findDropdownItemsText()).toStrictEqual(
wrapper.vm.filterOptions.map(n => {
if (n.label === 'All') {
return `${n.label} ${MOCK_REPLICABLE_TYPE}`;
}
return n.label;
}),
);
});
it('clicking a dropdown item calls setFilter with its index', () => {
......
import * as getters from 'ee/geo_replicable/store/getters';
import createState from 'ee/geo_replicable/store/state';
describe('GeoReplicable Store Getters', () => {
let state;
beforeEach(() => {
state = createState();
});
describe('replicableTypeName', () => {
it('handles a single word replicable type', () => {
state.replicableType = 'designs';
expect(getters.replicableTypeName(state)).toBe('designs');
});
it('handles a multi-word replicable type', () => {
state.replicableType = 'package_files';
expect(getters.replicableTypeName(state)).toBe('package files');
});
});
});
......@@ -44,6 +44,12 @@ describe 'EE-specific admin routing' do
end
end
describe Admin::Geo::PackageFilesController, 'routing' do
it 'routes / to #index' do
expect(get('/admin/geo/replication/package_files')).to route_to('admin/geo/package_files#index')
end
end
describe Admin::Geo::NodesController, 'routing' do
let(:geo_node) { create(:geo_node) }
......
......@@ -15332,6 +15332,9 @@ msgstr ""
msgid "Owner"
msgstr ""
msgid "Package Files"
msgstr ""
msgid "Package Registry"
msgstr ""
......@@ -22077,7 +22080,7 @@ msgstr ""
msgid "The vulnerability is no longer detected. Verify the vulnerability has been remediated before changing its status."
msgstr ""
msgid "There are no %{replicableType} to show"
msgid "There are no %{replicableTypeName} to show"
msgstr ""
msgid "There are no GPG keys associated with this account."
......
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