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-07-05 13:20:03 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-07-05 13:20:03 +0300
commitd2612b42b9da6638d70b9d7144f6d427070d042d (patch)
treeed7de87d4b112cae8a45ba186d717ca9768c7d4e /app
parentd80373b353005e70f44eca8a3bc4a4c5cfbf0e9e (diff)
Add latest changes from gitlab-org/gitlab@15-1-stable-ee
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/clusters/agents/components/create_token_button.vue216
-rw-r--r--app/assets/javascripts/clusters/agents/components/create_token_modal.vue218
-rw-r--r--app/assets/javascripts/clusters/agents/components/revoke_token_button.vue2
-rw-r--r--app/assets/javascripts/clusters/agents/components/token_table.vue92
-rw-r--r--app/assets/javascripts/projects/project_new.js35
-rw-r--r--app/uploaders/object_storage.rb14
-rw-r--r--app/workers/namespaces/process_sync_events_worker.rb2
-rw-r--r--app/workers/projects/process_sync_events_worker.rb2
8 files changed, 306 insertions, 275 deletions
diff --git a/app/assets/javascripts/clusters/agents/components/create_token_button.vue b/app/assets/javascripts/clusters/agents/components/create_token_button.vue
index 74155d7819a..67a178b5f98 100644
--- a/app/assets/javascripts/clusters/agents/components/create_token_button.vue
+++ b/app/assets/javascripts/clusters/agents/components/create_token_button.vue
@@ -1,154 +1,23 @@
<script>
-import {
- GlButton,
- GlModalDirective,
- GlTooltip,
- GlModal,
- GlFormGroup,
- GlFormInput,
- GlFormTextarea,
- GlAlert,
-} from '@gitlab/ui';
-import { s__, __ } from '~/locale';
-import Tracking from '~/tracking';
-import AgentToken from '~/clusters_list/components/agent_token.vue';
-import {
- CREATE_TOKEN_MODAL,
- EVENT_LABEL_MODAL,
- EVENT_ACTIONS_OPEN,
- EVENT_ACTIONS_CLICK,
- TOKEN_NAME_LIMIT,
- TOKEN_STATUS_ACTIVE,
-} from '../constants';
-import createNewAgentToken from '../graphql/mutations/create_new_agent_token.mutation.graphql';
-import getClusterAgentQuery from '../graphql/queries/get_cluster_agent.query.graphql';
-import { addAgentTokenToStore } from '../graphql/cache_update';
-
-const trackingMixin = Tracking.mixin({ label: EVENT_LABEL_MODAL });
+import { GlButton, GlModalDirective, GlTooltip } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import { CREATE_TOKEN_MODAL } from '../constants';
export default {
components: {
- AgentToken,
GlButton,
GlTooltip,
- GlModal,
- GlFormGroup,
- GlFormInput,
- GlFormTextarea,
- GlAlert,
},
directives: {
GlModalDirective,
},
- mixins: [trackingMixin],
- inject: ['agentName', 'projectPath', 'canAdminCluster'],
- props: {
- clusterAgentId: {
- required: true,
- type: String,
- },
- cursor: {
- required: true,
- type: Object,
- },
- },
+ inject: ['canAdminCluster'],
modalId: CREATE_TOKEN_MODAL,
- EVENT_ACTIONS_OPEN,
- EVENT_ACTIONS_CLICK,
- EVENT_LABEL_MODAL,
- TOKEN_NAME_LIMIT,
i18n: {
createTokenButton: s__('ClusterAgents|Create token'),
- modalTitle: s__('ClusterAgents|Create agent access token'),
- unknownError: s__('ClusterAgents|An unknown error occurred. Please try again.'),
- errorTitle: s__('ClusterAgents|Failed to create a token'),
dropdownDisabledHint: s__(
'ClusterAgents|Requires a Maintainer or greater role to perform these actions',
),
- modalCancel: __('Cancel'),
- modalClose: __('Close'),
- tokenNameLabel: __('Name'),
- tokenDescriptionLabel: __('Description (optional)'),
- },
- data() {
- return {
- token: {
- name: null,
- description: null,
- },
- agentToken: null,
- error: null,
- loading: false,
- variables: {
- agentName: this.agentName,
- projectPath: this.projectPath,
- tokenStatus: TOKEN_STATUS_ACTIVE,
- ...this.cursor,
- },
- };
- },
- computed: {
- modalBtnDisabled() {
- return this.loading || !this.hasTokenName;
- },
- hasTokenName() {
- return Boolean(this.token.name?.length);
- },
- },
- methods: {
- async createToken() {
- this.loading = true;
- this.error = null;
-
- try {
- const { errors: tokenErrors, secret } = await this.createAgentTokenMutation();
-
- if (tokenErrors?.length > 0) {
- throw new Error(tokenErrors[0]);
- }
-
- this.agentToken = secret;
- } catch (error) {
- if (error) {
- this.error = error.message;
- } else {
- this.error = this.$options.i18n.unknownError;
- }
- } finally {
- this.loading = false;
- }
- },
- resetModal() {
- this.agentToken = null;
- this.token.name = null;
- this.token.description = null;
- this.error = null;
- },
- closeModal() {
- this.$refs.modal.hide();
- },
- createAgentTokenMutation() {
- return this.$apollo
- .mutate({
- mutation: createNewAgentToken,
- variables: {
- input: {
- clusterAgentId: this.clusterAgentId,
- name: this.token.name,
- description: this.token.description,
- },
- },
- update: (store, { data: { clusterAgentTokenCreate } }) => {
- addAgentTokenToStore(
- store,
- clusterAgentTokenCreate,
- getClusterAgentQuery,
- this.variables,
- );
- },
- })
- .then(({ data: { clusterAgentTokenCreate } }) => clusterAgentTokenCreate);
- },
},
};
</script>
@@ -170,82 +39,5 @@ export default {
:title="$options.i18n.dropdownDisabledHint"
/>
</div>
-
- <gl-modal
- ref="modal"
- :modal-id="$options.modalId"
- :title="$options.i18n.modalTitle"
- static
- lazy
- @hidden="resetModal"
- @show="track($options.EVENT_ACTIONS_OPEN)"
- >
- <gl-alert
- v-if="error"
- :title="$options.i18n.errorTitle"
- :dismissible="false"
- variant="danger"
- class="gl-mb-5"
- >
- {{ error }}
- </gl-alert>
-
- <template v-if="!agentToken">
- <gl-form-group :label="$options.i18n.tokenNameLabel">
- <gl-form-input
- v-model="token.name"
- :max-length="$options.TOKEN_NAME_LIMIT"
- :disabled="loading"
- required
- />
- </gl-form-group>
-
- <gl-form-group :label="$options.i18n.tokenDescriptionLabel">
- <gl-form-textarea v-model="token.description" :disabled="loading" name="description" />
- </gl-form-group>
- </template>
-
- <agent-token
- v-else
- :agent-name="agentName"
- :agent-token="agentToken"
- :modal-id="$options.modalId"
- />
-
- <template #modal-footer>
- <gl-button
- v-if="!agentToken && !loading"
- :data-track-action="$options.EVENT_ACTIONS_CLICK"
- :data-track-label="$options.EVENT_LABEL_MODAL"
- data-track-property="close"
- data-testid="agent-token-close-button"
- @click="closeModal"
- >{{ $options.i18n.modalCancel }}
- </gl-button>
-
- <gl-button
- v-if="!agentToken"
- :disabled="modalBtnDisabled"
- :loading="loading"
- :data-track-action="$options.EVENT_ACTIONS_CLICK"
- :data-track-label="$options.EVENT_LABEL_MODAL"
- data-track-property="create-token"
- variant="confirm"
- type="submit"
- @click="createToken"
- >{{ $options.i18n.createTokenButton }}
- </gl-button>
-
- <gl-button
- v-else
- :data-track-action="$options.EVENT_ACTIONS_CLICK"
- :data-track-label="$options.EVENT_LABEL_MODAL"
- data-track-property="close"
- variant="confirm"
- @click="closeModal"
- >{{ $options.i18n.modalClose }}
- </gl-button>
- </template>
- </gl-modal>
</div>
</template>
diff --git a/app/assets/javascripts/clusters/agents/components/create_token_modal.vue b/app/assets/javascripts/clusters/agents/components/create_token_modal.vue
new file mode 100644
index 00000000000..451e1ee1d67
--- /dev/null
+++ b/app/assets/javascripts/clusters/agents/components/create_token_modal.vue
@@ -0,0 +1,218 @@
+<script>
+import { GlButton, GlModal, GlFormGroup, GlFormInput, GlFormTextarea, GlAlert } from '@gitlab/ui';
+import { s__, __ } from '~/locale';
+import Tracking from '~/tracking';
+import AgentToken from '~/clusters_list/components/agent_token.vue';
+import {
+ CREATE_TOKEN_MODAL,
+ EVENT_LABEL_MODAL,
+ EVENT_ACTIONS_OPEN,
+ EVENT_ACTIONS_CLICK,
+ TOKEN_NAME_LIMIT,
+ TOKEN_STATUS_ACTIVE,
+} from '../constants';
+import createNewAgentToken from '../graphql/mutations/create_new_agent_token.mutation.graphql';
+import getClusterAgentQuery from '../graphql/queries/get_cluster_agent.query.graphql';
+import { addAgentTokenToStore } from '../graphql/cache_update';
+
+const trackingMixin = Tracking.mixin({ label: EVENT_LABEL_MODAL });
+
+export default {
+ components: {
+ AgentToken,
+ GlButton,
+ GlModal,
+ GlFormGroup,
+ GlFormInput,
+ GlFormTextarea,
+ GlAlert,
+ },
+ mixins: [trackingMixin],
+ inject: ['agentName', 'projectPath'],
+ props: {
+ clusterAgentId: {
+ required: true,
+ type: String,
+ },
+ cursor: {
+ required: true,
+ type: Object,
+ },
+ },
+ modalId: CREATE_TOKEN_MODAL,
+ EVENT_ACTIONS_OPEN,
+ EVENT_ACTIONS_CLICK,
+ EVENT_LABEL_MODAL,
+ TOKEN_NAME_LIMIT,
+ i18n: {
+ createTokenButton: s__('ClusterAgents|Create token'),
+ modalTitle: s__('ClusterAgents|Create agent access token'),
+ unknownError: s__('ClusterAgents|An unknown error occurred. Please try again.'),
+ errorTitle: s__('ClusterAgents|Failed to create a token'),
+ modalCancel: __('Cancel'),
+ modalClose: __('Close'),
+ tokenNameLabel: __('Name'),
+ tokenDescriptionLabel: __('Description (optional)'),
+ },
+ data() {
+ return {
+ token: {
+ name: null,
+ description: null,
+ },
+ agentToken: null,
+ error: null,
+ loading: false,
+ variables: {
+ agentName: this.agentName,
+ projectPath: this.projectPath,
+ tokenStatus: TOKEN_STATUS_ACTIVE,
+ ...this.cursor,
+ },
+ };
+ },
+ computed: {
+ modalBtnDisabled() {
+ return this.loading || !this.hasTokenName;
+ },
+ hasTokenName() {
+ return Boolean(this.token.name?.length);
+ },
+ },
+ methods: {
+ async createToken() {
+ this.loading = true;
+ this.error = null;
+
+ try {
+ const { errors: tokenErrors, secret } = await this.createAgentTokenMutation();
+
+ if (tokenErrors?.length > 0) {
+ throw new Error(tokenErrors[0]);
+ }
+ this.agentToken = secret;
+ } catch (error) {
+ this.error = error ? error.message : this.$options.i18n.unknownError;
+ } finally {
+ this.loading = false;
+ }
+ },
+ resetModal() {
+ this.agentToken = null;
+ this.token.name = null;
+ this.token.description = null;
+ this.error = null;
+ },
+ closeModal() {
+ this.$refs.modal.hide();
+ },
+ createAgentTokenMutation() {
+ return this.$apollo
+ .mutate({
+ mutation: createNewAgentToken,
+ variables: {
+ input: {
+ clusterAgentId: this.clusterAgentId,
+ name: this.token.name,
+ description: this.token.description,
+ },
+ },
+ update: (store, { data: { clusterAgentTokenCreate } }) => {
+ addAgentTokenToStore(
+ store,
+ clusterAgentTokenCreate,
+ getClusterAgentQuery,
+ this.variables,
+ );
+ },
+ })
+ .then(({ data: { clusterAgentTokenCreate } }) => clusterAgentTokenCreate);
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-modal
+ ref="modal"
+ :modal-id="$options.modalId"
+ :title="$options.i18n.modalTitle"
+ static
+ lazy
+ @hidden="resetModal"
+ @show="track($options.EVENT_ACTIONS_OPEN)"
+ >
+ <gl-alert
+ v-if="error"
+ :title="$options.i18n.errorTitle"
+ :dismissible="false"
+ variant="danger"
+ class="gl-mb-5"
+ >
+ {{ error }}
+ </gl-alert>
+
+ <template v-if="!agentToken">
+ <gl-form-group :label="$options.i18n.tokenNameLabel" label-for="token-name">
+ <gl-form-input
+ id="token-name"
+ v-model="token.name"
+ :max-length="$options.TOKEN_NAME_LIMIT"
+ :disabled="loading"
+ required
+ />
+ </gl-form-group>
+
+ <gl-form-group :label="$options.i18n.tokenDescriptionLabel" label-for="token-description">
+ <gl-form-textarea
+ id="token-description"
+ v-model="token.description"
+ :disabled="loading"
+ name="description"
+ />
+ </gl-form-group>
+ </template>
+
+ <agent-token
+ v-else
+ :agent-name="agentName"
+ :agent-token="agentToken"
+ :modal-id="$options.modalId"
+ />
+
+ <template #modal-footer>
+ <gl-button
+ v-if="!agentToken && !loading"
+ :data-track-action="$options.EVENT_ACTIONS_CLICK"
+ :data-track-label="$options.EVENT_LABEL_MODAL"
+ data-track-property="close"
+ data-testid="agent-token-close-button"
+ @click="closeModal"
+ >{{ $options.i18n.modalCancel }}
+ </gl-button>
+
+ <gl-button
+ v-if="!agentToken"
+ :disabled="modalBtnDisabled"
+ :loading="loading"
+ :data-track-action="$options.EVENT_ACTIONS_CLICK"
+ :data-track-label="$options.EVENT_LABEL_MODAL"
+ data-track-property="create-token"
+ variant="confirm"
+ type="submit"
+ @click="createToken"
+ >{{ $options.i18n.createTokenButton }}
+ </gl-button>
+
+ <gl-button
+ v-else
+ :data-track-action="$options.EVENT_ACTIONS_CLICK"
+ :data-track-label="$options.EVENT_LABEL_MODAL"
+ data-track-property="close"
+ variant="confirm"
+ @click="closeModal"
+ >{{ $options.i18n.modalClose }}
+ </gl-button>
+ </template>
+ </gl-modal>
+</template>
diff --git a/app/assets/javascripts/clusters/agents/components/revoke_token_button.vue b/app/assets/javascripts/clusters/agents/components/revoke_token_button.vue
index 7d36cbb170d..f0af0da4bb4 100644
--- a/app/assets/javascripts/clusters/agents/components/revoke_token_button.vue
+++ b/app/assets/javascripts/clusters/agents/components/revoke_token_button.vue
@@ -148,7 +148,7 @@ export default {
},
hideModal() {
this.resetModal();
- this.$refs.modal.hide();
+ this.$refs.modal?.hide();
},
},
};
diff --git a/app/assets/javascripts/clusters/agents/components/token_table.vue b/app/assets/javascripts/clusters/agents/components/token_table.vue
index 9e64c9da712..f74d66f6b8f 100644
--- a/app/assets/javascripts/clusters/agents/components/token_table.vue
+++ b/app/assets/javascripts/clusters/agents/components/token_table.vue
@@ -3,6 +3,7 @@ import { GlEmptyState, GlTable, GlTooltip, GlTruncate } from '@gitlab/ui';
import { s__ } from '~/locale';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import CreateTokenButton from './create_token_button.vue';
+import CreateTokenModal from './create_token_modal.vue';
import RevokeTokenButton from './revoke_token_button.vue';
export default {
@@ -13,6 +14,7 @@ export default {
GlTruncate,
TimeAgoTooltip,
CreateTokenButton,
+ CreateTokenModal,
RevokeTokenButton,
},
i18n: {
@@ -85,57 +87,57 @@ export default {
</script>
<template>
- <div v-if="tokens.length">
- <create-token-button
- class="gl-text-right gl-my-5"
- :cluster-agent-id="clusterAgentId"
- :cursor="cursor"
- />
+ <div>
+ <div v-if="tokens.length">
+ <create-token-button class="gl-text-right gl-my-5" />
- <gl-table
- :items="tokens"
- :fields="fields"
- fixed
- stacked="md"
- head-variant="white"
- thead-class="gl-border-b-solid gl-border-b-2 gl-border-b-gray-100"
- >
- <template #cell(lastUsed)="{ item }">
- <time-ago-tooltip v-if="item.lastUsedAt" :time="item.lastUsedAt" />
- <span v-else>{{ $options.i18n.neverUsed }}</span>
- </template>
+ <gl-table
+ :items="tokens"
+ :fields="fields"
+ fixed
+ stacked="md"
+ head-variant="white"
+ thead-class="gl-border-b-solid gl-border-b-2 gl-border-b-gray-100"
+ >
+ <template #cell(lastUsed)="{ item }">
+ <time-ago-tooltip v-if="item.lastUsedAt" :time="item.lastUsedAt" />
+ <span v-else>{{ $options.i18n.neverUsed }}</span>
+ </template>
- <template #cell(createdAt)="{ item }">
- <time-ago-tooltip :time="item.createdAt" />
- </template>
+ <template #cell(createdAt)="{ item }">
+ <time-ago-tooltip :time="item.createdAt" />
+ </template>
- <template #cell(createdBy)="{ item }">
- <span>{{ createdByName(item) }}</span>
- </template>
+ <template #cell(createdBy)="{ item }">
+ <span>{{ createdByName(item) }}</span>
+ </template>
- <template #cell(description)="{ item }">
- <div v-if="item.description" :id="`tooltip-description-container-${item.id}`">
- <gl-truncate :id="`tooltip-description-${item.id}`" :text="item.description" />
+ <template #cell(description)="{ item }">
+ <div v-if="item.description" :id="`tooltip-description-container-${item.id}`">
+ <gl-truncate :id="`tooltip-description-${item.id}`" :text="item.description" />
- <gl-tooltip
- :container="`tooltip-description-container-${item.id}`"
- :target="`tooltip-description-${item.id}`"
- placement="top"
- >
- {{ item.description }}
- </gl-tooltip>
- </div>
- </template>
+ <gl-tooltip
+ :container="`tooltip-description-container-${item.id}`"
+ :target="`tooltip-description-${item.id}`"
+ placement="top"
+ >
+ {{ item.description }}
+ </gl-tooltip>
+ </div>
+ </template>
- <template #cell(actions)="{ item }">
- <revoke-token-button :token="item" :cluster-agent-id="clusterAgentId" :cursor="cursor" />
+ <template #cell(actions)="{ item }">
+ <revoke-token-button :token="item" :cluster-agent-id="clusterAgentId" :cursor="cursor" />
+ </template>
+ </gl-table>
+ </div>
+
+ <gl-empty-state v-else :title="$options.i18n.noTokens">
+ <template #actions>
+ <create-token-button />
</template>
- </gl-table>
- </div>
+ </gl-empty-state>
- <gl-empty-state v-else :title="$options.i18n.noTokens">
- <template #actions>
- <create-token-button :cluster-agent-id="clusterAgentId" :cursor="cursor" />
- </template>
- </gl-empty-state>
+ <create-token-modal :cluster-agent-id="clusterAgentId" :cursor="cursor" />
+ </div>
</template>
diff --git a/app/assets/javascripts/projects/project_new.js b/app/assets/javascripts/projects/project_new.js
index 2c2f957a75d..186946a83ad 100644
--- a/app/assets/javascripts/projects/project_new.js
+++ b/app/assets/javascripts/projects/project_new.js
@@ -276,28 +276,33 @@ const bindEvents = () => {
);
let isProjectImportUrlDirty = false;
- $projectImportUrl.addEventListener('blur', () => {
- isProjectImportUrlDirty = true;
- debouncedUpdateUrlPathWarningVisibility();
- });
- $projectImportUrl.addEventListener('keyup', () => {
- deriveProjectPathFromUrl($projectImportUrl);
- });
+
+ if ($projectImportUrl) {
+ $projectImportUrl.addEventListener('blur', () => {
+ isProjectImportUrlDirty = true;
+ debouncedUpdateUrlPathWarningVisibility();
+ });
+ $projectImportUrl.addEventListener('keyup', () => {
+ deriveProjectPathFromUrl($projectImportUrl);
+ });
+ }
[$projectImportUrl, $projectImportUrlUser, $projectImportUrlPassword].forEach(($f) => {
- if ($f?.on) {
- $f.on('input', () => {
- if (isProjectImportUrlDirty) {
- debouncedUpdateUrlPathWarningVisibility();
- }
- });
- } else {
- $f.addEventListener('input', () => {
+ if (!$f) return false;
+
+ if ($f.on) {
+ return $f.on('input', () => {
if (isProjectImportUrlDirty) {
debouncedUpdateUrlPathWarningVisibility();
}
});
}
+
+ return $f.addEventListener('input', () => {
+ if (isProjectImportUrlDirty) {
+ debouncedUpdateUrlPathWarningVisibility();
+ }
+ });
});
$projectImportForm.on('submit', async (e) => {
diff --git a/app/uploaders/object_storage.rb b/app/uploaders/object_storage.rb
index 1d56cddca63..891df5180d8 100644
--- a/app/uploaders/object_storage.rb
+++ b/app/uploaders/object_storage.rb
@@ -353,6 +353,20 @@ module ObjectStorage
}
end
+ def store_path(*args)
+ if self.object_store == Store::REMOTE
+ # We allow administrators to create "sub buckets" by setting a prefix.
+ # This makes it possible to deploy GitLab with only one object storage
+ # bucket. Because the prefix is configuration data we do not want to
+ # store it in the uploads table via RecordsUploads. That means that the
+ # prefix cannot be part of store_dir. This is why we chose to implement
+ # the prefix support here in store_path.
+ File.join([self.class.object_store_options.bucket_prefix, super].compact)
+ else
+ super
+ end
+ end
+
# Returns all the possible paths for an upload.
# the `upload.path` is a lookup parameter, and it may change
# depending on the `store` param.
diff --git a/app/workers/namespaces/process_sync_events_worker.rb b/app/workers/namespaces/process_sync_events_worker.rb
index 36c4ab2058d..2bf2a4a6ef8 100644
--- a/app/workers/namespaces/process_sync_events_worker.rb
+++ b/app/workers/namespaces/process_sync_events_worker.rb
@@ -13,7 +13,7 @@ module Namespaces
urgency :high
idempotent!
- deduplicate :until_executed
+ deduplicate :until_executing
def perform
results = ::Ci::ProcessSyncEventsService.new(
diff --git a/app/workers/projects/process_sync_events_worker.rb b/app/workers/projects/process_sync_events_worker.rb
index 92322a9ea99..57f3e3dee5e 100644
--- a/app/workers/projects/process_sync_events_worker.rb
+++ b/app/workers/projects/process_sync_events_worker.rb
@@ -13,7 +13,7 @@ module Projects
urgency :high
idempotent!
- deduplicate :until_executed
+ deduplicate :until_executing
def perform
results = ::Ci::ProcessSyncEventsService.new(