Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-10-20 21:09:10 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-10-20 21:09:10 +0300
commita3764262c04bafcd6a54aff635541d73a8a630fd (patch)
treeea54444857967f08b7601886b47d15819990b6cf /app
parent049d16d168fdee408b78f5f38619c092fd3b2265 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/issuable/components/related_issuable_item.vue1
-rw-r--r--app/assets/javascripts/pipeline_schedules/components/pipeline_schedules.vue106
-rw-r--r--app/assets/javascripts/pipeline_schedules/components/table/pipeline_schedules_table.vue6
-rw-r--r--app/assets/javascripts/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql5
-rw-r--r--app/controllers/jira_connect/subscriptions_controller.rb2
-rw-r--r--app/models/namespace.rb6
-rw-r--r--app/models/personal_access_token.rb33
-rw-r--r--app/views/admin/application_settings/general.html.haml2
-rw-r--r--app/views/ci/variables/_url_query_variable_row.html.haml28
-rw-r--r--app/views/shared/access_tokens/_created_container.html.haml12
-rw-r--r--app/views/shared/access_tokens/_table.html.haml51
11 files changed, 113 insertions, 139 deletions
diff --git a/app/assets/javascripts/issuable/components/related_issuable_item.vue b/app/assets/javascripts/issuable/components/related_issuable_item.vue
index 8894e8f63b8..254248ef1d4 100644
--- a/app/assets/javascripts/issuable/components/related_issuable_item.vue
+++ b/app/assets/javascripts/issuable/components/related_issuable_item.vue
@@ -141,6 +141,7 @@ export default {
<gl-link
:href="computedPath"
class="sortable-link gl-font-weight-normal"
+ target="_blank"
@click="handleTitleClick"
>
{{ title }}
diff --git a/app/assets/javascripts/pipeline_schedules/components/pipeline_schedules.vue b/app/assets/javascripts/pipeline_schedules/components/pipeline_schedules.vue
index 4a08a82275a..b055b89c528 100644
--- a/app/assets/javascripts/pipeline_schedules/components/pipeline_schedules.vue
+++ b/app/assets/javascripts/pipeline_schedules/components/pipeline_schedules.vue
@@ -1,6 +1,8 @@
<script>
-import { GlAlert, GlLoadingIcon, GlModal } from '@gitlab/ui';
+import { GlAlert, GlBadge, GlButton, GlLoadingIcon, GlModal, GlTabs, GlTab } from '@gitlab/ui';
import { s__, __ } from '~/locale';
+import { limitedCounterWithDelimiter } from '~/lib/utils/text_utility';
+import { queryToObject } from '~/lib/utils/url_utility';
import deletePipelineScheduleMutation from '../graphql/mutations/delete_pipeline_schedule.mutation.graphql';
import getPipelineSchedulesQuery from '../graphql/queries/get_pipeline_schedules.query.graphql';
import PipelineSchedulesTable from './table/pipeline_schedules_table.vue';
@@ -11,6 +13,7 @@ export default {
scheduleDeleteError: s__(
'PipelineSchedules|There was a problem deleting the pipeline schedule.',
),
+ newSchedule: s__('PipelineSchedules|New schedule'),
},
modal: {
id: 'delete-pipeline-schedule-modal',
@@ -28,8 +31,12 @@ export default {
},
components: {
GlAlert,
+ GlBadge,
+ GlButton,
GlLoadingIcon,
GlModal,
+ GlTabs,
+ GlTab,
PipelineSchedulesTable,
},
inject: {
@@ -43,10 +50,16 @@ export default {
variables() {
return {
projectPath: this.fullPath,
+ status: this.scope,
};
},
- update({ project }) {
- return project?.pipelineSchedules?.nodes || [];
+ update(data) {
+ const { pipelineSchedules: { nodes: list = [], count } = {} } = data.project || {};
+
+ return {
+ list,
+ count,
+ };
},
error() {
this.reportError(this.$options.i18n.schedulesFetchError);
@@ -54,18 +67,58 @@ export default {
},
},
data() {
+ const { scope } = queryToObject(window.location.search);
return {
- schedules: [],
+ schedules: {
+ list: [],
+ },
+ scope,
hasError: false,
errorMessage: '',
scheduleToDeleteId: null,
showModal: false,
+ count: 0,
};
},
computed: {
isLoading() {
return this.$apollo.queries.schedules.loading;
},
+ schedulesCount() {
+ return this.schedules.count;
+ },
+ tabs() {
+ return [
+ {
+ text: s__('PipelineSchedules|All'),
+ count: limitedCounterWithDelimiter(this.count),
+ scope: null,
+ showBadge: true,
+ attrs: { 'data-testid': 'pipeline-schedules-all-tab' },
+ },
+ {
+ text: s__('PipelineSchedules|Active'),
+ scope: 'ACTIVE',
+ showBadge: false,
+ attrs: { 'data-testid': 'pipeline-schedules-active-tab' },
+ },
+ {
+ text: s__('PipelineSchedules|Inactive'),
+ scope: 'INACTIVE',
+ showBadge: false,
+ attrs: { 'data-testid': 'pipeline-schedules-inactive-tab' },
+ },
+ ];
+ },
+ },
+ watch: {
+ // this watcher ensures that the count on the all tab
+ // is not updated when switching to other tabs
+ schedulesCount(newCount) {
+ if (!this.scope) {
+ this.count = newCount;
+ }
+ },
},
methods: {
reportError(error) {
@@ -100,6 +153,10 @@ export default {
this.reportError(this.$options.i18n.scheduleDeleteError);
}
},
+ fetchPipelineSchedulesByStatus(scope) {
+ this.scope = scope;
+ this.$apollo.queries.schedules.refetch();
+ },
},
};
</script>
@@ -110,12 +167,45 @@ export default {
{{ errorMessage }}
</gl-alert>
- <gl-loading-icon v-if="isLoading" size="lg" />
+ <template v-else>
+ <gl-tabs
+ sync-active-tab-with-query-params
+ query-param-name="scope"
+ nav-class="gl-flex-grow-1 gl-align-items-center"
+ >
+ <gl-tab
+ v-for="tab in tabs"
+ :key="tab.text"
+ :title-link-attributes="tab.attrs"
+ :query-param-value="tab.scope"
+ @click="fetchPipelineSchedulesByStatus(tab.scope)"
+ >
+ <template #title>
+ <span>{{ tab.text }}</span>
- <!-- Tabs will be addressed in #371989 -->
+ <template v-if="tab.showBadge">
+ <gl-loading-icon v-if="tab.scope === scope && isLoading" class="gl-ml-2" />
- <template v-else>
- <pipeline-schedules-table :schedules="schedules" @showDeleteModal="showDeleteModal" />
+ <gl-badge v-else-if="tab.count" size="sm" class="gl-tab-counter-badge">
+ {{ tab.count }}
+ </gl-badge>
+ </template>
+ </template>
+
+ <gl-loading-icon v-if="isLoading" size="lg" />
+ <pipeline-schedules-table
+ v-else
+ :schedules="schedules.list"
+ @showDeleteModal="showDeleteModal"
+ />
+ </gl-tab>
+
+ <template #tabs-end>
+ <gl-button variant="confirm" class="gl-ml-auto" data-testid="new-schedule-button">
+ {{ $options.i18n.newSchedule }}
+ </gl-button>
+ </template>
+ </gl-tabs>
<gl-modal
:visible="showModal"
diff --git a/app/assets/javascripts/pipeline_schedules/components/table/pipeline_schedules_table.vue b/app/assets/javascripts/pipeline_schedules/components/table/pipeline_schedules_table.vue
index d54008b81b2..da2157a8851 100644
--- a/app/assets/javascripts/pipeline_schedules/components/table/pipeline_schedules_table.vue
+++ b/app/assets/javascripts/pipeline_schedules/components/table/pipeline_schedules_table.vue
@@ -12,31 +12,37 @@ export default {
{
key: 'description',
label: s__('PipelineSchedules|Description'),
+ thClass: 'gl-border-t-none!',
columnClass: 'gl-w-40p',
},
{
key: 'target',
label: s__('PipelineSchedules|Target'),
+ thClass: 'gl-border-t-none!',
columnClass: 'gl-w-10p',
},
{
key: 'pipeline',
label: s__('PipelineSchedules|Last Pipeline'),
+ thClass: 'gl-border-t-none!',
columnClass: 'gl-w-10p',
},
{
key: 'next',
label: s__('PipelineSchedules|Next Run'),
+ thClass: 'gl-border-t-none!',
columnClass: 'gl-w-15p',
},
{
key: 'owner',
label: s__('PipelineSchedules|Owner'),
+ thClass: 'gl-border-t-none!',
columnClass: 'gl-w-10p',
},
{
key: 'actions',
label: '',
+ thClass: 'gl-border-t-none!',
columnClass: 'gl-w-15p',
},
],
diff --git a/app/assets/javascripts/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql b/app/assets/javascripts/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql
index 7d9d658b1b6..9f6cb429cca 100644
--- a/app/assets/javascripts/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql
+++ b/app/assets/javascripts/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql
@@ -1,7 +1,8 @@
-query getPipelineSchedulesQuery($projectPath: ID!) {
+query getPipelineSchedulesQuery($projectPath: ID!, $status: PipelineScheduleStatus) {
project(fullPath: $projectPath) {
id
- pipelineSchedules {
+ pipelineSchedules(status: $status) {
+ count
nodes {
id
description
diff --git a/app/controllers/jira_connect/subscriptions_controller.rb b/app/controllers/jira_connect/subscriptions_controller.rb
index 9305f46c39e..751481f78e2 100644
--- a/app/controllers/jira_connect/subscriptions_controller.rb
+++ b/app/controllers/jira_connect/subscriptions_controller.rb
@@ -64,7 +64,7 @@ class JiraConnect::SubscriptionsController < JiraConnect::ApplicationController
private
def allow_self_managed_content_security_policy
- return unless Feature.enabled?(:jira_connect_oauth_self_managed)
+ return unless Feature.enabled?(:jira_connect_oauth_self_managed_setting)
return unless current_jira_installation.instance_url?
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 42f362876bb..12b96f34316 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -40,9 +40,9 @@ class Namespace < ApplicationRecord
PATH_TRAILING_VIOLATIONS = %w[.git .atom .].freeze
- # The first date in https://docs.gitlab.com/ee/user/usage_quotas.html#namespace-storage-limit-enforcement-schedule
- # Determines when we start enforcing namespace storage
- MIN_STORAGE_ENFORCEMENT_DATE = Date.new(2022, 10, 19)
+ # This date is just a placeholder until namespace storage enforcement timeline is confirmed at which point
+ # this should be replaced, see https://about.gitlab.com/pricing/faq-efficient-free-tier/#user-limits-on-gitlab-saas-free-tier
+ MIN_STORAGE_ENFORCEMENT_DATE = 3.months.from_now.to_date
# https://gitlab.com/gitlab-org/gitlab/-/issues/367531
MIN_STORAGE_ENFORCEMENT_USAGE = 5.gigabytes
diff --git a/app/models/personal_access_token.rb b/app/models/personal_access_token.rb
index f0ed1822da6..3126dba9d6d 100644
--- a/app/models/personal_access_token.rb
+++ b/app/models/personal_access_token.rb
@@ -11,8 +11,6 @@ class PersonalAccessToken < ApplicationRecord
add_authentication_token_field :token, digest: true
- REDIS_EXPIRY_TIME = 3.minutes
-
# PATs are 20 characters + optional configurable settings prefix (0..20)
TOKEN_LENGTH_RANGE = (20..40).freeze
@@ -34,8 +32,6 @@ class PersonalAccessToken < ApplicationRecord
scope :for_user, -> (user) { where(user: user) }
scope :for_users, -> (users) { where(user: users) }
scope :preload_users, -> { preload(:user) }
- scope :order_expires_at_asc, -> { reorder(expires_at: :asc) }
- scope :order_expires_at_desc, -> { reorder(expires_at: :desc) }
scope :order_expires_at_asc_id_desc, -> { reorder(expires_at: :asc, id: :desc) }
scope :project_access_token, -> { includes(:user).where(user: { user_type: :project_bot }) }
scope :owner_is_human, -> { includes(:user).where(user: { user_type: :human }) }
@@ -55,35 +51,10 @@ class PersonalAccessToken < ApplicationRecord
!revoked? && !expired?
end
- def self.redis_getdel(user_id)
- Gitlab::Redis::SharedState.with do |redis|
- redis_key = redis_shared_state_key(user_id)
- encrypted_token = redis.get(redis_key)
- redis.del(redis_key)
-
- begin
- Gitlab::CryptoHelper.aes256_gcm_decrypt(encrypted_token)
- rescue StandardError => e
- logger.warn "Failed to decrypt #{self.name} value stored in Redis for key ##{redis_key}: #{e.class}"
- encrypted_token
- end
- end
- end
-
- def self.redis_store!(user_id, token)
- encrypted_token = Gitlab::CryptoHelper.aes256_gcm_encrypt(token)
-
- Gitlab::Redis::SharedState.with do |redis|
- redis.set(redis_shared_state_key(user_id), encrypted_token, ex: REDIS_EXPIRY_TIME)
- end
- end
-
override :simple_sorts
def self.simple_sorts
super.merge(
{
- 'expires_at_asc' => -> { order_expires_at_asc },
- 'expires_at_desc' => -> { order_expires_at_desc },
'expires_at_asc_id_desc' => -> { order_expires_at_asc_id_desc }
}
)
@@ -121,10 +92,6 @@ class PersonalAccessToken < ApplicationRecord
self.scopes = Gitlab::Auth::DEFAULT_SCOPES if self.scopes.empty?
end
-
- def self.redis_shared_state_key(user_id)
- "gitlab:personal_access_token:#{user_id}"
- end
end
PersonalAccessToken.prepend_mod_with('PersonalAccessToken')
diff --git a/app/views/admin/application_settings/general.html.haml b/app/views/admin/application_settings/general.html.haml
index ec5d1ef4a34..db407ae35c4 100644
--- a/app/views/admin/application_settings/general.html.haml
+++ b/app/views/admin/application_settings/general.html.haml
@@ -123,4 +123,4 @@
= render 'admin/application_settings/eks'
= render 'admin/application_settings/floc'
= render_if_exists 'admin/application_settings/add_license'
-= render 'admin/application_settings/jira_connect_application_key' if Feature.enabled?(:jira_connect_oauth, current_user)
+= render 'admin/application_settings/jira_connect_application_key' if Feature.enabled?(:jira_connect_oauth_self_managed_setting, current_user)
diff --git a/app/views/ci/variables/_url_query_variable_row.html.haml b/app/views/ci/variables/_url_query_variable_row.html.haml
deleted file mode 100644
index 77bcacdb94b..00000000000
--- a/app/views/ci/variables/_url_query_variable_row.html.haml
+++ /dev/null
@@ -1,28 +0,0 @@
-- form_field = local_assigns.fetch(:form_field, nil)
-- variable = local_assigns.fetch(:variable, nil)
-
-- key = variable[0]
-- value = variable[1]
-- variable_type = variable[2] || "env_var"
-
-- destroy_input_name = "#{form_field}[variables_attributes][][_destroy]"
-- variable_type_input_name = "#{form_field}[variables_attributes][][variable_type]"
-- key_input_name = "#{form_field}[variables_attributes][][key]"
-- value_input_name = "#{form_field}[variables_attributes][][secret_value]"
-
-%li.js-row.ci-variable-row
- .ci-variable-row-body.border-bottom
- %input.js-ci-variable-input-destroy{ type: "hidden", name: destroy_input_name }
- %select.js-ci-variable-input-variable-type.ci-variable-body-item.form-control.select-control.custom-select.table-section.section-15{ name: variable_type_input_name }
- = options_for_select(ci_variable_type_options, variable_type)
- %input.js-ci-variable-input-key.ci-variable-body-item.form-control.table-section.section-15{ type: "text",
- name: key_input_name,
- value: key,
- placeholder: s_('CiVariables|Input variable key') }
- .ci-variable-body-item.gl-show-field-errors.table-section.section-15.border-top-0.p-0
- %textarea.js-ci-variable-input-value.js-secret-value.form-control{ rows: 1,
- name: value_input_name,
- placeholder: s_('CiVariables|Input variable value') }
- = value
- %button.gl-button.btn.btn-default.btn-icon.btn-item-remove.js-row-remove-button.ci-variable-row-remove-button.table-section{ type: 'button', 'aria-label': s_('CiVariables|Remove variable row') }
- = sprite_icon('close')
diff --git a/app/views/shared/access_tokens/_created_container.html.haml b/app/views/shared/access_tokens/_created_container.html.haml
deleted file mode 100644
index c0aaa46e761..00000000000
--- a/app/views/shared/access_tokens/_created_container.html.haml
+++ /dev/null
@@ -1,12 +0,0 @@
-.created-personal-access-token-container
- %h5.gl-mt-0
- = _('Your new %{type}') % { type: type }
- .form-group
- .input-group
- = text_field_tag 'created-personal-access-token', new_token_value, readonly: true, class: 'form-control js-select-on-focus', data: { qa_selector: 'created_access_token_field' }, 'aria-describedby' => 'created-token-help-block'
- %span.input-group-append
- = clipboard_button(text: new_token_value, title: _('Copy %{type}') % { type: type }, placement: 'left', class: 'input-group-text btn-default btn-clipboard')
- %span#created-token-help-block.form-text.text-muted.text-danger
- = _("Make sure you save it - you won't be able to access it again.")
-
-%hr
diff --git a/app/views/shared/access_tokens/_table.html.haml b/app/views/shared/access_tokens/_table.html.haml
deleted file mode 100644
index 53c6800f93d..00000000000
--- a/app/views/shared/access_tokens/_table.html.haml
+++ /dev/null
@@ -1,51 +0,0 @@
-- no_active_tokens_message = local_assigns.fetch(:no_active_tokens_message, _('This user has no active %{type}.') % { type: type_plural })
-- impersonation = local_assigns.fetch(:impersonation, false)
-- resource = local_assigns.fetch(:resource, false)
-
-%hr
-
-%h5
- = _('Active %{type} (%{token_length})') % { type: type_plural, token_length: active_tokens.length }
-
-- if impersonation
- %p.profile-settings-content
- = _("To see all the user's personal access tokens you must impersonate them first.")
-
-- if active_tokens.present?
- .table-responsive
- %table.table.active-tokens
- %thead
- %tr
- %th= _('Token name')
- %th= _('Scopes')
- %th= s_('AccessTokens|Created')
- %th
- = _('Last Used')
- = link_to sprite_icon('question-o'), help_page_path('user/profile/personal_access_tokens.md', anchor: 'view-the-last-time-a-token-was-used'), target: '_blank', rel: 'noopener noreferrer'
- %th= _('Expires')
- - if resource
- %th= _('Role')
- %th
- %tbody
- - active_tokens.each do |token|
- %tr
- %td= token.name
- %td= token.scopes.present? ? token.scopes.join(', ') : _('no scopes selected')
- %td= token.created_at.to_date.to_s(:medium)
- %td
- - if token.last_used_at?
- %span.token-last-used-label= _(time_ago_with_tooltip(token.last_used_at))
- - else
- %span.token-never-used-label= _('Never')
- %td
- - if token.expires?
- %span{ class: ('text-warning' if token.expires_soon?) }
- = time_ago_with_tooltip(token.expires_at)
- - else
- %span.token-never-expires-label= _('Never')
- - if resource
- %td= resource.member(token.user).human_access
- %td= link_to _('Revoke'), revoke_route_helper.call(token), method: :put, class: "gl-button btn btn-danger btn-sm float-right #{'btn-danger-secondary' unless token.expires?}", aria: { label: _('Revoke') }, data: { confirm: _('Are you sure you want to revoke this %{type}? This action cannot be undone.') % { type: type }, 'confirm-btn-variant': 'danger', qa_selector: 'revoke_button' }
-- else
- .settings-message.text-center
- = no_active_tokens_message