Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
6cc1ef3307
commit
5a856c7946
|
|
@ -1,32 +0,0 @@
|
|||
import Vue from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import createDefaultClient from '~/lib/graphql';
|
||||
import ProjectStorageApp from './components/project_storage_app.vue';
|
||||
|
||||
Vue.use(VueApollo);
|
||||
|
||||
export default (containerId = 'js-project-storage-count-app') => {
|
||||
const el = document.getElementById(containerId);
|
||||
|
||||
if (!el) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const { projectPath } = el.dataset;
|
||||
|
||||
const apolloProvider = new VueApollo({
|
||||
defaultClient: createDefaultClient(),
|
||||
});
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
apolloProvider,
|
||||
name: 'ProjectStorageApp',
|
||||
provide: {
|
||||
projectPath,
|
||||
},
|
||||
render(createElement) {
|
||||
return createElement(ProjectStorageApp);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
@ -4,7 +4,7 @@ import getProjectStorageStatisticsQuery from 'ee_else_ce/usage_quotas/storage/qu
|
|||
import ProjectStorageApp from './project_storage_app.vue';
|
||||
|
||||
const meta = {
|
||||
title: 'usage_quotas/storage/project_storage_app',
|
||||
title: 'usage_quotas/storage/project/project_storage_app',
|
||||
component: ProjectStorageApp,
|
||||
};
|
||||
|
||||
|
|
@ -20,7 +20,7 @@ import {
|
|||
NAMESPACE_STORAGE_TYPES,
|
||||
usageQuotasHelpPaths,
|
||||
storageTypeHelpPaths,
|
||||
} from '../constants';
|
||||
} from '../../constants';
|
||||
import { getStorageTypesFromProjectStatistics, descendingStorageUsageSort } from '../utils';
|
||||
import ProjectStorageDetail from './project_storage_detail.vue';
|
||||
|
||||
|
|
@ -7,7 +7,7 @@ import {
|
|||
HELP_LINK_ARIA_LABEL,
|
||||
PROJECT_TABLE_LABEL_STORAGE_TYPE,
|
||||
PROJECT_TABLE_LABEL_USAGE,
|
||||
} from '../constants';
|
||||
} from '../../constants';
|
||||
import StorageTypeIcon from './storage_type_icon.vue';
|
||||
|
||||
export default {
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
* Populates an array of storage types with usage value and other details
|
||||
*
|
||||
* @param {Array} selectedStorageTypes selected storage types that will be populated
|
||||
* @param {Object} projectStatistics object of storage values, with storage type as keys
|
||||
* @param {Object} statisticsDetailsPaths object of storage detail paths, with storage type as keys
|
||||
* @param {Object} helpLinks object of help paths, with storage type as keys
|
||||
* @returns {Array}
|
||||
*/
|
||||
export const getStorageTypesFromProjectStatistics = (
|
||||
selectedStorageTypes,
|
||||
projectStatistics,
|
||||
statisticsDetailsPaths = {},
|
||||
helpLinks = {},
|
||||
) =>
|
||||
selectedStorageTypes.reduce((types, currentType) => {
|
||||
const helpPath = helpLinks[currentType.id];
|
||||
const value = projectStatistics[`${currentType.id}Size`];
|
||||
const detailsPath = statisticsDetailsPaths[currentType.id];
|
||||
|
||||
return types.concat({
|
||||
...currentType,
|
||||
helpPath,
|
||||
detailsPath,
|
||||
value,
|
||||
});
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Creates a sorting function to sort storage types by usage in the graph and in the table
|
||||
*
|
||||
* @param {string} storageUsageKey key storing value of storage usage
|
||||
* @returns {Function} sorting function
|
||||
*/
|
||||
export function descendingStorageUsageSort(storageUsageKey) {
|
||||
return (a, b) => b[storageUsageKey] - a[storageUsageKey];
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@ import {
|
|||
STORAGE_TAB_METADATA_EL_SELECTOR,
|
||||
} from '../constants';
|
||||
import NamespaceStorageApp from './components/namespace_storage_app.vue';
|
||||
import ProjectStorageApp from './components/project_storage_app.vue';
|
||||
import ProjectStorageApp from './project/components/project_storage_app.vue';
|
||||
|
||||
const parseProjectProvideData = (el) => {
|
||||
const { projectPath } = el.dataset;
|
||||
|
|
|
|||
|
|
@ -3,44 +3,6 @@ import { numberToHumanSize } from '~/lib/utils/number_utils';
|
|||
import { __ } from '~/locale';
|
||||
import { storageTypeHelpPaths } from './constants';
|
||||
|
||||
/**
|
||||
* Populates an array of storage types with usage value and other details
|
||||
*
|
||||
* @param {Array} selectedStorageTypes selected storage types that will be populated
|
||||
* @param {Object} projectStatistics object of storage values, with storage type as keys
|
||||
* @param {Object} statisticsDetailsPaths object of storage detail paths, with storage type as keys
|
||||
* @param {Object} helpLinks object of help paths, with storage type as keys
|
||||
* @returns {Array}
|
||||
*/
|
||||
export const getStorageTypesFromProjectStatistics = (
|
||||
selectedStorageTypes,
|
||||
projectStatistics,
|
||||
statisticsDetailsPaths = {},
|
||||
helpLinks = {},
|
||||
) =>
|
||||
selectedStorageTypes.reduce((types, currentType) => {
|
||||
const helpPath = helpLinks[currentType.id];
|
||||
const value = projectStatistics[`${currentType.id}Size`];
|
||||
const detailsPath = statisticsDetailsPaths[currentType.id];
|
||||
|
||||
return types.concat({
|
||||
...currentType,
|
||||
helpPath,
|
||||
detailsPath,
|
||||
value,
|
||||
});
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Creates a sorting function to sort storage types by usage in the graph and in the table
|
||||
*
|
||||
* @param {string} storageUsageKey key storing value of storage usage
|
||||
* @returns {Function} sorting function
|
||||
*/
|
||||
export function descendingStorageUsageSort(storageUsageKey) {
|
||||
return (a, b) => b[storageUsageKey] - a[storageUsageKey];
|
||||
}
|
||||
|
||||
/**
|
||||
* This method parses the results from `getNamespaceStorageStatistics`
|
||||
* call.
|
||||
|
|
|
|||
|
|
@ -26,19 +26,23 @@ class BaseActionController < ActionController::Base
|
|||
next if p.directives.blank?
|
||||
|
||||
if helpers.vite_enabled?
|
||||
vite_port = ViteRuby.instance.config.port
|
||||
vite_origin = "#{Gitlab.config.gitlab.host}:#{vite_port}"
|
||||
http_origin = "http://#{vite_origin}"
|
||||
ws_origin = "ws://#{vite_origin}"
|
||||
wss_origin = "wss://#{vite_origin}"
|
||||
gitlab_ws_origin = Gitlab::Utils.append_path(Gitlab.config.gitlab.url, 'vite-dev/')
|
||||
http_path = Gitlab::Utils.append_path(http_origin, 'vite-dev/')
|
||||
# Normally all Vite requests are proxied via Vite Ruby's middleware (example:
|
||||
# https://gdk.test:3000/vite-dev/@fs/path/to/your/gdk), unless the
|
||||
# skipProxy parameter is used (https://vite-ruby.netlify.app/config/#skipproxy-experimental).
|
||||
#
|
||||
# However, HMR requests go directly to another host, and we need to allow that.
|
||||
# We need both Websocket and HTTP URLs because Vite will attempt to ping
|
||||
# the HTTP URL if the Websocket isn't available:
|
||||
# https://github.com/vitejs/vite/blob/899d9b1d272b7057aafc6fa01570d40f288a473b/packages/vite/src/client/client.ts#L320-L327
|
||||
hmr_ws_url = Gitlab::Utils.append_path(helpers.vite_hmr_websocket_url, 'vite-dev/')
|
||||
hmr_http_url = Gitlab::Utils.append_path(helpers.vite_hmr_http_url, 'vite-dev/')
|
||||
http_path = Gitlab::Utils.append_path(Gitlab.config.gitlab.url, 'vite-dev/')
|
||||
|
||||
connect_sources = p.directives['connect-src']
|
||||
p.connect_src(*(Array.wrap(connect_sources) | [ws_origin, wss_origin, http_path]))
|
||||
p.connect_src(*(Array.wrap(connect_sources) | [hmr_ws_url, hmr_http_url]))
|
||||
|
||||
worker_sources = p.directives['worker-src']
|
||||
p.worker_src(*(Array.wrap(worker_sources) | [gitlab_ws_origin, http_path]))
|
||||
p.worker_src(*(Array.wrap(worker_sources) | [hmr_ws_url, hmr_http_url, http_path]))
|
||||
end
|
||||
|
||||
next unless Gitlab::CurrentSettings.snowplow_enabled? && !Gitlab::CurrentSettings.snowplow_collector_hostname.blank?
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ module Groups
|
|||
button_testid: 'remove-group-button',
|
||||
disabled: group.prevent_delete?.to_s,
|
||||
confirm_danger_message: remove_group_message(group),
|
||||
phrase: group.full_path
|
||||
phrase: group.full_path,
|
||||
html_confirmation_message: 'true'
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -86,8 +86,42 @@ module GroupsHelper
|
|||
|
||||
# Overridden in EE
|
||||
def remove_group_message(group)
|
||||
_("You are going to remove %{group_name}. This will also delete all of its subgroups and projects. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?") %
|
||||
{ group_name: group.name }
|
||||
content_tag :div do
|
||||
content = ''.html_safe
|
||||
content << content_tag(:span, _("You are about to remove the group %{group_name}.") % { group_name: group.name })
|
||||
|
||||
additional_content = additional_removed_items(group)
|
||||
content << additional_content if additional_content.present?
|
||||
|
||||
content << remove_group_warning
|
||||
end
|
||||
end
|
||||
|
||||
def additional_removed_items(group)
|
||||
list_content = ''.html_safe
|
||||
|
||||
list_content << content_tag(:li, pluralize(group.subgroup_count, _('subgroup'))) if group.subgroup_count > 0
|
||||
list_content << content_tag(:li, pluralize(group.all_projects.non_archived.count, _('active project'))) if group.all_projects.non_archived.count > 0
|
||||
list_content << content_tag(:li, pluralize(group.all_projects.archived.count, _('archived project'))) if group.all_projects.archived.count > 0
|
||||
|
||||
if list_content.present?
|
||||
content_tag(:span, _(" This action will also remove:")) +
|
||||
content_tag(:ul) do
|
||||
list_content
|
||||
end
|
||||
else
|
||||
''.html_safe
|
||||
end
|
||||
end
|
||||
|
||||
def remove_group_warning
|
||||
message = _('After you remove a group, you %{strongOpen}cannot%{strongClose} restore it or its components.')
|
||||
content_tag(:p, class: 'gl-mb-0') do
|
||||
ERB::Util.html_escape(message) % {
|
||||
strongOpen: '<strong>'.html_safe,
|
||||
strongClose: '</strong>'.html_safe
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def share_with_group_lock_help_text(group)
|
||||
|
|
|
|||
|
|
@ -7,4 +7,12 @@ module ViteHelper
|
|||
|
||||
Gitlab::Utils.to_boolean(ViteRuby.env['VITE_ENABLED'], default: false)
|
||||
end
|
||||
|
||||
def vite_hmr_websocket_url
|
||||
ViteRuby.env['VITE_HMR_WS_URL']
|
||||
end
|
||||
|
||||
def vite_hmr_http_url
|
||||
ViteRuby.env['VITE_HMR_HTTP_URL']
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -21,7 +21,12 @@ module ViteGdk
|
|||
hmr_host = hmr_config['host'] || host
|
||||
hmr_port = hmr_config['clientPort'] || hmr_config['port'] || port
|
||||
hmr_ws_protocol = hmr_config['protocol'] || 'ws'
|
||||
hmr_http_protocol = hmr_ws_protocol == 'wss' ? 'https' : 'http'
|
||||
ViteRuby.env['VITE_HMR_HOST'] = hmr_host
|
||||
# If the Websocket connection to the HMR host is not up, Vite will attempt to
|
||||
# ping the HMR host via HTTP or HTTPS:
|
||||
# https://github.com/vitejs/vite/blob/899d9b1d272b7057aafc6fa01570d40f288a473b/packages/vite/src/client/client.ts#L320-L327
|
||||
ViteRuby.env['VITE_HMR_HTTP_URL'] = "#{hmr_http_protocol}://#{hmr_host}:#{hmr_port}"
|
||||
ViteRuby.env['VITE_HMR_WS_URL'] = "#{hmr_ws_protocol}://#{hmr_host}:#{hmr_port}"
|
||||
|
||||
ViteRuby.configure(
|
||||
|
|
|
|||
|
|
@ -33,6 +33,9 @@ msgstr ""
|
|||
msgid " Please sign in."
|
||||
msgstr ""
|
||||
|
||||
msgid " This action will also remove:"
|
||||
msgstr ""
|
||||
|
||||
msgid " Try to %{action} this file again."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -4524,6 +4527,9 @@ msgstr ""
|
|||
msgid "After you enable the integration, the following protected variables are created for CI/CD use:"
|
||||
msgstr ""
|
||||
|
||||
msgid "After you remove a group, you %{strongOpen}cannot%{strongClose} restore it or its components."
|
||||
msgstr ""
|
||||
|
||||
msgid "After you've reviewed these contribution guidelines, you'll be all set to"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -57863,6 +57869,9 @@ msgstr ""
|
|||
msgid "You are about to incur additional charges"
|
||||
msgstr ""
|
||||
|
||||
msgid "You are about to remove the group %{group_name}."
|
||||
msgstr ""
|
||||
|
||||
msgid "You are already a member of this %{member_source}."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -57890,9 +57899,6 @@ msgstr ""
|
|||
msgid "You are going to delete %{project_full_name}. Deleted projects CANNOT be restored! Are you ABSOLUTELY sure?"
|
||||
msgstr ""
|
||||
|
||||
msgid "You are going to remove %{group_name}. This will also delete all of its subgroups and projects. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
|
||||
msgstr ""
|
||||
|
||||
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -59053,6 +59059,9 @@ msgstr[1] ""
|
|||
msgid "access:"
|
||||
msgstr ""
|
||||
|
||||
msgid "active project"
|
||||
msgstr ""
|
||||
|
||||
msgid "add at least one file to the repository"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -59121,6 +59130,9 @@ msgid_plural "approvals"
|
|||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "archived project"
|
||||
msgstr ""
|
||||
|
||||
msgid "archived:"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -61046,6 +61058,9 @@ msgstr ""
|
|||
msgid "stuck"
|
||||
msgstr ""
|
||||
|
||||
msgid "subgroup"
|
||||
msgstr ""
|
||||
|
||||
msgid "success"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -5,12 +5,12 @@ import createMockApollo from 'helpers/mock_apollo_helper';
|
|||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { getPreferredLocales } from '~/locale';
|
||||
import ProjectStorageApp from '~/usage_quotas/storage/components/project_storage_app.vue';
|
||||
import ProjectStorageApp from '~/usage_quotas/storage/project/components/project_storage_app.vue';
|
||||
import SectionedPercentageBar from '~/usage_quotas/components/sectioned_percentage_bar.vue';
|
||||
import {
|
||||
descendingStorageUsageSort,
|
||||
getStorageTypesFromProjectStatistics,
|
||||
} from '~/usage_quotas/storage/utils';
|
||||
} from '~/usage_quotas/storage/project/utils';
|
||||
import {
|
||||
storageTypeHelpPaths,
|
||||
PROJECT_STORAGE_TYPES,
|
||||
|
|
@ -24,7 +24,7 @@ import {
|
|||
mockGetProjectStorageStatisticsGraphQLResponse,
|
||||
mockEmptyResponse,
|
||||
defaultProjectProvideValues,
|
||||
} from '../mock_data';
|
||||
} from '../../mock_data';
|
||||
|
||||
Vue.use(VueApollo);
|
||||
|
||||
|
|
@ -34,6 +34,7 @@ jest.mock('~/locale', () => ({
|
|||
}));
|
||||
|
||||
describe('ProjectStorageApp', () => {
|
||||
/** @type {import('helpers/vue_test_utils_helper').ExtendedWrapper} */
|
||||
let wrapper;
|
||||
|
||||
const createMockApolloProvider = ({ reject = false, mockedValue } = {}) => {
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
import { GlTableLite } from '@gitlab/ui';
|
||||
import { mount, Wrapper } from '@vue/test-utils'; // eslint-disable-line no-unused-vars
|
||||
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
|
||||
import ProjectStorageDetail from '~/usage_quotas/storage/components/project_storage_detail.vue';
|
||||
import ProjectStorageDetail from '~/usage_quotas/storage/project/components/project_storage_detail.vue';
|
||||
import { numberToHumanSize } from '~/lib/utils/number_utils';
|
||||
|
||||
describe('ProjectStorageDetail', () => {
|
||||
/** @type { Wrapper } */
|
||||
/** @type {import('helpers/vue_test_utils_helper').ExtendedWrapper} */
|
||||
let wrapper;
|
||||
|
||||
const generateStorageType = (props) => {
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
import { mount } from '@vue/test-utils';
|
||||
import { GlIcon } from '@gitlab/ui';
|
||||
import StorageTypeIcon from '~/usage_quotas/storage/components/storage_type_icon.vue';
|
||||
import StorageTypeIcon from '~/usage_quotas/storage/project/components/storage_type_icon.vue';
|
||||
|
||||
describe('StorageTypeIcon', () => {
|
||||
/** @type {import('@vue/test-utils').Wrapper} */
|
||||
let wrapper;
|
||||
|
||||
const createComponent = (props = {}) => {
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
import { PROJECT_STORAGE_TYPES } from '~/usage_quotas/storage/constants';
|
||||
import {
|
||||
getStorageTypesFromProjectStatistics,
|
||||
descendingStorageUsageSort,
|
||||
} from '~/usage_quotas/storage/project/utils';
|
||||
import { mockGetProjectStorageStatisticsGraphQLResponse } from 'jest/usage_quotas/storage/mock_data';
|
||||
|
||||
describe('getStorageTypesFromProjectStatistics', () => {
|
||||
const {
|
||||
statistics: projectStatistics,
|
||||
statisticsDetailsPaths,
|
||||
} = mockGetProjectStorageStatisticsGraphQLResponse.data.project;
|
||||
|
||||
describe('matches project statistics value with matching storage type', () => {
|
||||
const typesWithStats = getStorageTypesFromProjectStatistics(
|
||||
PROJECT_STORAGE_TYPES,
|
||||
projectStatistics,
|
||||
);
|
||||
|
||||
it.each(PROJECT_STORAGE_TYPES)('storage type: $id', ({ id }) => {
|
||||
expect(typesWithStats).toContainEqual(
|
||||
expect.objectContaining({
|
||||
id,
|
||||
value: projectStatistics[`${id}Size`],
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('adds helpPath to a relevant type', () => {
|
||||
const helpLinks = PROJECT_STORAGE_TYPES.reduce((acc, { id }) => {
|
||||
return {
|
||||
...acc,
|
||||
[id]: `url://${id}`,
|
||||
};
|
||||
}, {});
|
||||
|
||||
const typesWithStats = getStorageTypesFromProjectStatistics(
|
||||
PROJECT_STORAGE_TYPES,
|
||||
projectStatistics,
|
||||
{},
|
||||
helpLinks,
|
||||
);
|
||||
|
||||
typesWithStats.forEach((type) => {
|
||||
expect(type.helpPath).toBe(helpLinks[type.id]);
|
||||
});
|
||||
});
|
||||
|
||||
it('adds details page path', () => {
|
||||
const typesWithStats = getStorageTypesFromProjectStatistics(
|
||||
PROJECT_STORAGE_TYPES,
|
||||
projectStatistics,
|
||||
statisticsDetailsPaths,
|
||||
{},
|
||||
);
|
||||
typesWithStats.forEach((type) => {
|
||||
expect(type.detailsPath).toBe(statisticsDetailsPaths[type.id]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('descendingStorageUsageSort', () => {
|
||||
it('sorts items by a given key in descending order', () => {
|
||||
const items = [{ k: 1 }, { k: 3 }, { k: 2 }];
|
||||
|
||||
const sorted = [...items].sort(descendingStorageUsageSort('k'));
|
||||
|
||||
const expectedSorted = [{ k: 3 }, { k: 2 }, { k: 1 }];
|
||||
expect(sorted).toEqual(expectedSorted);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,79 +1,5 @@
|
|||
import { PROJECT_STORAGE_TYPES } from '~/usage_quotas/storage/constants';
|
||||
import {
|
||||
getStorageTypesFromProjectStatistics,
|
||||
descendingStorageUsageSort,
|
||||
parseGetStorageResults,
|
||||
} from '~/usage_quotas/storage/utils';
|
||||
import {
|
||||
mockGetProjectStorageStatisticsGraphQLResponse,
|
||||
mockGetNamespaceStorageGraphQLResponse,
|
||||
} from 'jest/usage_quotas/storage/mock_data';
|
||||
|
||||
describe('getStorageTypesFromProjectStatistics', () => {
|
||||
const {
|
||||
statistics: projectStatistics,
|
||||
statisticsDetailsPaths,
|
||||
} = mockGetProjectStorageStatisticsGraphQLResponse.data.project;
|
||||
|
||||
describe('matches project statistics value with matching storage type', () => {
|
||||
const typesWithStats = getStorageTypesFromProjectStatistics(
|
||||
PROJECT_STORAGE_TYPES,
|
||||
projectStatistics,
|
||||
);
|
||||
|
||||
it.each(PROJECT_STORAGE_TYPES)('storage type: $id', ({ id }) => {
|
||||
expect(typesWithStats).toContainEqual(
|
||||
expect.objectContaining({
|
||||
id,
|
||||
value: projectStatistics[`${id}Size`],
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('adds helpPath to a relevant type', () => {
|
||||
const helpLinks = PROJECT_STORAGE_TYPES.reduce((acc, { id }) => {
|
||||
return {
|
||||
...acc,
|
||||
[id]: `url://${id}`,
|
||||
};
|
||||
}, {});
|
||||
|
||||
const typesWithStats = getStorageTypesFromProjectStatistics(
|
||||
PROJECT_STORAGE_TYPES,
|
||||
projectStatistics,
|
||||
{},
|
||||
helpLinks,
|
||||
);
|
||||
|
||||
typesWithStats.forEach((type) => {
|
||||
expect(type.helpPath).toBe(helpLinks[type.id]);
|
||||
});
|
||||
});
|
||||
|
||||
it('adds details page path', () => {
|
||||
const typesWithStats = getStorageTypesFromProjectStatistics(
|
||||
PROJECT_STORAGE_TYPES,
|
||||
projectStatistics,
|
||||
statisticsDetailsPaths,
|
||||
{},
|
||||
);
|
||||
typesWithStats.forEach((type) => {
|
||||
expect(type.detailsPath).toBe(statisticsDetailsPaths[type.id]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('descendingStorageUsageSort', () => {
|
||||
it('sorts items by a given key in descending order', () => {
|
||||
const items = [{ k: 1 }, { k: 3 }, { k: 2 }];
|
||||
|
||||
const sorted = [...items].sort(descendingStorageUsageSort('k'));
|
||||
|
||||
const expectedSorted = [{ k: 3 }, { k: 2 }, { k: 1 }];
|
||||
expect(sorted).toEqual(expectedSorted);
|
||||
});
|
||||
});
|
||||
import { parseGetStorageResults } from '~/usage_quotas/storage/utils';
|
||||
import { mockGetNamespaceStorageGraphQLResponse } from 'jest/usage_quotas/storage/mock_data';
|
||||
|
||||
describe('parseGetStorageResults', () => {
|
||||
it('returns the object keys we use', () => {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,8 @@ RSpec.describe Groups::SettingsHelper do
|
|||
remove_form_id: form_value_id,
|
||||
phrase: group.full_path,
|
||||
button_testid: "remove-group-button",
|
||||
disabled: is_button_disabled
|
||||
disabled: is_button_disabled,
|
||||
html_confirmation_message: 'true'
|
||||
})
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ RSpec.describe ViteGdk, feature_category: :tooling do
|
|||
expect(ViteRuby).to receive(:configure).with(host: 'gdk.test', port: 3038)
|
||||
expect(ViteRuby.env).to receive(:[]=).with('VITE_ENABLED', 'true')
|
||||
expect(ViteRuby.env).to receive(:[]=).with('VITE_HMR_HOST', 'gdk.test')
|
||||
expect(ViteRuby.env).to receive(:[]=).with('VITE_HMR_HTTP_URL', 'http://gdk.test:3038')
|
||||
expect(ViteRuby.env).to receive(:[]=).with('VITE_HMR_WS_URL', 'ws://gdk.test:3038')
|
||||
|
||||
described_class.load_gdk_vite_config
|
||||
|
|
@ -52,6 +53,7 @@ RSpec.describe ViteGdk, feature_category: :tooling do
|
|||
expect(ViteRuby).to receive(:configure).with(host: 'gdk.test', port: 3038)
|
||||
expect(ViteRuby.env).to receive(:[]=).with('VITE_ENABLED', 'true')
|
||||
expect(ViteRuby.env).to receive(:[]=).with('VITE_HMR_HOST', 'hmr.gdk.test')
|
||||
expect(ViteRuby.env).to receive(:[]=).with('VITE_HMR_HTTP_URL', 'https://hmr.gdk.test:9999')
|
||||
expect(ViteRuby.env).to receive(:[]=).with('VITE_HMR_WS_URL', 'wss://hmr.gdk.test:9999')
|
||||
|
||||
described_class.load_gdk_vite_config
|
||||
|
|
@ -76,6 +78,7 @@ RSpec.describe ViteGdk, feature_category: :tooling do
|
|||
expect(ViteRuby).to receive(:configure).with(host: 'gdk.test', port: 3038)
|
||||
expect(ViteRuby.env).to receive(:[]=).with('VITE_ENABLED', 'true')
|
||||
expect(ViteRuby.env).to receive(:[]=).with('VITE_HMR_HOST', 'hmr.gdk.test')
|
||||
expect(ViteRuby.env).to receive(:[]=).with('VITE_HMR_HTTP_URL', 'https://hmr.gdk.test:3038')
|
||||
expect(ViteRuby.env).to receive(:[]=).with('VITE_HMR_WS_URL', 'wss://hmr.gdk.test:3038')
|
||||
|
||||
described_class.load_gdk_vite_config
|
||||
|
|
|
|||
|
|
@ -47,31 +47,40 @@ RSpec.shared_examples 'Base action controller' do
|
|||
end
|
||||
|
||||
context 'when configuring vite' do
|
||||
let(:vite_origin) { "#{ViteRuby.instance.config.host}:#{ViteRuby.instance.config.port}" }
|
||||
let(:vite_hmr_websocket_url) { "ws://gitlab.example.com:3808" }
|
||||
let(:vite_hmr_http_url) { "http://gitlab.example.com:3808" }
|
||||
let(:vite_gitlab_url) { Gitlab::Utils.append_path(Gitlab.config.gitlab.url, 'vite-dev/') }
|
||||
|
||||
context 'when vite enabled during development',
|
||||
skip: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424334' do
|
||||
before do
|
||||
stub_rails_env('development')
|
||||
allow(ViteHelper).to receive(:vite_enabled?).and_return(true)
|
||||
allow(BaseActionController.helpers).to receive(:vite_enabled?).and_return(true)
|
||||
allow(BaseActionController.helpers).to receive(:vite_hmr_websocket_url).and_return(vite_hmr_websocket_url)
|
||||
allow(BaseActionController.helpers).to receive(:vite_hmr_http_url).and_return(vite_hmr_http_url)
|
||||
end
|
||||
|
||||
it 'adds vite csp' do
|
||||
request
|
||||
|
||||
expect(response.headers['Content-Security-Policy']).to include(vite_origin)
|
||||
expect(response.headers['Content-Security-Policy']).to include("#{vite_hmr_websocket_url}/vite-dev/")
|
||||
expect(response.headers['Content-Security-Policy']).to include("#{vite_hmr_http_url}/vite-dev/")
|
||||
expect(response.headers['Content-Security-Policy']).to include(vite_gitlab_url)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when vite disabled' do
|
||||
before do
|
||||
allow(ViteHelper).to receive(:vite_enabled?).and_return(false)
|
||||
allow(BaseActionController.helpers).to receive(:vite_enabled?).and_return(false)
|
||||
end
|
||||
|
||||
it "doesn't add vite csp" do
|
||||
request
|
||||
|
||||
expect(response.headers['Content-Security-Policy']).not_to include(vite_origin)
|
||||
expect(response.headers['Content-Security-Policy']).not_to include(vite_hmr_websocket_url)
|
||||
expect(response.headers['Content-Security-Policy']).not_to include(vite_hmr_http_url)
|
||||
expect(response.headers['Content-Security-Policy']).not_to include(vite_gitlab_url)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ def webmock_allowed_hosts
|
|||
|
||||
if ViteRuby.env['VITE_ENABLED'] == "true"
|
||||
hosts << ViteRuby.instance.config.host
|
||||
hosts << ViteRuby.env['VITE_HMR_HOST']
|
||||
end
|
||||
end.compact.uniq
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue