Skip to content
Snippets Groups Projects
Commit a62c2305 authored by 🤖 GitLab Bot 🤖's avatar 🤖 GitLab Bot 🤖
Browse files

Automatic merge of gitlab-org/gitlab master

parents 364956fd ba34a39c
No related branches found
No related tags found
No related merge requests found
Showing
with 195 additions and 134 deletions
......@@ -413,6 +413,7 @@ export default {
:aria-label="$options.i18n.newIssue"
:title="$options.i18n.newIssue"
class="no-drag"
size="small"
icon="plus"
@click="showNewIssueForm"
/>
......@@ -424,6 +425,7 @@ export default {
:aria-label="$options.i18n.newEpic"
:title="$options.i18n.newEpic"
class="no-drag"
size="small"
icon="plus"
@click="showNewEpicForm"
/>
......@@ -434,6 +436,7 @@ export default {
v-gl-tooltip.hover
:aria-label="$options.i18n.listSettings"
class="no-drag"
size="small"
:title="$options.i18n.listSettings"
icon="settings"
@click="openSidebarSettings"
......
......@@ -3,11 +3,11 @@ import Visibility from 'visibilityjs';
import Vue from 'vue';
import { createAlert } from '~/flash';
import AccessorUtilities from '~/lib/utils/accessor';
import initProjectSelectDropdown from '~/project_select';
import Poll from '~/lib/utils/poll';
import { s__ } from '~/locale';
import PersistentUserCallout from '~/persistent_user_callout';
import initSettingsPanels from '~/settings_panels';
import { initProjectSelects } from '~/vue_shared/components/entity_select/init_project_selects';
import RemoveClusterConfirmation from './components/remove_cluster_confirmation.vue';
import ClustersService from './services/clusters_service';
import ClustersStore from './stores/clusters_store';
......@@ -62,7 +62,7 @@ export default class Clusters {
this.errorReasonContainer = this.errorContainer.querySelector('.js-error-reason');
this.tokenField = document.querySelector('.js-cluster-token');
initProjectSelectDropdown();
initProjectSelects();
Clusters.initDismissableCallout();
initSettingsPanels();
......
......@@ -20,6 +20,8 @@ const PERSISTENT_USER_CALLOUTS = [
'.js-web-hook-disabled-callout',
'.js-merge-request-settings-callout',
'.js-ultimate-feature-removal-banner',
'.js-geo-enable-hashed-storage-callout',
'.js-geo-migrate-hashed-storage-callout',
];
const initCallouts = () => {
......
......@@ -170,6 +170,9 @@ export default {
<template>
<gl-form-group :label="label">
<slot name="error"></slot>
<template v-if="Boolean($scopedSlots.label)" #label>
<slot name="label"></slot>
</template>
<gl-collapsible-listbox
ref="listbox"
v-model="selected"
......
......@@ -11,8 +11,18 @@ export const initProjectSelects = () => {
}
document.querySelectorAll(SELECTOR).forEach((el) => {
const { label, inputName, inputId, groupId, selected: initialSelection } = el.dataset;
const clearable = parseBoolean(el.dataset.clearable);
const {
label,
inputName,
inputId,
groupId,
userId,
orderBy,
selected: initialSelection,
} = el.dataset;
const includeSubgroups = parseBoolean(el.dataset.includeSubgroups);
const membership = parseBoolean(el.dataset.membership);
const hasHtmlLabel = parseBoolean(el.dataset.hasHtmlLabel);
return new Vue({
el,
......@@ -21,11 +31,15 @@ export const initProjectSelects = () => {
return createElement(ProjectSelect, {
props: {
label,
hasHtmlLabel,
inputName,
inputId,
groupId,
userId,
orderBy,
includeSubgroups,
membership,
initialSelection,
clearable,
},
});
},
......
......@@ -2,6 +2,7 @@
import { GlAlert } from '@gitlab/ui';
import * as Sentry from '@sentry/browser';
import Api from '~/api';
import SafeHtml from '~/vue_shared/directives/safe_html';
import {
PROJECT_TOGGLE_TEXT,
PROJECT_HEADER_TEXT,
......@@ -15,11 +16,19 @@ export default {
GlAlert,
EntitySelector,
},
directives: {
SafeHtml,
},
props: {
label: {
type: String,
required: true,
},
hasHtmlLabel: {
type: Boolean,
required: false,
default: false,
},
inputName: {
type: String,
required: true,
......@@ -30,18 +39,34 @@ export default {
},
groupId: {
type: String,
required: true,
required: false,
default: null,
},
initialSelection: {
userId: {
type: String,
required: false,
default: null,
},
clearable: {
includeSubgroups: {
type: Boolean,
required: false,
default: false,
},
membership: {
type: Boolean,
required: false,
default: false,
},
orderBy: {
type: String,
required: false,
default: 'similarity',
},
initialSelection: {
type: String,
required: false,
default: null,
},
},
data() {
return {
......@@ -52,12 +77,39 @@ export default {
async fetchProjects(searchString = '') {
let projects = [];
try {
const { data = [] } = await Api.groupProjects(this.groupId, searchString, {
with_shared: true,
include_subgroups: false,
order_by: 'similarity',
simple: true,
});
const { data = [] } = await (() => {
const commonParams = {
order_by: this.orderBy,
simple: true,
};
if (this.groupId) {
return Api.groupProjects(this.groupId, searchString, {
...commonParams,
with_shared: true,
include_subgroups: this.includeSubgroups,
simple: true,
});
}
// Note: the whole userId handling supports a single project selector that is slated for
// removal. Once we have deleted app/views/clusters/clusters/_advanced_settings.html.haml,
// we should be able to clean this up.
if (this.userId) {
return Api.userProjects(
this.userId,
searchString,
{
with_shared: true,
include_subgroups: this.includeSubgroups,
},
(res) => ({ data: res }),
);
}
return Api.projects(searchString, {
...commonParams,
membership: this.membership,
});
})();
projects = data.map((item) => ({
text: item.name_with_namespace || item.name,
value: String(item.id),
......@@ -98,12 +150,15 @@ export default {
:input-name="inputName"
:input-id="inputId"
:initial-selection="initialSelection"
:clearable="clearable"
:header-text="$options.i18n.selectProject"
:default-toggle-text="$options.i18n.searchForProject"
:fetch-items="fetchProjects"
:fetch-initial-selection-text="fetchProjectName"
clearable
>
<template v-if="hasHtmlLabel" #label>
<span v-safe-html="label"></span>
</template>
<template #error>
<gl-alert v-if="errorMessage" class="gl-mb-3" variant="danger" @dismiss="dismissError">{{
errorMessage
......
......@@ -25,10 +25,6 @@ def show_gcp_signup_offer?
!user_dismissed?(GCP_SIGNUP_OFFER)
end
def render_flash_user_callout(flash_type, message, feature_name)
render 'shared/flash_user_callout', flash_type: flash_type, message: message, feature_name: feature_name
end
def render_dashboard_ultimate_trial(user)
end
......
......@@ -18,12 +18,18 @@
%h4
= s_('ClusterIntegration|Cluster management project')
%p
= project_select_tag('cluster[management_project_id]', class: 'hidden-filter-value', toggle_class: 'js-project-search js-project-filter js-filter-submit', dropdown_class: 'dropdown-menu-selectable dropdown-menu-project js-filter-submit',
placeholder: _('Select project'), idAttribute: 'id', data: { order_by: 'last_activity_at', idattribute: 'id', simple_filter: true, allow_clear: true, include_groups: false, include_projects_in_subgroups: true, group_id: group_id, user_id: user_id }, value: @cluster.management_project_id)
.text-muted
= html_escape(s_('ClusterIntegration|A cluster management project can be used to run deployment jobs with Kubernetes %{code_open}cluster-admin%{code_close} privileges.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
= link_to _('More information'), help_page_path('user/clusters/management_project.md'), target: '_blank', rel: 'noopener noreferrer'
.js-vue-project-select{ data: { label: _('Select a cluster management project'),
input_name: 'cluster[management_project_id]',
input_id: 'cluster[management_project_id]',
order_by: 'last_activity_at',
group_id: group_id,
user_id: user_id,
include_subgroups: true.to_s,
membership: true.to_s,
selected: @cluster.management_project_id } }
%p.text-muted.gl-mt-n5
= html_escape(s_('ClusterIntegration|A cluster management project can be used to run deployment jobs with Kubernetes %{code_open}cluster-admin%{code_close} privileges.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
= link_to _('More information'), help_page_path('user/clusters/management_project.md'), target: '_blank', rel: 'noopener noreferrer'
= field.submit _('Save changes'), pajamas_button: true
.sub-section.form-group
......
- callout_data = { uid: "callout_feature_#{feature_name}_dismissed", feature_id: feature_name, dismiss_endpoint: callouts_path }
- extra_flash_class = local_assigns.fetch(:extra_flash_class, nil)
.flash-container.flash-container-page.user-callout{ data: callout_data }
-# We currently only support `alert`, `warning`, `notice`, `success`
%div{ class: "flash-#{flash_type}" }
%div{ class: "#{container_class unless fluid_layout} #{extra_flash_class unless @no_container} #{@content_class}" }
%span= message
%button.btn.gl-button.btn-default.close.js-close{ type: 'button',
'aria-label' => _('Dismiss') }
= sprite_icon('close', css_class: 'dismiss-icon')
......@@ -30,7 +30,7 @@ To complete this tutorial:
## Create the Google Cloud Workload Identity Pool
[Create a new Google Cloud Workload Identity Pool](https://cloud.google.com/iam/docs/configuring-workload-identity-federation#oidc) with the following options:
[Create a new Google Cloud Workload Identity Pool](https://cloud.google.com/iam/docs/workload-identity-federation-with-other-clouds#oidc) with the following options:
- **Name**: Human-friendly name for the Workload Identity Pool, such as `GitLab`.
- **Pool ID**: Unique ID in the Google Cloud project for the Workload Identity Pool,
......@@ -42,7 +42,7 @@ We recommend creating a single _pool_ per GitLab installation per Google Cloud p
## Create a Workload Identity Provider
[Create a new Google Cloud Workload Identity Provider](https://cloud.google.com/iam/docs/configuring-workload-identity-federation#create_the_workload_identity_pool_and_provider)
[Create a new Google Cloud Workload Identity Provider](https://cloud.google.com/iam/docs/workload-identity-federation-with-other-clouds#create_the_workload_identity_pool_and_provider)
inside the Workload Identity Pool created in the previous step, using the following options:
- **Provider type**: OpenID Connect (OIDC).
......@@ -86,7 +86,7 @@ To grant your GitLab CI/CD job permissions on Google Cloud, you must:
service account on Google Cloud resources. These permissions vary significantly based on
your use case. In general, grant this service account the permissions on your Google Cloud
project and resources you want your GitLab CI/CD job to be able to use. For example, if you needed to upload a file to a Google Cloud Storage bucket in your GitLab CI/CD job, you would grant this Service Account the `roles/storage.objectCreator` role on your Cloud Storage bucket.
1. [Grant the external identity permissions](https://cloud.google.com/iam/docs/using-workload-identity-federation#impersonate)
1. [Grant the external identity permissions](https://cloud.google.com/iam/docs/workload-identity-federation-with-other-clouds#impersonate)
to impersonate that Service Account. This step enables a GitLab CI/CD job to _authorize_
to Google Cloud, via Service Account impersonation. This step grants an IAM permission
_on the Service Account itself_, giving the external identity permissions to act as that
......
......@@ -10,12 +10,16 @@ Members are the users and groups who have access to your project.
Each member gets a role, which determines what they can do in the project.
Project members can:
## Membership types
1. Be [direct members](#add-users-to-a-project) of the project.
1. [Inherit membership](#inherited-membership) of the project from the project's group.
1. Be a member of a group that was [shared](share_project_with_groups.md) with the project.
1. Be a member of a group that was [shared with the project's group](../../group/manage.md#share-a-group-with-another-group).
Users can become members of a group or project in different ways, which define their membership type.
| Membership type | Membership process |
| --------------------------------------------- | ------------------ |
| [Direct](#add-users-to-a-project) | The user is added directly to the current group or project. |
| [Inherited](#inherited-membership) | The user is a member of an ancestor group or project that is added to the current group or project. |
| [Direct shared](share_project_with_groups.md) | The user is a member of a group or project that is shared into the current group or project. |
| [Inherited shared](../../group/manage.md#share-a-group-with-another-group) | The user is a member of an ancestor of a group or project that is shared into the current group or project. |
```mermaid
flowchart RL
......@@ -41,6 +45,28 @@ flowchart RL
G-->|Group C shared with Project A|E
```
### Inherited membership
When your project belongs to a group, project members inherit their role
from the group.
![Project members page](img/project_members_v14_4.png)
In this example:
- Three members have access to the project.
- **User 0** is a Reporter and has inherited their role in the project from the **demo** group,
which contains the project.
- **User 1** belongs directly to the project. In the **Source** column, they are listed
as a **Direct member**.
- **Administrator** is the [Owner](../../permissions.md) and member of all groups.
They have inherited their role in the project from the **demo** group.
If a user is:
- A direct member of a project, the **Expiration** and **Max role** fields can be updated directly on the project.
- An inherited member from a parent group, the **Expiration** and **Max role** fields must be updated on the parent group.
## Add users to a project
> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/247208) in GitLab 13.11 from a form to a modal window [with a flag](../../feature_flags.md). Disabled by default.
......@@ -147,28 +173,6 @@ To import users:
After the success message displays, refresh the page to view the new members.
## Inherited membership
When your project belongs to a group, group members inherit their role
from the group.
![Project members page](img/project_members_v14_4.png)
In this example:
- Three members have access to the project.
- **User 0** is a Reporter and has inherited their role from the **demo** group,
which contains the project.
- **User 1** belongs directly to the project. In the **Source** column, they are listed
as a **Direct member**.
- **Administrator** is the [Owner](../../permissions.md) and member of all groups.
They have inherited their role from the **demo** group.
If a user is a:
- Direct member of a project, the **Expiration** and **Max role** fields can be updated directly on the project.
- Inherited member from a parent group, the **Expiration** and **Max role** fields must be updated on the parent group.
## Remove a member from a project
If a user is:
......
......@@ -35,11 +35,17 @@ Learn more about [how suggested reviewers works and data privacy](data_usage.md)
### Enable suggested reviewers
Project Maintainers or Owners can enable suggested reviewers by visiting the [project settings](../../settings/index.md).
Project Maintainers or Owners can enable suggested reviewers by visiting
the [project settings](../../settings/index.md).
Enabling suggested reviewers will trigger GitLab to create an ML model for your project that will be used to generate reviewers. The larger your project, the longer this can take, but usually, the model will be ready to generate suggestions within a few hours.
Enabling suggested reviewers triggers GitLab to create an ML model for your
project that is used to generate reviewers. The larger your project, the longer
this process can take. Usually, the model is ready to generate suggestions
within a few hours.
No action is required once the feature is enabled. Once the model is ready, recommendations will populate the Reviewer dropdown list in the right-hand sidebar of a merge request with new commits.
No action is required after the feature is enabled. After the model is ready,
recommendations populate the **Reviewer** dropdown list in the right-hand sidebar
of a merge request with new commits.
## Review a merge request
......@@ -147,7 +153,7 @@ To resolve or unresolve a thread when replying to a comment:
Pending comments display information about the action to be taken when the comment is published:
- **{check-circle-filled}** Thread will be resolved.
- **{check-circle-filled}** Thread is resolved.
- **{check-circle}** Thread stays unresolved.
### Add a new comment
......@@ -194,7 +200,7 @@ them a notification email.
## Comment on multiple lines
> - [Introduced](https://gitlab.com/gitlab-org/ux-research/-/issues/870) in GitLab 13.2.
> - [Added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/49875) click-and-drag features in GitLab 13.8.
> - [Added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/49875) select-and-drag features in GitLab 13.8.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/299121) in GitLab 13.9.
When commenting on a diff, you can select which lines of code your comment refers
......
import { initProjectSelects } from '~/vue_shared/components/entity_select/init_project_selects';
import { initGroupSelects } from '~/vue_shared/components/entity_select/init_group_selects';
initGroupSelects();
initProjectSelects();
......@@ -17,22 +17,6 @@ module CalloutsHelper
CL_SUBSCRIPTION_ACTIVATION = 'cloud_licensing_subscription_activation_banner'
PROFILE_PERSONAL_ACCESS_TOKEN_EXPIRY = 'profile_personal_access_token_expiry'
def render_enable_hashed_storage_warning
return unless show_enable_hashed_storage_warning?
message = enable_hashed_storage_warning_message
render_flash_user_callout(:warning, message, GEO_ENABLE_HASHED_STORAGE)
end
def render_migrate_hashed_storage_warning
return unless show_migrate_hashed_storage_warning?
message = migrate_hashed_storage_warning_message
render_flash_user_callout(:warning, message, GEO_MIGRATE_HASHED_STORAGE)
end
def show_enable_hashed_storage_warning?
return if hashed_storage_enabled?
......@@ -119,24 +103,6 @@ def any_project_not_in_hashed_storage?
::Project.with_unmigrated_storage.exists?
end
def enable_hashed_storage_warning_message
message = _('Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}')
add_migrate_to_hashed_storage_link(message)
end
def migrate_hashed_storage_warning_message
message = _('Please migrate all existing projects to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}')
add_migrate_to_hashed_storage_link(message)
end
def add_migrate_to_hashed_storage_link(message)
migrate_link = link_to(_('For more info, read the documentation.'), help_page_path('administration/raketasks/storage.md', anchor: 'migrate-to-hashed-storage'), target: '_blank', rel: 'noopener')
linked_message = message % { migrate_link: migrate_link }
linked_message.html_safe
end
def show_ultimate_trial?(user, callout = ULTIMATE_TRIAL)
return false unless user
return false unless show_ultimate_trial_suitable_env?
......
......@@ -12,12 +12,10 @@
= gitlab_ui_form_for @application_setting, url: templates_admin_application_settings_path, html: { class: 'fieldset-form' } do |f|
= form_errors(@application_setting)
%fieldset
.form-group
= f.label :file_template_project_id, class: 'label-bold' do
.form-text
= _('Select a template repository')
= project_select_tag('application_setting[file_template_project_id]', class: 'project-item-select hidden-filter-value', toggle_class: 'js-project-search js-project-filter js-filter-submit', dropdown_class: 'dropdown-menu-selectable dropdown-menu-project js-filter-submit',
placeholder: _('Search projects'), idAttribute: 'id', data: { order_by: 'last_activity_at', idattribute: 'id', all_projects: 'true', simple_filter: true, allow_clear: true }, value: @application_setting.file_template_project_id)
= s_('TemplateRepository|Create common files more quickly, and standardize their format.')
.js-vue-project-select{ data: { label: _('Select a template repository'),
input_name: 'application_setting[file_template_project_id]',
input_id: 'application_setting[file_template_project_id]',
order_by: 'last_activity_at',
selected: @application_setting.file_template_project_id } }
%p.gl-mt-n5= s_('TemplateRepository|Create common files more quickly, and standardize their format.')
= f.submit _('Save changes'), pajamas_button: true
- add_page_specific_style 'page_bundles/admin/geo_nodes'
- page_title _('Geo sites')
= render_enable_hashed_storage_warning
= render_migrate_hashed_storage_warning
= render partial: 'admin/geo/shared/hashed_storage_alerts'
= render partial: 'admin/geo/shared/license_alert'
#js-geo-nodes{ data: node_vue_list_properties }
- migrate_link = link_to(_('For more info, read the documentation.'), help_page_path('administration/raketasks/storage.md', anchor: 'migrate-to-hashed-storage'), target: '_blank', rel: 'noopener').html_safe
- if show_enable_hashed_storage_warning?
= render Pajamas::AlertComponent.new(variant: :warning,
dismissible: true,
alert_options: { class: 'gl-mt-5 js-geo-enable-hashed-storage-callout', data: { testid: 'enable_hashed_storage_alert', feature_id: Users::CalloutsHelper::GEO_ENABLE_HASHED_STORAGE, dismiss_endpoint: callouts_path } }) do |c|
= c.body do
= _('Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}').html_safe % { migrate_link: migrate_link }
- if show_migrate_hashed_storage_warning?
= render Pajamas::AlertComponent.new(variant: :warning,
dismissible: true,
alert_options: { class: 'gl-mt-5 js-geo-migrate-hashed-storage-callout', data: { testid: 'migrate_hashed_storage_alert', feature_id: Users::CalloutsHelper::GEO_MIGRATE_HASHED_STORAGE, dismiss_endpoint: callouts_path } }) do |c|
= c.body do
= _('Please migrate all existing projects to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}').html_safe % { migrate_link: migrate_link }
......@@ -14,13 +14,14 @@
= gitlab_ui_form_for @group, html: { class: 'fieldset-form' } do |form|
= form_errors(@group)
%fieldset
.form-group
- pointer = @group.analytics_dashboards_pointer || @group.build_analytics_dashboards_pointer
= form.fields_for :analytics_dashboards_pointer_attributes, pointer do |pointer_form|
= pointer_form.hidden_field :id
= pointer_form.label :project_id, class: 'label-light' do
= s_('GroupSettings|Select the project containing Analytics Dashboards configuration files')
= project_select_tag('group[analytics_dashboards_pointer_attributes][project_id]', class: 'project-item-select',
placeholder: _('Search projects'), idAttribute: 'id', data: { order_by: 'last_activity_at', idattribute: 'id', simple_filter: true, allow_clear: true, include_projects_in_subgroups: true}, value: pointer.project_id)
- pointer = @group.analytics_dashboards_pointer || @group.build_analytics_dashboards_pointer
= form.fields_for :analytics_dashboards_pointer_attributes, pointer do |pointer_form|
= pointer_form.hidden_field :id
.js-vue-project-select{ data: { label: s_('GroupSettings|Select the project containing Analytics Dashboards configuration files'),
input_name: 'group[analytics_dashboards_pointer_attributes][project_id]',
input_id: 'group_analytics_dashboards_pointer_attributes_project_id',
group_id: @group.id,
order_by: 'last_activity_at',
include_subgroups: true.to_s,
selected: pointer.project_id } }
= form.submit _('Save changes'), pajamas_button: true
......@@ -14,13 +14,15 @@
= gitlab_ui_form_for @group, html: { class: 'fieldset-form' } do |form|
= form_errors(@group)
%fieldset
.form-group
- insight = @group.insight || @group.build_insight
= form.fields_for :insight_attributes, insight do |insight_form|
= insight_form.hidden_field :id
= insight_form.label :project_id, class: 'label-light' do
= html_escape(s_('GroupSettings|Select the project containing the %{code_start}.gitlab/insights.yml%{code_end} file')) % { code_start: '<code>'.html_safe, code_end: '</code>'.html_safe }
= project_select_tag('group[insight_attributes][project_id]', class: 'project-item-select hidden-filter-value', toggle_class: 'js-project-search js-project-filter js-filter-submit', dropdown_class: 'dropdown-menu-selectable dropdown-menu-project js-filter-submit',
placeholder: _('Search projects'), idAttribute: 'id', data: { order_by: 'last_activity_at', idattribute: 'id', simple_filter: true, allow_clear: true, include_projects_in_subgroups: true }, value: insight.project_id)
- insight = @group.insight || @group.build_insight
= form.fields_for :insight_attributes, insight do |insight_form|
= insight_form.hidden_field :id
.js-vue-project-select{ data: { label: html_escape(s_('GroupSettings|Select the project containing the %{code_start}.gitlab/insights.yml%{code_end} file')) % { code_start: '<code>'.html_safe, code_end: '</code>'.html_safe },
has_html_label: true.to_s,
input_name: 'group[insight_attributes][project_id]',
input_id: 'group_insight_attributes_project_id',
group_id: @group.id,
order_by: 'last_activity_at',
include_subgroups: true.to_s,
selected: insight.project_id } }
= form.submit _('Save changes'), pajamas_button: true
......@@ -12,6 +12,6 @@
.settings-content
= gitlab_ui_form_for @group, url: group_path, html: { class: 'fieldset-form' } do |f|
= form_errors(@group)
.js-vue-project-select{ data: { label: _('Select a template repository'), input_name: 'group[file_template_project_id]', input_id: 'group[file_template_project_id]', group_id: @group.id, clearable: true.to_s, selected: @group.checked_file_template_project_id } }
.js-vue-project-select{ data: { label: _('Select a template repository'), input_name: 'group[file_template_project_id]', input_id: 'group[file_template_project_id]', group_id: @group.id, selected: @group.checked_file_template_project_id } }
%p.gl-mt-n5= s_('Create common files more quickly, and standardize their format.')
= f.submit _('Save changes'), pajamas_button: true, data: { qa_selector: 'save_changes_button' }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment