Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
e69d400913
commit
7564f3f38f
|
|
@ -15,7 +15,7 @@ include:
|
|||
gitlab_auth_token_variable_name: "PROJECT_TOKEN_FOR_CI_SCRIPTS_API_USAGE"
|
||||
allure_job_name: "${QA_RUN_TYPE}"
|
||||
- project: gitlab-org/quality/pipeline-common
|
||||
ref: 8.4.3
|
||||
ref: 8.4.4
|
||||
file:
|
||||
- /ci/base.gitlab-ci.yml
|
||||
- /ci/knapsack-report.yml
|
||||
|
|
|
|||
|
|
@ -4025,7 +4025,6 @@ RSpec/FeatureCategory:
|
|||
- 'spec/lib/gitlab/usage_data_counters/quick_action_activity_unique_counter_spec.rb'
|
||||
- 'spec/lib/gitlab/usage_data_counters/redis_counter_spec.rb'
|
||||
- 'spec/lib/gitlab/usage_data_counters/search_counter_spec.rb'
|
||||
- 'spec/lib/gitlab/usage_data_counters/service_usage_data_counter_spec.rb'
|
||||
- 'spec/lib/gitlab/usage_data_counters/snippet_counter_spec.rb'
|
||||
- 'spec/lib/gitlab/usage_data_counters/source_code_counter_spec.rb'
|
||||
- 'spec/lib/gitlab/usage_data_counters/vscode_extension_activity_unique_counter_spec.rb'
|
||||
|
|
|
|||
|
|
@ -516,7 +516,6 @@ Style/ClassAndModuleChildren:
|
|||
- 'lib/gitlab/usage_data_counters/designs_counter.rb'
|
||||
- 'lib/gitlab/usage_data_counters/note_counter.rb'
|
||||
- 'lib/gitlab/usage_data_counters/productivity_analytics_counter.rb'
|
||||
- 'lib/gitlab/usage_data_counters/service_usage_data_counter.rb'
|
||||
- 'lib/gitlab/usage_data_counters/snippet_counter.rb'
|
||||
- 'lib/gitlab/usage_data_counters/source_code_counter.rb'
|
||||
- 'lib/gitlab/usage_data_counters/wiki_page_counter.rb'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
<script>
|
||||
import { GlButton } from '@gitlab/ui';
|
||||
import { __, s__ } from '~/locale';
|
||||
import OrganizationsView from '~/organizations/shared/components/organizations_view.vue';
|
||||
import { DEFAULT_PER_PAGE } from '~/api';
|
||||
import { createAlert } from '~/alert';
|
||||
import organizationsQuery from '../graphql/queries/organizations.query.graphql';
|
||||
|
||||
export default {
|
||||
name: 'AdminOrganizationsIndexApp',
|
||||
i18n: {
|
||||
pageTitle: __('Organizations'),
|
||||
newOrganization: s__('Organization|New organization'),
|
||||
errorMessage: s__(
|
||||
'Organization|An error occurred loading organizations. Please refresh the page to try again.',
|
||||
),
|
||||
},
|
||||
components: { GlButton, OrganizationsView },
|
||||
inject: ['newOrganizationUrl'],
|
||||
data() {
|
||||
return {
|
||||
organizations: {},
|
||||
pagination: {
|
||||
first: DEFAULT_PER_PAGE,
|
||||
after: null,
|
||||
last: null,
|
||||
before: null,
|
||||
},
|
||||
};
|
||||
},
|
||||
apollo: {
|
||||
organizations: {
|
||||
query: organizationsQuery,
|
||||
variables() {
|
||||
return this.pagination;
|
||||
},
|
||||
update(data) {
|
||||
return data.organizations;
|
||||
},
|
||||
error(error) {
|
||||
createAlert({ message: this.$options.i18n.errorMessage, error, captureError: true });
|
||||
},
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
showHeader() {
|
||||
return this.loading || this.organizations.nodes?.length;
|
||||
},
|
||||
loading() {
|
||||
return this.$apollo.queries.organizations.loading;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onNext(endCursor) {
|
||||
this.pagination = {
|
||||
first: DEFAULT_PER_PAGE,
|
||||
after: endCursor,
|
||||
last: null,
|
||||
before: null,
|
||||
};
|
||||
},
|
||||
onPrev(startCursor) {
|
||||
this.pagination = {
|
||||
first: null,
|
||||
after: null,
|
||||
last: DEFAULT_PER_PAGE,
|
||||
before: startCursor,
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="gl-py-6">
|
||||
<div
|
||||
v-if="showHeader"
|
||||
class="gl-display-flex gl-align-items-center gl-justify-content-space-between gl-mb-5"
|
||||
>
|
||||
<h1 class="gl-m-0 gl-font-size-h-display">{{ $options.i18n.pageTitle }}</h1>
|
||||
<gl-button :href="newOrganizationUrl" variant="confirm">{{
|
||||
$options.i18n.newOrganization
|
||||
}}</gl-button>
|
||||
</div>
|
||||
<organizations-view
|
||||
:organizations="organizations"
|
||||
:loading="loading"
|
||||
@next="onNext"
|
||||
@prev="onPrev"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
#import "~/graphql_shared/fragments/page_info.fragment.graphql"
|
||||
#import "~/organizations/shared/graphql/fragments/organization.fragment.graphql"
|
||||
|
||||
query getOrganizations($first: Int, $last: Int, $before: String, $after: String) {
|
||||
organizations(first: $first, last: $last, before: $before, after: $after) {
|
||||
nodes {
|
||||
...Organization
|
||||
}
|
||||
pageInfo {
|
||||
...PageInfo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
import Vue from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
|
||||
import createDefaultClient from '~/lib/graphql';
|
||||
import App from './components/app.vue';
|
||||
|
||||
export const initAdminOrganizationsIndex = () => {
|
||||
const el = document.getElementById('js-admin-organizations-index');
|
||||
|
||||
if (!el) return false;
|
||||
|
||||
const {
|
||||
dataset: { appData },
|
||||
} = el;
|
||||
const { newOrganizationUrl, organizationsEmptyStateSvgPath } = convertObjectPropsToCamelCase(
|
||||
JSON.parse(appData),
|
||||
);
|
||||
|
||||
const apolloProvider = new VueApollo({
|
||||
defaultClient: createDefaultClient(),
|
||||
});
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
name: 'AdminOrganizationIndexRoot',
|
||||
apolloProvider,
|
||||
provide: {
|
||||
newOrganizationUrl,
|
||||
organizationsEmptyStateSvgPath,
|
||||
},
|
||||
render(createElement) {
|
||||
return createElement(App);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
@ -31,6 +31,16 @@ export default {
|
|||
headingDescription: s__(
|
||||
'Runners|After you complete the steps below, an autoscaling fleet of runners is available to execute your CI/CD jobs in Google Cloud. Based on demand, a runner manager automatically creates temporary runners.',
|
||||
),
|
||||
beforeHeading: s__('Runners|Before you begin'),
|
||||
permissionsText: s__(
|
||||
'Runners|Ensure you have the %{linkStart}Owner%{linkEnd} IAM role on your Google Cloud project.',
|
||||
),
|
||||
billingLinkText: s__(
|
||||
'Runners|Ensure that %{linkStart}billing is enabled for your Google Cloud project%{linkEnd}.',
|
||||
),
|
||||
preInstallText: s__(
|
||||
'Runners|To follow the setup instructions, %{gcloudLinkStart}install the Google Cloud CLI%{gcloudLinkEnd} and %{terraformLinkStart}install Terraform%{terraformLinkEnd}.',
|
||||
),
|
||||
stepOneHeading: s__('Runners|Step 1: Specify environment'),
|
||||
stepOneDescription: s__(
|
||||
'Runners|Environment in Google Cloud where runners execute CI/CD jobs. Runners are created in temporary virtual machines based on demand.',
|
||||
|
|
@ -86,8 +96,14 @@ export default {
|
|||
},
|
||||
alertBody: s__('Runners|To view the setup instructions, complete the previous form'),
|
||||
invalidFormButton: s__('Runners|Go to first invalid form field'),
|
||||
externalLink: __('(external link)'),
|
||||
},
|
||||
links: {
|
||||
permissionsLink: 'https://cloud.google.com/iam/docs/understanding-roles#owner',
|
||||
billingLink:
|
||||
'https://cloud.google.com/billing/docs/how-to/verify-billing-enabled#confirm_billing_is_enabled_on_a_project',
|
||||
gcloudLink: 'https://cloud.google.com/sdk/docs/install',
|
||||
terraformLink: 'https://developer.hashicorp.com/terraform/install',
|
||||
projectIdLink:
|
||||
'https://cloud.google.com/resource-manager/docs/creating-managing-projects#identifying_projects',
|
||||
regionAndZonesLink: 'https://cloud.google.com/compute/docs/regions-zones',
|
||||
|
|
@ -309,6 +325,51 @@ export default {
|
|||
</div>
|
||||
<hr />
|
||||
|
||||
<!-- start: before you begin -->
|
||||
<div>
|
||||
<h2 class="gl-font-lg">{{ $options.i18n.beforeHeading }}</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<gl-sprintf :message="$options.i18n.permissionsText">
|
||||
<template #link="{ content }">
|
||||
<gl-link :href="$options.links.permissionsLink" target="_blank">
|
||||
{{ content }}
|
||||
<gl-icon name="external-link" :aria-label="$options.i18n.externalLink" />
|
||||
</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</li>
|
||||
<li>
|
||||
<gl-sprintf :message="$options.i18n.billingLinkText">
|
||||
<template #link="{ content }">
|
||||
<gl-link :href="$options.links.billingLink" target="_blank">
|
||||
{{ content }}
|
||||
<gl-icon name="external-link" :aria-label="$options.i18n.externalLink" />
|
||||
</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</li>
|
||||
<li>
|
||||
<gl-sprintf :message="$options.i18n.preInstallText">
|
||||
<template #gcloudLink="{ content }">
|
||||
<gl-link :href="$options.links.gcloudLink" target="_blank">
|
||||
{{ content }}
|
||||
<gl-icon name="external-link" :aria-label="$options.i18n.externalLink" />
|
||||
</gl-link>
|
||||
</template>
|
||||
<template #terraformLink="{ content }">
|
||||
<gl-link :href="$options.links.terraformLink" target="_blank">
|
||||
{{ content }}
|
||||
<gl-icon name="external-link" :aria-label="$options.i18n.externalLink" />
|
||||
</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<hr />
|
||||
<!-- end: before you begin -->
|
||||
|
||||
<!-- start: step one -->
|
||||
<div class="gl-pb-4">
|
||||
<h2 class="gl-font-lg">{{ $options.i18n.stepOneHeading }}</h2>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { EditorContent as TiptapEditorContent } from '@tiptap/vue-2';
|
|||
import { __ } from '~/locale';
|
||||
import { VARIANT_DANGER } from '~/alert';
|
||||
import EditorModeSwitcher from '~/vue_shared/components/markdown/editor_mode_switcher.vue';
|
||||
import { CONTENT_EDITOR_READY_EVENT } from '~/vue_shared/constants';
|
||||
import { CONTENT_EDITOR_READY_EVENT, CONTENT_EDITOR_PASTE } from '~/vue_shared/constants';
|
||||
import markdownEditorEventHub from '~/vue_shared/components/markdown/eventhub';
|
||||
import SidebarMediator from '~/sidebar/sidebar_mediator';
|
||||
import { createContentEditor } from '../services/create_content_editor';
|
||||
|
|
@ -169,11 +169,16 @@ export default {
|
|||
this.$emit('initialized');
|
||||
await this.setSerializedContent(this.markdown);
|
||||
markdownEditorEventHub.$emit(CONTENT_EDITOR_READY_EVENT);
|
||||
markdownEditorEventHub.$on(CONTENT_EDITOR_PASTE, this.pasteContent);
|
||||
},
|
||||
beforeDestroy() {
|
||||
markdownEditorEventHub.$off(CONTENT_EDITOR_PASTE, this.pasteContent);
|
||||
this.contentEditor.dispose();
|
||||
},
|
||||
methods: {
|
||||
pasteContent(content) {
|
||||
this.contentEditor.tiptapEditor.chain().focus().pasteContent(content).run();
|
||||
},
|
||||
async setSerializedContent(markdown) {
|
||||
this.notifyLoading();
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ import { GlButton } from '@gitlab/ui';
|
|||
import { __, s__ } from '~/locale';
|
||||
import { createAlert } from '~/alert';
|
||||
import { DEFAULT_PER_PAGE } from '~/api';
|
||||
import OrganizationsView from '~/organizations/shared/components/organizations_view.vue';
|
||||
import organizationsQuery from '../../shared/graphql/queries/organizations.query.graphql';
|
||||
import OrganizationsView from './organizations_view.vue';
|
||||
|
||||
export default {
|
||||
name: 'OrganizationsIndexApp',
|
||||
|
|
|
|||
|
|
@ -1,10 +1,16 @@
|
|||
<script>
|
||||
import { GlAvatarLabeled, GlTruncateText } from '@gitlab/ui';
|
||||
import { __ } from '~/locale';
|
||||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
import SafeHtml from '~/vue_shared/directives/safe_html';
|
||||
|
||||
export default {
|
||||
name: 'OrganizationsListItem',
|
||||
i18n: {
|
||||
showMore: __('Show more'),
|
||||
showLess: __('Show less'),
|
||||
},
|
||||
truncateTextToggleButtonProps: { class: 'gl-font-sm!' },
|
||||
components: {
|
||||
GlAvatarLabeled,
|
||||
GlTruncateText,
|
||||
|
|
@ -21,17 +27,20 @@ export default {
|
|||
required: true,
|
||||
},
|
||||
},
|
||||
avatarSize: { default: 32, md: 48 },
|
||||
getIdFromGraphQLId,
|
||||
methods: {
|
||||
getIdFromGraphQLId,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<li class="organization-row gl-py-3 gl-border-b gl-display-flex gl-align-items-flex-start">
|
||||
<li
|
||||
class="organization-row gl-py-5 gl-px-5 gl-border-b gl-display-flex gl-align-items-flex-start"
|
||||
>
|
||||
<gl-avatar-labeled
|
||||
:size="$options.avatarSize"
|
||||
:size="48"
|
||||
:src="organization.avatarUrl"
|
||||
:entity-id="$options.getIdFromGraphQLId(organization.id)"
|
||||
:entity-id="getIdFromGraphQLId(organization.id)"
|
||||
:entity-name="organization.name"
|
||||
:label="organization.name"
|
||||
:label-link="organization.webUrl"
|
||||
|
|
@ -41,12 +50,15 @@ export default {
|
|||
v-if="organization.descriptionHtml"
|
||||
:lines="2"
|
||||
:mobile-lines="2"
|
||||
class="gl-mt-2"
|
||||
:show-more-text="$options.i18n.showMore"
|
||||
:show-less-text="$options.i18n.showLess"
|
||||
:toggle-button-props="$options.truncateTextToggleButtonProps"
|
||||
class="gl-mt-2 gl-max-w-88"
|
||||
>
|
||||
<div
|
||||
v-safe-html:[$options.safeHtmlConfig]="organization.descriptionHtml"
|
||||
data-testid="organization-description-html"
|
||||
class="organization-description gl-text-secondary gl-font-sm"
|
||||
class="gl-text-secondary gl-font-sm md"
|
||||
></div>
|
||||
</gl-truncate-text>
|
||||
</gl-avatar-labeled>
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<script>
|
||||
import { GlLoadingIcon, GlEmptyState } from '@gitlab/ui';
|
||||
import { s__ } from '~/locale';
|
||||
import OrganizationsList from './organizations_list.vue';
|
||||
import OrganizationsList from './list/organizations_list.vue';
|
||||
|
||||
export default {
|
||||
name: 'OrganizationsView',
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
import initUsageQuotas from '~/usage_quotas';
|
||||
import { GROUP_VIEW_TYPE } from '~/usage_quotas/constants';
|
||||
|
||||
initUsageQuotas();
|
||||
initUsageQuotas(GROUP_VIEW_TYPE);
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ export default {
|
|||
:key="tab.hash"
|
||||
:title="tab.title"
|
||||
:active="isActive(tab.hash)"
|
||||
:data-testid="tab.hash"
|
||||
@click="updateActiveTab(tab.hash)"
|
||||
>
|
||||
<component :is="tab.component" :data-testid="`${tab.hash}-app`" />
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
export const GROUP_VIEW_TYPE = 'group_view';
|
||||
export const PROJECT_VIEW_TYPE = 'project_view';
|
||||
export const PROFILE_VIEW_TYPE = 'profile_view';
|
||||
|
||||
export const STORAGE_TAB_METADATA_EL_SELECTOR = '#js-namespace-storage-app';
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
import { getStorageTabMetadata } from './storage/tab_metadata';
|
||||
|
||||
export const usageQuotasTabsMetadata = [getStorageTabMetadata()];
|
||||
export const usageQuotasTabsMetadata = [getStorageTabMetadata()].filter(Boolean);
|
||||
|
|
|
|||
|
|
@ -1,26 +1,32 @@
|
|||
import Vue from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import createDefaultClient from '~/lib/graphql';
|
||||
import { usageQuotasTabsMetadata } from 'ee_else_ce/usage_quotas/group_view_metadata';
|
||||
import { usageQuotasTabsMetadata as groupViewTabsMetadata } from 'ee_else_ce/usage_quotas/group_view_metadata';
|
||||
import { usageQuotasTabsMetadata as profileViewTabsMetadata } from 'ee_else_ce/usage_quotas/profile_view_metadata';
|
||||
import UsageQuotasApp from './components/usage_quotas_app.vue';
|
||||
import { GROUP_VIEW_TYPE, PROFILE_VIEW_TYPE } from './constants';
|
||||
|
||||
Vue.use(VueApollo);
|
||||
const getViewTabs = (viewType) => {
|
||||
if (viewType === GROUP_VIEW_TYPE) {
|
||||
return groupViewTabsMetadata;
|
||||
}
|
||||
|
||||
const apolloProvider = new VueApollo({
|
||||
defaultClient: createDefaultClient(),
|
||||
});
|
||||
if (viewType === PROFILE_VIEW_TYPE) {
|
||||
return profileViewTabsMetadata;
|
||||
}
|
||||
|
||||
export default () => {
|
||||
return false;
|
||||
};
|
||||
|
||||
export default (viewType) => {
|
||||
const el = document.querySelector('#js-usage-quotas-view');
|
||||
const tabs = getViewTabs(viewType);
|
||||
|
||||
if (!el) return false;
|
||||
if (!el || !tabs) return false;
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
name: 'UsageQuotasView',
|
||||
apolloProvider,
|
||||
provide: {
|
||||
tabs: usageQuotasTabsMetadata.filter(Boolean),
|
||||
tabs,
|
||||
},
|
||||
render(createElement) {
|
||||
return createElement(UsageQuotasApp);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
// To Be implemented in https://gitlab.com/gitlab-org/gitlab/-/issues/385653
|
||||
export const usageQuotasTabsMetadata = [];
|
||||
|
|
@ -100,4 +100,5 @@ export const EDITING_MODE_CONTENT_EDITOR = 'contentEditor';
|
|||
|
||||
export const CLEAR_AUTOSAVE_ENTRY_EVENT = 'markdown_clear_autosave_entry';
|
||||
export const CONTENT_EDITOR_READY_EVENT = 'content_editor_ready';
|
||||
export const CONTENT_EDITOR_PASTE = 'content_editor_paste';
|
||||
export const MARKDOWN_EDITOR_READY_EVENT = 'markdown_editor_ready';
|
||||
|
|
|
|||
|
|
@ -1,10 +1,5 @@
|
|||
@import 'mixins_and_variables_and_functions';
|
||||
|
||||
// Modeled after projects.scss and groups.scss
|
||||
.organization-row .organization-description p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.organization-root-path {
|
||||
max-width: 40vw;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
|
|||
end
|
||||
|
||||
format.json do
|
||||
Gitlab::UsageDataCounters::ServiceUsageDataCounter.count(:download_payload_click)
|
||||
Gitlab::InternalEvents.track_event('usage_data_download_payload_clicked', user: current_user)
|
||||
|
||||
render json: Gitlab::Json.dump(prerecorded_service_ping_data)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -34,10 +34,7 @@ module Organizations
|
|||
end
|
||||
|
||||
def organization_index_app_data
|
||||
{
|
||||
new_organization_url: new_organization_path,
|
||||
organizations_empty_state_svg_path: image_path('illustrations/empty-state/empty-organizations-md.svg')
|
||||
}
|
||||
shared_organization_index_app_data
|
||||
end
|
||||
|
||||
def organization_user_app_data(organization)
|
||||
|
|
@ -66,6 +63,10 @@ module Organizations
|
|||
}.to_json
|
||||
end
|
||||
|
||||
def admin_organizations_index_app_data
|
||||
shared_organization_index_app_data.to_json
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def shared_groups_and_projects_app_data(organization)
|
||||
|
|
@ -89,6 +90,13 @@ module Organizations
|
|||
}
|
||||
end
|
||||
|
||||
def shared_organization_index_app_data
|
||||
{
|
||||
new_organization_url: new_organization_path,
|
||||
organizations_empty_state_svg_path: image_path('illustrations/empty-state/empty-organizations-md.svg')
|
||||
}
|
||||
end
|
||||
|
||||
# See UsersHelper#admin_users_paths for inspiration to this method
|
||||
def organizations_users_paths
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1 +1,3 @@
|
|||
- page_title _('Organizations')
|
||||
|
||||
#js-admin-organizations-index{ data: { app_data: admin_organizations_index_app_data } }
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@
|
|||
|
||||
.row
|
||||
.col-sm-6{ data: { testid: 'group-usage-message' } }
|
||||
%p.text-secondary
|
||||
%p.gl-text-secondary
|
||||
= safe_format(s_('UsageQuota|Usage of group resources across the projects in the %{strong_start}%{group_name}%{strong_end} group'),
|
||||
{ group_name: @group.name },
|
||||
tag_pair(tag.strong, :strong_start, :strong_end))
|
||||
|
||||
#js-usage-quotas-view
|
||||
.gl-font-lg.gl--flex-center
|
||||
%span.mr-1= s_('UsageQuota|Loading Usage Quotas tabs')
|
||||
%span.gl-mr-1= s_('UsageQuota|Loading Usage Quotas tabs')
|
||||
= render Pajamas::SpinnerComponent.new(inline: true, size: :md)
|
||||
#js-namespace-storage-app{ data: storage_usage_app_data(@group) }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
description: Counts Download Payload button clicks
|
||||
category: InternalEventTracking
|
||||
action: usage_data_download_payload_clicked
|
||||
identifiers:
|
||||
- user
|
||||
product_section: analytics
|
||||
product_stage: monitor
|
||||
product_group: analytics_instrumentation
|
||||
milestone: '16.10'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/146118
|
||||
distributions:
|
||||
- ce
|
||||
- ee
|
||||
tiers:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -8,11 +8,9 @@ product_group: analytics_instrumentation
|
|||
value_type: number
|
||||
status: active
|
||||
time_frame: all
|
||||
data_source: redis
|
||||
instrumentation_class: RedisMetric
|
||||
options:
|
||||
prefix: service_usage_data
|
||||
event: download_payload_click
|
||||
data_source: internal_events
|
||||
events:
|
||||
- name: usage_data_download_payload_clicked
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
|
|
|
|||
|
|
@ -7,4 +7,4 @@ feature_categories:
|
|||
description: User mentions in commit messages
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/19009
|
||||
milestone: '12.6'
|
||||
gitlab_schema: gitlab_main
|
||||
gitlab_schema: gitlab_main_cell
|
||||
|
|
|
|||
|
|
@ -7,4 +7,4 @@ feature_categories:
|
|||
description: Stores diff notes positions
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28113
|
||||
milestone: '13.0'
|
||||
gitlab_schema: gitlab_main
|
||||
gitlab_schema: gitlab_main_cell
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddOrganizationIdToDependencyListExports < Gitlab::Database::Migration[2.2]
|
||||
milestone '16.10'
|
||||
|
||||
def change
|
||||
add_column :dependency_list_exports, :organization_id, :bigint
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class IndexOrganizationIdOnDependencyListExports < Gitlab::Database::Migration[2.2]
|
||||
INDEX_NAME = 'index_dependency_list_exports_on_organization_id'
|
||||
|
||||
disable_ddl_transaction!
|
||||
milestone '16.10'
|
||||
|
||||
def up
|
||||
add_concurrent_index :dependency_list_exports, :organization_id, name: INDEX_NAME
|
||||
end
|
||||
|
||||
def down
|
||||
remove_concurrent_index_by_name :dependency_list_exports, INDEX_NAME
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddForeignKeyToOrganizationIdOnDependencyListExports < Gitlab::Database::Migration[2.2]
|
||||
disable_ddl_transaction!
|
||||
milestone '16.10'
|
||||
|
||||
def up
|
||||
add_concurrent_foreign_key :dependency_list_exports, :organizations,
|
||||
column: :organization_id,
|
||||
on_delete: :cascade,
|
||||
reverse_lock_order: true
|
||||
end
|
||||
|
||||
def down
|
||||
remove_foreign_key_if_exists :dependency_list_exports, column: :organization_id
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class UnscheduleOpenAiClearConvosCron < Gitlab::Database::Migration[2.2]
|
||||
milestone '16.10'
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
# This is to clean up the cron schedule for OpenAi::ClearConversationsWorker
|
||||
# which was removed in
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/commit/8c24e145c14d64c62a5b4f6fe72726140457d9f1#be4e3233708096a83c31a905040cb84cc105703d_780_780
|
||||
Sidekiq::Cron::Job.destroy('open_ai_clear_conversations')
|
||||
|
||||
sidekiq_remove_jobs(job_klasses: %w[OpenAi::ClearConversationsWorker])
|
||||
end
|
||||
|
||||
def down
|
||||
# No-op
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
ba88b86b5331d02fa7cfa4416fc2de5dbd451dc1fc03f5c6550f981b91d7ed96
|
||||
|
|
@ -0,0 +1 @@
|
|||
d1c427131b7cddcab2891069a03af3c615e6126f3d7a3a5a8e6b30b7f1875d5e
|
||||
|
|
@ -0,0 +1 @@
|
|||
0e53c0f6004aad8fee7323e5652dbabc9823561dd73ed017c7bfa34678ff9527
|
||||
|
|
@ -0,0 +1 @@
|
|||
f16288a4771fe31dd8e10e3441facc9e79918a4f46f0b8910f5924fd0819b472
|
||||
|
|
@ -7759,6 +7759,7 @@ CREATE TABLE dependency_list_exports (
|
|||
group_id bigint,
|
||||
pipeline_id bigint,
|
||||
export_type smallint DEFAULT 0 NOT NULL,
|
||||
organization_id bigint,
|
||||
CONSTRAINT check_fff6fc9b2f CHECK ((char_length(file) <= 255))
|
||||
);
|
||||
|
||||
|
|
@ -24751,6 +24752,8 @@ CREATE UNIQUE INDEX index_dep_prox_manifests_on_group_id_file_name_and_status ON
|
|||
|
||||
CREATE INDEX index_dependency_list_exports_on_group_id ON dependency_list_exports USING btree (group_id);
|
||||
|
||||
CREATE INDEX index_dependency_list_exports_on_organization_id ON dependency_list_exports USING btree (organization_id);
|
||||
|
||||
CREATE INDEX index_dependency_list_exports_on_pipeline_id ON dependency_list_exports USING btree (pipeline_id);
|
||||
|
||||
CREATE INDEX index_dependency_list_exports_on_project_id ON dependency_list_exports USING btree (project_id);
|
||||
|
|
@ -30189,6 +30192,9 @@ ALTER TABLE ONLY sbom_occurrences
|
|||
ALTER TABLE ONLY issues
|
||||
ADD CONSTRAINT fk_c34dd2b036 FOREIGN KEY (tmp_epic_id) REFERENCES epics(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY dependency_list_exports
|
||||
ADD CONSTRAINT fk_c348f16f10 FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY user_group_callouts
|
||||
ADD CONSTRAINT fk_c366e12ec3 FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
extends: existence
|
||||
message: "Offerings should be comma-separated, without `and`, and must be capitalized. Example: `GitLab.com, Self-managed, GitLab Dedicated`."
|
||||
link: https://docs.gitlab.com/ee/development/documentation/styleguide/#available-product-tier-badges
|
||||
level: suggestion
|
||||
level: error
|
||||
scope: raw
|
||||
raw:
|
||||
- (?<=\n\*\*Offering:\*\* )(Dedicated|[^\n]*(SaaS|self-managed|Self-Managed|GitLab dedicated|and|GitLab Dedicated,|, GitLab\.com|, Dedicated))
|
||||
|
|
|
|||
|
|
@ -20,6 +20,22 @@ self-managed instances. If you are an administrator, to access the Admin Area:
|
|||
NOTE:
|
||||
Only administrators can access the Admin Area.
|
||||
|
||||
## Administering organizations
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/419540) in GitLab 16.10 [with a flag](feature_flags.md) named `ui_for_organizations`. Disabled by default.
|
||||
|
||||
FLAG:
|
||||
On self-managed GitLab, by default this feature is not available. To make it available, an administrator can [enable the feature flag](feature_flags.md) named `ui_for_organizations`.
|
||||
On GitLab.com and GitLab Dedicated, this feature is not available.
|
||||
This feature is not ready for production use.
|
||||
|
||||
You can administer all organizations in the GitLab instance from the Admin Area's Organizations page.
|
||||
|
||||
To access the Organizations page:
|
||||
|
||||
1. On the left sidebar, at the bottom, select **Admin Area**.
|
||||
1. Select **Overview > Organizations**.
|
||||
|
||||
## Administering projects
|
||||
|
||||
You can administer all projects in the GitLab instance from the Admin Area's Projects page.
|
||||
|
|
|
|||
|
|
@ -43,6 +43,12 @@ NOTE:
|
|||
Audit event types with the `-` scope are limited to either project, group, or instance and user audit events, but the
|
||||
[information on the scope](https://gitlab.com/gitlab-org/gitlab/-/issues/438620) is still being added to the documentation.
|
||||
|
||||
### Ai framework
|
||||
|
||||
| Name | Description | Saved to database | Streamed | Introduced in | Scope |
|
||||
|:------------|:------------|:------------------|:---------|:--------------|:--------------|
|
||||
| [`duo_features_enabled_updated`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/145509) | GitLab Duo Features enabled setting on group or project changed| **{check-circle}** Yes | **{check-circle}** Yes | GitLab [16.10](https://gitlab.com/gitlab-org/gitlab/-/issues/442485) | Group, Project |
|
||||
|
||||
### Audit events
|
||||
|
||||
| Name | Description | Saved to database | Streamed | Introduced in | Scope |
|
||||
|
|
|
|||
|
|
@ -15126,7 +15126,6 @@ Represents the approval policy.
|
|||
| <a id="approvalpolicyenabled"></a>`enabled` | [`Boolean!`](#boolean) | Indicates whether this policy is enabled. |
|
||||
| <a id="approvalpolicygroupapprovers"></a>`groupApprovers` **{warning-solid}** | [`[Group!]`](#group) | **Deprecated** in GitLab 16.5. Use `allGroupApprovers`. |
|
||||
| <a id="approvalpolicyname"></a>`name` | [`String!`](#string) | Name of the policy. |
|
||||
| <a id="approvalpolicypolicyscope"></a>`policyScope` | [`PolicyScope`](#policyscope) | Scope of the policy. |
|
||||
| <a id="approvalpolicyroleapprovers"></a>`roleApprovers` | [`[MemberAccessLevelName!]`](#memberaccesslevelname) | Approvers of the role type. Users belonging to these role(s) alone will be approvers. |
|
||||
| <a id="approvalpolicysource"></a>`source` | [`SecurityPolicySource!`](#securitypolicysource) | Source of the policy. Its fields depend on the source type. |
|
||||
| <a id="approvalpolicyupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp of when the policy YAML was last updated. |
|
||||
|
|
@ -25211,16 +25210,6 @@ Represents vulnerability finding of a security report on the pipeline.
|
|||
| <a id="policyapprovalgroupid"></a>`id` | [`ID!`](#id) | ID of the namespace. |
|
||||
| <a id="policyapprovalgroupweburl"></a>`webUrl` | [`String!`](#string) | Web URL of the group. |
|
||||
|
||||
### `PolicyScope`
|
||||
|
||||
#### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="policyscopecomplianceframeworks"></a>`complianceFrameworks` | [`ComplianceFrameworkConnection!`](#complianceframeworkconnection) | Compliance Frameworks linked to the policy. (see [Connections](#connections)) |
|
||||
| <a id="policyscopeexcludingprojects"></a>`excludingProjects` | [`ProjectConnection!`](#projectconnection) | Projects to which the policy should not be applied to. (see [Connections](#connections)) |
|
||||
| <a id="policyscopeincludingprojects"></a>`includingProjects` | [`ProjectConnection!`](#projectconnection) | Projects to which the policy should be applied to. (see [Connections](#connections)) |
|
||||
|
||||
### `PreviewBillableUserChange`
|
||||
|
||||
#### Fields
|
||||
|
|
@ -27942,7 +27931,6 @@ Represents the scan execution policy.
|
|||
| <a id="scanexecutionpolicyeditpath"></a>`editPath` | [`String!`](#string) | URL of policy edit page. |
|
||||
| <a id="scanexecutionpolicyenabled"></a>`enabled` | [`Boolean!`](#boolean) | Indicates whether this policy is enabled. |
|
||||
| <a id="scanexecutionpolicyname"></a>`name` | [`String!`](#string) | Name of the policy. |
|
||||
| <a id="scanexecutionpolicypolicyscope"></a>`policyScope` | [`PolicyScope`](#policyscope) | Scope of the policy. |
|
||||
| <a id="scanexecutionpolicysource"></a>`source` | [`SecurityPolicySource!`](#securitypolicysource) | Source of the policy. Its fields depend on the source type. |
|
||||
| <a id="scanexecutionpolicyupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp of when the policy YAML was last updated. |
|
||||
| <a id="scanexecutionpolicyyaml"></a>`yaml` | [`String!`](#string) | YAML definition of the policy. |
|
||||
|
|
@ -27961,7 +27949,6 @@ Represents the scan result policy.
|
|||
| <a id="scanresultpolicyenabled"></a>`enabled` | [`Boolean!`](#boolean) | Indicates whether this policy is enabled. |
|
||||
| <a id="scanresultpolicygroupapprovers"></a>`groupApprovers` **{warning-solid}** | [`[Group!]`](#group) | **Deprecated** in GitLab 16.5. Use `allGroupApprovers`. |
|
||||
| <a id="scanresultpolicyname"></a>`name` | [`String!`](#string) | Name of the policy. |
|
||||
| <a id="scanresultpolicypolicyscope"></a>`policyScope` | [`PolicyScope`](#policyscope) | Scope of the policy. |
|
||||
| <a id="scanresultpolicyroleapprovers"></a>`roleApprovers` | [`[MemberAccessLevelName!]`](#memberaccesslevelname) | Approvers of the role type. Users belonging to these role(s) alone will be approvers. |
|
||||
| <a id="scanresultpolicysource"></a>`source` | [`SecurityPolicySource!`](#securitypolicysource) | Source of the policy. Its fields depend on the source type. |
|
||||
| <a id="scanresultpolicyupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp of when the policy YAML was last updated. |
|
||||
|
|
@ -34783,7 +34770,6 @@ Implementations:
|
|||
| <a id="orchestrationpolicyeditpath"></a>`editPath` | [`String!`](#string) | URL of policy edit page. |
|
||||
| <a id="orchestrationpolicyenabled"></a>`enabled` | [`Boolean!`](#boolean) | Indicates whether this policy is enabled. |
|
||||
| <a id="orchestrationpolicyname"></a>`name` | [`String!`](#string) | Name of the policy. |
|
||||
| <a id="orchestrationpolicypolicyscope"></a>`policyScope` | [`PolicyScope`](#policyscope) | Scope of the policy. |
|
||||
| <a id="orchestrationpolicyupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp of when the policy YAML was last updated. |
|
||||
| <a id="orchestrationpolicyyaml"></a>`yaml` | [`String!`](#string) | YAML definition of the policy. |
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ You must have at least the Maintainer role for the project.
|
|||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. Select **Settings > Access Tokens**.
|
||||
1. Create an access token with the following scopes: `read_api`, `read_observability`, `write_observability`. Be sure to save the access token value for later.
|
||||
1. Select **Monitor > Tracing**, and then select **Enable**.
|
||||
1. Select **Monitor > Metrics**, and then select **Enable**.
|
||||
1. To configure your application to send GitLab metrics, set the following environment variables:
|
||||
|
||||
```shell
|
||||
|
|
|
|||
|
|
@ -7,10 +7,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
# Use CI/CD to build your application
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Free, Premium, Ultimate
|
||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
||||
|
||||
Use CI/CD to generate your application.
|
||||
|
||||
- [Getting started](../ci/index.md)
|
||||
|
|
|
|||
|
|
@ -7,10 +7,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
# Manage your code
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Free, Premium, Ultimate
|
||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
||||
|
||||
Store your source files in a repository and create merge requests. Write, debug, and collaborate on code.
|
||||
|
||||
- [Repositories](../user/project/repository/index.md)
|
||||
|
|
|
|||
|
|
@ -7,10 +7,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
# Plan and track work
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Free, Premium, Ultimate
|
||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
||||
|
||||
Plan your work by creating requirements, issues, and epics. Schedule work
|
||||
with milestones and track your team's time. Learn how to save time with
|
||||
quick actions, see how GitLab renders Markdown text, and learn how to
|
||||
|
|
|
|||
|
|
@ -7,10 +7,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
# Deploy and release your application
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Free, Premium, Ultimate
|
||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
||||
|
||||
Deployment is the step of the software delivery process when your
|
||||
application gets deployed to its final, target infrastructure.
|
||||
|
||||
|
|
|
|||
|
|
@ -7,10 +7,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
# Set up your organization
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Free, Premium, Ultimate
|
||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
||||
|
||||
Configure your organization and its users. Determine user roles
|
||||
and give everyone access to the projects they need.
|
||||
|
||||
|
|
|
|||
|
|
@ -7,10 +7,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
# Analyze GitLab usage
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Free, Premium, Ultimate
|
||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
||||
|
||||
GitLab provides different types of analytics insights at the instance, group, and project level.
|
||||
These insights appear on the left sidebar, under [**Analyze**](../project/settings/project_features_permissions.md#disable-project-analytics).
|
||||
|
||||
|
|
|
|||
|
|
@ -7,10 +7,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
# Secure your application
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Free, Premium, Ultimate
|
||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
||||
|
||||
GitLab can check your applications for security vulnerabilities.
|
||||
|
||||
- [Get started](get-started-security.md)
|
||||
|
|
|
|||
|
|
@ -158,11 +158,11 @@ To see the full list of customizations available, see the Helm chart's [README](
|
|||
##### Use the agent when KAS is behind a self-signed certificate
|
||||
|
||||
When [KAS](../../../../administration/clusters/kas.md) is behind a self-signed certificate,
|
||||
you can set the value of `config.caCert` to the certificate. For example:
|
||||
you can set the value of `config.kasCaCert` to the certificate. For example:
|
||||
|
||||
```shell
|
||||
helm upgrade --install gitlab-agent gitlab/gitlab-agent \
|
||||
--set-file config.caCert=my-custom-ca.pem
|
||||
--set-file config.kasCaCert=my-custom-ca.pem
|
||||
```
|
||||
|
||||
In this example, `my-custom-ca.pem` is the path to a local file that contains
|
||||
|
|
|
|||
|
|
@ -12,23 +12,33 @@ DETAILS:
|
|||
|
||||
In GitLab, you use groups to manage one or more related projects at the same time.
|
||||
|
||||
You can use groups to manage permissions for your projects. If someone has access to
|
||||
the group, they get access to all the projects in the group.
|
||||
You can use groups to communicate with all group members and manage permissions for your projects.
|
||||
If someone has access to the group, they get access to all the projects in the group.
|
||||
|
||||
You can also view all of the issues and merge requests for the projects in the group,
|
||||
and view analytics that show the group's activity.
|
||||
|
||||
You can use groups to communicate with all of the members of the group at once.
|
||||
and analytics about the group's activity.
|
||||
|
||||
For larger organizations, you can also create [subgroups](subgroups/index.md).
|
||||
|
||||
For more information about creating and managing your groups, see [Manage groups](manage.md).
|
||||
|
||||
## Group structure
|
||||
|
||||
The way to set up a group depends on your use cases, team size, and access requirements.
|
||||
The following table describes the most common models of structuring groups.
|
||||
|
||||
| Model | Structure | Use cases |
|
||||
| ----- | --------- | --------- |
|
||||
| Simple | One group for all your projects. | Work in a small team or on specific solutions (for example, a marketing website) that require seamless collaboration and access to resources. |
|
||||
| Team | Different groups or subgroups for different types of teams (for example, product and engineering). | Work in a large organization where some teams work autonomously or require centralized resources and limited access from external team members. |
|
||||
| Client | One group for each client. | Provide custom solutions for multiple clients that require different resources and access levels. |
|
||||
| Functionality | One group or subgroup for one type of functionality (for example, AI/ML). | Develop complex products where one functionality requires specific resources and collaboration of subject-matter experts. |
|
||||
|
||||
NOTE:
|
||||
For self-managed customers it could be beneficial to create one single top-level group, so you can see an overview of
|
||||
your entire organization. For more information about efforts to create an
|
||||
organization view of all groups, [see epic 9266](https://gitlab.com/groups/gitlab-org/-/epics/9266).
|
||||
A single top-level group provides insights in your entire organization via a complete
|
||||
On self-managed GitLab, if you want to see an overview of your entire organization, you should create one top-level group.
|
||||
For more information about efforts to create an organization view of all groups,
|
||||
[see epic 9266](https://gitlab.com/groups/gitlab-org/-/epics/9266).
|
||||
A single top-level group provides insights in your entire organization through a complete
|
||||
[Security Dashboard and Center](../application_security/security_dashboard/index.md),
|
||||
[Vulnerability](../application_security/vulnerability_report/index.md#vulnerability-report) and
|
||||
[Compliance center](../compliance/compliance_center/index.md), and
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/409913) in GitLab 16.1 [with a flag](../../administration/feature_flags.md) named `ui_for_organizations`. Disabled by default.
|
||||
|
||||
FLAG:
|
||||
This feature is not ready for production use.
|
||||
On self-managed GitLab, by default this feature is not available. To make it available, an administrator can [enable the feature flag](../../administration/feature_flags.md) named `ui_for_organizations`.
|
||||
On GitLab.com and GitLab Dedicated, this feature is not available.
|
||||
This feature is not ready for production use.
|
||||
|
||||
DISCLAIMER:
|
||||
This page contains information related to upcoming products, features, and functionality.
|
||||
|
|
|
|||
|
|
@ -7,10 +7,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
# Organize work with projects
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Free, Premium, Ultimate
|
||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
||||
|
||||
In GitLab, you can create projects to host
|
||||
your codebase. You can also use projects to track issues, plan work,
|
||||
collaborate on code, and continuously build, test, and use
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
variables:
|
||||
DAST_AUTO_DEPLOY_IMAGE_VERSION: 'v2.85.0'
|
||||
DAST_AUTO_DEPLOY_IMAGE_VERSION: 'v2.86.0'
|
||||
|
||||
.dast-auto-deploy:
|
||||
image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${DAST_AUTO_DEPLOY_IMAGE_VERSION}"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
variables:
|
||||
AUTO_DEPLOY_IMAGE_VERSION: 'v2.85.0'
|
||||
AUTO_DEPLOY_IMAGE_VERSION: 'v2.86.0'
|
||||
|
||||
.auto-deploy:
|
||||
image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${AUTO_DEPLOY_IMAGE_VERSION}"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
variables:
|
||||
AUTO_DEPLOY_IMAGE_VERSION: 'v2.85.0'
|
||||
AUTO_DEPLOY_IMAGE_VERSION: 'v2.86.0'
|
||||
|
||||
.auto-deploy:
|
||||
image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${AUTO_DEPLOY_IMAGE_VERSION}"
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ module Gitlab
|
|||
state :finished, value: 3
|
||||
state :failed, value: 4
|
||||
state :finalizing, value: 5
|
||||
state :finalized, value: 6
|
||||
|
||||
event :pause do
|
||||
transition [:active, :paused] => :paused
|
||||
|
|
@ -79,6 +80,10 @@ module Gitlab
|
|||
transition any => :finalizing
|
||||
end
|
||||
|
||||
event :confirm_finalize do
|
||||
transition [:finalized, :finished] => :finalized
|
||||
end
|
||||
|
||||
before_transition any => :finished do |migration|
|
||||
migration.finished_at = Time.current if migration.respond_to?(:finished_at)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -216,11 +216,19 @@ module Gitlab
|
|||
|
||||
return Gitlab::AppLogger.warn "Could not find batched background migration for the given configuration: #{configuration}" if migration.nil?
|
||||
|
||||
return if migration.finished?
|
||||
return if migration.finalized?
|
||||
|
||||
if migration.finished?
|
||||
migration.confirm_finalize!
|
||||
return
|
||||
end
|
||||
|
||||
finalize_batched_background_migration(job_class_name: job_class_name, table_name: table_name, column_name: column_name, job_arguments: job_arguments) if finalize
|
||||
|
||||
return if migration.reload.finished? # rubocop:disable Cop/ActiveRecordAssociationReload
|
||||
if migration.reload.finished? # rubocop:disable Cop/ActiveRecordAssociationReload -- TODO: ensure that we have latest version of the batched migration
|
||||
migration.confirm_finalize!
|
||||
return
|
||||
end
|
||||
|
||||
raise "Expected batched background migration for the given configuration to be marked as 'finished', " \
|
||||
"but it is '#{migration.status_name}':" \
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ module Gitlab
|
|||
KubernetesAgentCounter,
|
||||
NoteCounter,
|
||||
SearchCounter,
|
||||
ServiceUsageDataCounter,
|
||||
WebIdeCounter,
|
||||
WikiPageCounter,
|
||||
SnippetCounter,
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab::UsageDataCounters
|
||||
class ServiceUsageDataCounter < BaseCounter
|
||||
KNOWN_EVENTS = %w[download_payload_click].freeze
|
||||
PREFIX = 'service_usage_data'
|
||||
end
|
||||
end
|
||||
|
|
@ -7,4 +7,5 @@
|
|||
# NEW_KEY_2: LEGACY_KEY_2
|
||||
# ...
|
||||
#
|
||||
'{event_counters}_usage_data_download_payload_clicked': USAGE_SERVICE_USAGE_DATA_DOWNLOAD_PAYLOAD_CLICK
|
||||
'{event_counters}_web_ide_viewed': WEB_IDE_VIEWS_COUNT
|
||||
|
|
|
|||
|
|
@ -34800,6 +34800,9 @@ msgstr ""
|
|||
msgid "Organization|An error occurred deleting the project. Please refresh the page to try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "Organization|An error occurred loading organizations. Please refresh the page to try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -42752,6 +42755,9 @@ msgstr ""
|
|||
msgid "Runners|Available to all projects and subgroups in the group"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Before you begin"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Can run untagged jobs"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -42868,6 +42874,12 @@ msgstr ""
|
|||
msgid "Runners|Enable stale runner cleanup?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Ensure that %{linkStart}billing is enabled for your Google Cloud project%{linkEnd}."
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Ensure you have the %{linkStart}Owner%{linkEnd} IAM role on your Google Cloud project."
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Enter the job timeout in seconds. Must be a minimum of 600 seconds."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -43464,6 +43476,9 @@ msgstr ""
|
|||
msgid "Runners|This step creates the required infrastructure in Google Cloud, installs GitLab Runner, and registers it to this GitLab project. "
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|To follow the setup instructions, %{gcloudLinkStart}install the Google Cloud CLI%{gcloudLinkEnd} and %{terraformLinkStart}install Terraform%{terraformLinkEnd}."
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|To improve security, use a dedicated project for CI/CD, separate from resources and identity management projects. %{linkStart}Where’s my project ID in Google Cloud?%{linkEnd}"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@
|
|||
"@gitlab/cluster-client": "^2.1.0",
|
||||
"@gitlab/favicon-overlay": "2.0.0",
|
||||
"@gitlab/fonts": "^1.3.0",
|
||||
"@gitlab/svgs": "3.86.0",
|
||||
"@gitlab/svgs": "3.88.0",
|
||||
"@gitlab/ui": "77.1.0",
|
||||
"@gitlab/visual-review-tools": "1.7.3",
|
||||
"@gitlab/web-ide": "^0.0.1-dev-20240226152102",
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ gem 'gitlab-qa', '~> 14', '>= 14.2.1', require: 'gitlab/qa'
|
|||
gem 'gitlab_quality-test_tooling', '~> 1.11.0', require: false
|
||||
gem 'gitlab-utils', path: '../gems/gitlab-utils'
|
||||
gem 'activesupport', '~> 7.0.8.1' # This should stay in sync with the root's Gemfile
|
||||
gem 'allure-rspec', '~> 2.24.0'
|
||||
gem 'allure-rspec', '~> 2.24.1'
|
||||
gem 'capybara', '~> 3.40.0'
|
||||
gem 'capybara-screenshot', '~> 1.0.26'
|
||||
gem 'rake', '~> 13', '>= 13.1.0'
|
||||
|
|
|
|||
|
|
@ -29,10 +29,10 @@ GEM
|
|||
rack-test (>= 1.1.0, < 2.0)
|
||||
rest-client (>= 2.0.2, < 3.0)
|
||||
rspec (~> 3.8)
|
||||
allure-rspec (2.24.0)
|
||||
allure-ruby-commons (= 2.24.0)
|
||||
allure-rspec (2.24.1)
|
||||
allure-ruby-commons (= 2.24.1)
|
||||
rspec-core (>= 3.8, < 4)
|
||||
allure-ruby-commons (2.24.0)
|
||||
allure-ruby-commons (2.24.1)
|
||||
mime-types (>= 3.3, < 4)
|
||||
require_all (>= 2, < 4)
|
||||
rspec-expectations (~> 3.12)
|
||||
|
|
@ -347,7 +347,7 @@ PLATFORMS
|
|||
DEPENDENCIES
|
||||
activesupport (~> 7.0.8.1)
|
||||
airborne (~> 0.3.7)
|
||||
allure-rspec (~> 2.24.0)
|
||||
allure-rspec (~> 2.24.1)
|
||||
capybara (~> 3.40.0)
|
||||
capybara-screenshot (~> 1.0.26)
|
||||
chemlab (~> 0.11, >= 0.11.1)
|
||||
|
|
|
|||
|
|
@ -120,14 +120,21 @@ RSpec.describe Admin::ApplicationSettingsController, :do_not_mock_admin_mode_set
|
|||
end
|
||||
|
||||
describe 'usage data counter' do
|
||||
let(:counter) { Gitlab::UsageDataCounters::ServiceUsageDataCounter }
|
||||
it_behaves_like 'internal event tracking' do
|
||||
let(:event) { 'usage_data_download_payload_clicked' }
|
||||
let(:user) { admin }
|
||||
let(:project) { nil }
|
||||
let(:namespace) { nil }
|
||||
|
||||
it 'incremented when json generated' do
|
||||
expect { get :usage_data, format: :json }.to change { counter.read(:download_payload_click) }.by(1)
|
||||
subject(:track_event) { get :usage_data, format: :json }
|
||||
end
|
||||
|
||||
it 'not incremented when html format requested' do
|
||||
expect { get :usage_data }.not_to change { counter.read(:download_payload_click) }
|
||||
context 'with html format requested' do
|
||||
it 'not incremented when html format requested' do
|
||||
expect(Gitlab::InternalEvents).not_to receive(:track_event)
|
||||
|
||||
get :usage_data, format: :html
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,214 @@
|
|||
import { GlButton } from '@gitlab/ui';
|
||||
import Vue from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { createAlert } from '~/alert';
|
||||
import { DEFAULT_PER_PAGE } from '~/api';
|
||||
import { organizations as nodes, pageInfo, pageInfoEmpty } from '~/organizations/mock_data';
|
||||
import organizationsQuery from '~/admin/organizations/index/graphql/queries/organizations.query.graphql';
|
||||
import OrganizationsIndexApp from '~/admin/organizations/index/components/app.vue';
|
||||
import OrganizationsView from '~/organizations/shared/components/organizations_view.vue';
|
||||
import { MOCK_NEW_ORG_URL } from 'jest/organizations/shared/mock_data';
|
||||
|
||||
jest.mock('~/alert');
|
||||
|
||||
Vue.use(VueApollo);
|
||||
|
||||
describe('AdminOrganizationsIndexApp', () => {
|
||||
let wrapper;
|
||||
let mockApollo;
|
||||
|
||||
const organizations = {
|
||||
nodes,
|
||||
pageInfo,
|
||||
};
|
||||
|
||||
const organizationEmpty = {
|
||||
nodes: [],
|
||||
pageInfo: pageInfoEmpty,
|
||||
};
|
||||
|
||||
const successHandler = jest.fn().mockResolvedValue({
|
||||
data: {
|
||||
organizations,
|
||||
},
|
||||
});
|
||||
|
||||
const createComponent = (handler = successHandler) => {
|
||||
mockApollo = createMockApollo([[organizationsQuery, handler]]);
|
||||
|
||||
wrapper = shallowMountExtended(OrganizationsIndexApp, {
|
||||
apolloProvider: mockApollo,
|
||||
provide: {
|
||||
newOrganizationUrl: MOCK_NEW_ORG_URL,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
mockApollo = null;
|
||||
});
|
||||
|
||||
// Finders
|
||||
const findOrganizationHeaderText = () => wrapper.findByRole('heading', { name: 'Organizations' });
|
||||
const findNewOrganizationButton = () => wrapper.findComponent(GlButton);
|
||||
const findOrganizationsView = () => wrapper.findComponent(OrganizationsView);
|
||||
|
||||
// Assertions
|
||||
const itRendersHeaderText = () => {
|
||||
it('renders the header text', () => {
|
||||
expect(findOrganizationHeaderText().exists()).toBe(true);
|
||||
});
|
||||
};
|
||||
|
||||
const itRendersNewOrganizationButton = () => {
|
||||
it('render new organization button with correct link', () => {
|
||||
expect(findNewOrganizationButton().attributes('href')).toBe(MOCK_NEW_ORG_URL);
|
||||
});
|
||||
};
|
||||
|
||||
const itDoesNotRenderErrorMessage = () => {
|
||||
it('does not render an error message', () => {
|
||||
expect(createAlert).not.toHaveBeenCalled();
|
||||
});
|
||||
};
|
||||
|
||||
const itDoesNotRenderHeaderText = () => {
|
||||
it('does not render the header text', () => {
|
||||
expect(findOrganizationHeaderText().exists()).toBe(false);
|
||||
});
|
||||
};
|
||||
|
||||
const itDoesNotRenderNewOrganizationButton = () => {
|
||||
it('does not render new organization button', () => {
|
||||
expect(findNewOrganizationButton().exists()).toBe(false);
|
||||
});
|
||||
};
|
||||
|
||||
describe('when API call is loading', () => {
|
||||
beforeEach(() => {
|
||||
createComponent(jest.fn().mockReturnValue(new Promise(() => {})));
|
||||
});
|
||||
|
||||
itRendersHeaderText();
|
||||
itRendersNewOrganizationButton();
|
||||
itDoesNotRenderErrorMessage();
|
||||
|
||||
it('renders the organizations view with loading prop set to true', () => {
|
||||
expect(findOrganizationsView().props('loading')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when API call is successful', () => {
|
||||
beforeEach(async () => {
|
||||
createComponent();
|
||||
await waitForPromises();
|
||||
});
|
||||
|
||||
itRendersHeaderText();
|
||||
itRendersNewOrganizationButton();
|
||||
itDoesNotRenderErrorMessage();
|
||||
|
||||
it('passes organizations to view component', () => {
|
||||
expect(findOrganizationsView().props()).toMatchObject({
|
||||
loading: false,
|
||||
organizations,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when API call is successful and returns no organizations', () => {
|
||||
beforeEach(async () => {
|
||||
createComponent(
|
||||
jest.fn().mockResolvedValue({
|
||||
data: {
|
||||
organizations: organizationEmpty,
|
||||
},
|
||||
}),
|
||||
);
|
||||
await waitForPromises();
|
||||
});
|
||||
|
||||
itDoesNotRenderHeaderText();
|
||||
itDoesNotRenderNewOrganizationButton();
|
||||
itDoesNotRenderErrorMessage();
|
||||
|
||||
it('renders view component with correct organizations and loading props', () => {
|
||||
expect(findOrganizationsView().props()).toMatchObject({
|
||||
loading: false,
|
||||
organizations: organizationEmpty,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when API call is not successful', () => {
|
||||
const error = new Error();
|
||||
|
||||
beforeEach(async () => {
|
||||
createComponent(jest.fn().mockRejectedValue(error));
|
||||
await waitForPromises();
|
||||
});
|
||||
|
||||
itDoesNotRenderHeaderText();
|
||||
itDoesNotRenderNewOrganizationButton();
|
||||
|
||||
it('renders view component with correct organizations and loading props', () => {
|
||||
expect(findOrganizationsView().props()).toMatchObject({
|
||||
loading: false,
|
||||
organizations: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('renders error message', () => {
|
||||
expect(createAlert).toHaveBeenCalledWith({
|
||||
message: 'An error occurred loading organizations. Please refresh the page to try again.',
|
||||
error,
|
||||
captureError: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when view component emits `next` event', () => {
|
||||
const endCursor = 'mockEndCursor';
|
||||
|
||||
beforeEach(async () => {
|
||||
createComponent();
|
||||
await waitForPromises();
|
||||
});
|
||||
|
||||
it('calls GraphQL query with correct pageInfo variables', async () => {
|
||||
findOrganizationsView().vm.$emit('next', endCursor);
|
||||
await waitForPromises();
|
||||
|
||||
expect(successHandler).toHaveBeenCalledWith({
|
||||
first: DEFAULT_PER_PAGE,
|
||||
after: endCursor,
|
||||
last: null,
|
||||
before: null,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when view component emits `prev` event', () => {
|
||||
const startCursor = 'mockStartCursor';
|
||||
|
||||
beforeEach(async () => {
|
||||
createComponent();
|
||||
await waitForPromises();
|
||||
});
|
||||
|
||||
it('calls GraphQL query with correct pageInfo variables', async () => {
|
||||
findOrganizationsView().vm.$emit('prev', startCursor);
|
||||
await waitForPromises();
|
||||
|
||||
expect(successHandler).toHaveBeenCalledWith({
|
||||
first: null,
|
||||
after: null,
|
||||
last: DEFAULT_PER_PAGE,
|
||||
before: startCursor,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -346,7 +346,7 @@ export const runnerInstallHelpPage = 'https://docs.example.com/runner/install/';
|
|||
|
||||
export const googleCloudRunnerProvisionResponse = {
|
||||
__typename: 'Project',
|
||||
id: 'gid://gitlab/Project/23',
|
||||
id: 'gid://gitlab/Project/1',
|
||||
runnerCloudProvisioning: {
|
||||
__typename: 'CiRunnerGoogleCloudProvisioning',
|
||||
projectSetupShellScript: '#!/bin/bash echo "hello world!"',
|
||||
|
|
@ -355,15 +355,13 @@ export const googleCloudRunnerProvisionResponse = {
|
|||
__typename: 'CiRunnerCloudProvisioningStep',
|
||||
title: 'Save the Terraform script to a file',
|
||||
languageIdentifier: 'terraform',
|
||||
instructions:
|
||||
'terraform {\n required_version = "~> 1.5"\n\n required_providers {\n google = {\n source = "hashicorp/google"\n version = "~> 5.12"\n }\n\n tls = {\n source = "hashicorp/tls"\n version = "~> 4.0"\n }\n }\n}\n\nlocals {\n google_project = "dev-gcp-s3c-integrati-9abafed1"\n google_region = "us-central1"\n google_zone = "us-central1-a"\n}\n\nprovider "google" {\n project = local.google_project\n region = local.google_region\n zone = local.google_zone\n}\n\nvariable "runner_token" {\n type = string\n sensitive = true\n}\n\n# Added available customisation\nmodule "runner-deployment" {\n source = "git::https://gitlab.com/gitlab-org/ci-cd/runner-tools/grit.git//scenarios/google/linux/docker-autoscaler-default"\n\n google_project = local.google_project\n google_region = local.google_region\n google_zone = local.google_zone\n\n name = "grit-BQQkbs5X_"\n\n gitlab_url = "http://gdk.test:3000"\n\n runner_token = var.runner_token\n\n ephemeral_runner = {\n # disk_type = "pd-ssd"\n # disk_size = 50\n machine_type = "n2d-standard-2"\n # source_image = "projects/cos-cloud/global/images/family/cos-stable"\n }\n}\n\noutput "runner-manager-external-ip" {\n value = module.runner-deployment.runner_manager_external_ip\n}\n',
|
||||
instructions: 'terraform...',
|
||||
},
|
||||
{
|
||||
__typename: 'CiRunnerCloudProvisioningStep',
|
||||
title: 'Apply the Terraform script',
|
||||
languageIdentifier: 'shell',
|
||||
instructions:
|
||||
'#!/bin/bash\n\nterraform plan -var gitlab_runner="glrt-BQQkbs5X_f-ys6wLEy2V" -out plan.out\nterraform apply plan.out\n',
|
||||
instructions: '#!/bin/bash\n\nterraform plan...',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import { nextTick } from 'vue';
|
|||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from 'axios';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import { CONTENT_EDITOR_PASTE } from '~/vue_shared/constants';
|
||||
import markdownEditorEventHub from '~/vue_shared/components/markdown/eventhub';
|
||||
import ContentEditor from '~/content_editor/components/content_editor.vue';
|
||||
import ContentEditorAlert from '~/content_editor/components/content_editor_alert.vue';
|
||||
import ContentEditorProvider from '~/content_editor/components/content_editor_provider.vue';
|
||||
|
|
@ -17,6 +19,7 @@ import LoadingIndicator from '~/content_editor/components/loading_indicator.vue'
|
|||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { KEYDOWN_EVENT } from '~/content_editor/constants';
|
||||
import EditorModeSwitcher from '~/vue_shared/components/markdown/editor_mode_switcher.vue';
|
||||
import { mockChainedCommands } from '../test_utils';
|
||||
|
||||
describe('ContentEditor', () => {
|
||||
let wrapper;
|
||||
|
|
@ -290,4 +293,29 @@ describe('ContentEditor', () => {
|
|||
|
||||
expect(wrapper.findComponent(EditorModeSwitcher).exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('pastes content when CONTENT_EDITOR_READY_PASTE event is emitted', async () => {
|
||||
const markdown = 'hello world';
|
||||
|
||||
createWrapper({ markdown });
|
||||
|
||||
renderMarkdown.mockResolvedValueOnce(markdown);
|
||||
|
||||
await waitForPromises();
|
||||
|
||||
const editorContent = findEditorContent();
|
||||
const commands = mockChainedCommands(editorContent.props('editor'), [
|
||||
'focus',
|
||||
'pasteContent',
|
||||
'run',
|
||||
]);
|
||||
|
||||
markdownEditorEventHub.$emit(CONTENT_EDITOR_PASTE, 'Paste content');
|
||||
|
||||
await waitForPromises();
|
||||
|
||||
expect(commands.focus).toHaveBeenCalled();
|
||||
expect(commands.pasteContent).toHaveBeenCalledWith('Paste content');
|
||||
expect(commands.run).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import { DEFAULT_PER_PAGE } from '~/api';
|
|||
import { organizations as nodes, pageInfo, pageInfoEmpty } from '~/organizations/mock_data';
|
||||
import organizationsQuery from '~/organizations/shared/graphql/queries/organizations.query.graphql';
|
||||
import OrganizationsIndexApp from '~/organizations/index/components/app.vue';
|
||||
import OrganizationsView from '~/organizations/index/components/organizations_view.vue';
|
||||
import { MOCK_NEW_ORG_URL } from '../mock_data';
|
||||
import OrganizationsView from '~/organizations/shared/components/organizations_view.vue';
|
||||
import { MOCK_NEW_ORG_URL } from '../../shared/mock_data';
|
||||
|
||||
jest.mock('~/alert');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { GlAvatarLabeled } from '@gitlab/ui';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
import OrganizationsListItem from '~/organizations/index/components/organizations_list_item.vue';
|
||||
import OrganizationsListItem from '~/organizations/shared/components/list/organizations_list_item.vue';
|
||||
import { organizations } from '~/organizations/mock_data';
|
||||
|
||||
const MOCK_ORGANIZATION = organizations[0];
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import { GlKeysetPagination } from '@gitlab/ui';
|
||||
import { omit } from 'lodash';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import OrganizationsList from '~/organizations/index/components/organizations_list.vue';
|
||||
import OrganizationsListItem from '~/organizations/index/components/organizations_list_item.vue';
|
||||
import OrganizationsList from '~/organizations/shared/components/list/organizations_list.vue';
|
||||
import OrganizationsListItem from '~/organizations/shared/components/list/organizations_list_item.vue';
|
||||
import { organizations as nodes, pageInfo, pageInfoOnePage } from '~/organizations/mock_data';
|
||||
|
||||
describe('OrganizationsList', () => {
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import { GlLoadingIcon, GlEmptyState } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import { organizations } from '~/organizations/mock_data';
|
||||
import OrganizationsView from '~/organizations/index/components/organizations_view.vue';
|
||||
import OrganizationsList from '~/organizations/index/components/organizations_list.vue';
|
||||
import OrganizationsView from '~/organizations/shared/components/organizations_view.vue';
|
||||
import OrganizationsList from '~/organizations/shared/components/list/organizations_list.vue';
|
||||
import { MOCK_NEW_ORG_URL, MOCK_ORG_EMPTY_STATE_SVG } from '../mock_data';
|
||||
|
||||
describe('OrganizationsView', () => {
|
||||
|
|
@ -302,4 +302,15 @@ RSpec.describe Organizations::OrganizationHelper, feature_category: :cell do
|
|||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#admin_organizations_index_app_data' do
|
||||
it 'returns expected json' do
|
||||
expect(Gitlab::Json.parse(helper.admin_organizations_index_app_data)).to eq(
|
||||
{
|
||||
'new_organization_url' => new_organization_path,
|
||||
'organizations_empty_state_svg_path' => organizations_empty_state_svg_path
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigration, type: :m
|
|||
end
|
||||
|
||||
describe '.valid_status' do
|
||||
valid_status = [:paused, :active, :finished, :failed, :finalizing]
|
||||
valid_status = [:paused, :active, :finished, :failed, :finalizing, :finalized]
|
||||
|
||||
it 'returns valid status' do
|
||||
expect(described_class.valid_status).to eq(valid_status)
|
||||
|
|
|
|||
|
|
@ -533,6 +533,25 @@ RSpec.describe Gitlab::Database::Migrations::BatchedBackgroundMigrationHelpers,
|
|||
end
|
||||
end
|
||||
|
||||
context 'when the migration is `finished`' do
|
||||
let(:finished_status) { 3 }
|
||||
let(:finalized_status) { 6 }
|
||||
let(:migration_record) { create(:batched_background_migration, :finished) }
|
||||
|
||||
let(:configuration) do
|
||||
{
|
||||
job_class_name: migration_record.job_class_name,
|
||||
table_name: migration_record.table_name,
|
||||
column_name: migration_record.column_name,
|
||||
job_arguments: migration_record.job_arguments
|
||||
}
|
||||
end
|
||||
|
||||
it 'updates the status to `finalized`' do
|
||||
expect { ensure_batched_background_migration_is_finished }.to change { migration_record.reload.status }.from(finished_status).to(finalized_status)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when within transaction' do
|
||||
before do
|
||||
allow(migration).to receive(:transaction_open?).and_return(true)
|
||||
|
|
|
|||
|
|
@ -14,11 +14,14 @@ RSpec.describe Gitlab::UsageDataCounters::RedisCounter, :clean_gitlab_redis_shar
|
|||
end.to change { subject.total_count(redis_key) }.by(1)
|
||||
end
|
||||
|
||||
context 'with aliased legacy key' do
|
||||
let(:redis_key) { '{event_counters}_web_ide_viewed' }
|
||||
context 'for every aliased legacy key' do
|
||||
let(:key_overrides) { YAML.safe_load(File.read(described_class::KEY_OVERRIDES_PATH)) }
|
||||
|
||||
it 'counter is increased for a legacy key' do
|
||||
expect { subject.increment(redis_key) }.to change { subject.total_count('WEB_IDE_VIEWS_COUNT') }.by(1)
|
||||
key_overrides.each do |alias_key, legacy_key|
|
||||
expect { subject.increment(alias_key) }.to change { subject.total_count(legacy_key) }.by(1),
|
||||
"Incrementing #{alias_key} did not increase #{legacy_key}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::UsageDataCounters::ServiceUsageDataCounter do
|
||||
it_behaves_like 'a redis usage counter', 'Service Usage Data', :download_payload_click
|
||||
end
|
||||
|
|
@ -7,7 +7,8 @@ require_migration!
|
|||
RSpec.describe FinalizeNullifyCreatorIdOfOrphanedProjects, :migration, feature_category: :groups_and_projects do
|
||||
let(:batched_migrations) { table(:batched_background_migrations) }
|
||||
let(:batch_failed_status) { 2 }
|
||||
let(:batch_finalized_status) { 3 }
|
||||
let(:batch_finalized_status) { 6 }
|
||||
let(:job_finished_status) { 3 }
|
||||
|
||||
let!(:migration) { described_class::MIGRATION }
|
||||
|
||||
|
|
@ -19,8 +20,8 @@ RSpec.describe FinalizeNullifyCreatorIdOfOrphanedProjects, :migration, feature_c
|
|||
|
||||
migration_record.reload
|
||||
failed_job.reload
|
||||
end.to change { migration_record.status }.from(migration_record.status).to(3).and(
|
||||
change { failed_job.status }.from(batch_failed_status).to(batch_finalized_status)
|
||||
end.to change { migration_record.status }.from(migration_record.status).to(batch_finalized_status).and(
|
||||
change { failed_job.status }.from(batch_failed_status).to(job_finished_status)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ require_migration!
|
|||
RSpec.describe FinalizeEncryptCiTriggerToken, migration: :gitlab_ci, feature_category: :continuous_integration do
|
||||
let(:batched_migrations) { table(:batched_background_migrations) }
|
||||
let(:batch_failed_status) { 2 }
|
||||
let(:batch_finalized_status) { 3 }
|
||||
let(:batch_finalized_status) { 6 }
|
||||
let(:job_finished_status) { 3 }
|
||||
|
||||
let!(:migration) { described_class::MIGRATION }
|
||||
|
||||
|
|
@ -85,7 +86,7 @@ RSpec.describe FinalizeEncryptCiTriggerToken, migration: :gitlab_ci, feature_cat
|
|||
end.to(
|
||||
change { migration_record.status }.from(status).to(batch_finalized_status)
|
||||
.and(
|
||||
change { failed_job.status }.from(batch_failed_status).to(batch_finalized_status)
|
||||
change { failed_job.status }.from(batch_failed_status).to(job_finished_status)
|
||||
)
|
||||
)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ RSpec.describe EnsureIncidentWorkItemTypeBackfillIsFinished, :migration, feature
|
|||
let(:batched_migrations) { table(:batched_background_migrations) }
|
||||
let(:work_item_types) { table(:work_item_types) }
|
||||
let(:batch_failed_status) { 2 }
|
||||
let(:batch_finalized_status) { 6 }
|
||||
|
||||
let!(:migration_class) { described_class::MIGRATION }
|
||||
|
||||
|
|
@ -68,7 +69,7 @@ RSpec.describe EnsureIncidentWorkItemTypeBackfillIsFinished, :migration, feature
|
|||
migrate!
|
||||
|
||||
backfill_migration.reload
|
||||
end.to change { backfill_migration.status }.from(status).to(3)
|
||||
end.to change { backfill_migration.status }.from(status).to(batch_finalized_status)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ RSpec.describe FinalizeBackfillResourceLinkEvents, feature_category: :team_plann
|
|||
migrate!
|
||||
|
||||
batched_migration.reload
|
||||
end.to change { batched_migration.status }.from(status).to(3)
|
||||
end.to change { batched_migration.status }.from(status).to(6)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6713,7 +6713,6 @@
|
|||
- './spec/lib/gitlab/usage_data_counters/quick_action_activity_unique_counter_spec.rb'
|
||||
- './spec/lib/gitlab/usage_data_counters/redis_counter_spec.rb'
|
||||
- './spec/lib/gitlab/usage_data_counters/search_counter_spec.rb'
|
||||
- './spec/lib/gitlab/usage_data_counters/service_usage_data_counter_spec.rb'
|
||||
- './spec/lib/gitlab/usage_data_counters/snippet_counter_spec.rb'
|
||||
- './spec/lib/gitlab/usage_data_counters/source_code_counter_spec.rb'
|
||||
- './spec/lib/gitlab/usage_data_counters_spec.rb'
|
||||
|
|
|
|||
|
|
@ -1321,10 +1321,10 @@
|
|||
stylelint-declaration-strict-value "1.10.4"
|
||||
stylelint-scss "6.0.0"
|
||||
|
||||
"@gitlab/svgs@3.86.0":
|
||||
version "3.86.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.86.0.tgz#d6546231fc3b1a7ac24dd0cfe9b6f7facf7f3bff"
|
||||
integrity sha512-+RDeJ6z05AXWAhCHC/4H4CKdw/nQgGIKBph2nsJ7/w0CJldnh/4GO5op8LmVaUVNyHt02AKbSJOnmen1LL+b8A==
|
||||
"@gitlab/svgs@3.88.0":
|
||||
version "3.88.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.88.0.tgz#f57bd0ea94866038b19d94a2fa815d54f10c2c09"
|
||||
integrity sha512-j2C+Ddt2LcJTf2hQZZ6sybsiQ/mMnZG4wKmJfM5YjXR5qPVaAUyH+MHnvPGcHnt+tMYr2P52zlcpsQa6WB5xeQ==
|
||||
|
||||
"@gitlab/ui@77.1.0":
|
||||
version "77.1.0"
|
||||
|
|
|
|||
Loading…
Reference in New Issue