diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-06-29 15:08:48 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-06-29 15:08:48 +0300 |
commit | e5f2a04e9d54615fded2ca05d0d5eef464795a8f (patch) | |
tree | 5412fccdb0a63b449fba4d7998eaa05ca70091ba /app | |
parent | ad2789aeba21edaadcbdc06523462e6fd87d4ba1 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
47 files changed, 240 insertions, 212 deletions
diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js index 41cc2036a6b..1bb19208828 100644 --- a/app/assets/javascripts/api.js +++ b/app/assets/javascripts/api.js @@ -83,8 +83,8 @@ const Api = { tagsPath: '/api/:version/projects/:id/repository/tags', freezePeriodsPath: '/api/:version/projects/:id/freeze_periods', freezePeriodPath: '/api/:version/projects/:id/freeze_periods/:freeze_period_id', - usageDataIncrementCounterPath: '/api/:version/usage_data/increment_counter', - usageDataIncrementUniqueUsersPath: '/api/:version/usage_data/increment_unique_users', + serviceDataIncrementCounterPath: '/api/:version/usage_data/increment_counter', + serviceDataIncrementUniqueUsersPath: '/api/:version/usage_data/increment_unique_users', featureFlagUserLists: '/api/:version/projects/:id/feature_flags_user_lists', featureFlagUserList: '/api/:version/projects/:id/feature_flags_user_lists/:list_iid', containerRegistryDetailsPath: '/api/:version/registry/repositories/:id/', @@ -875,7 +875,7 @@ const Api = { return null; } - const url = Api.buildUrl(this.usageDataIncrementCounterPath); + const url = Api.buildUrl(this.serviceDataIncrementCounterPath); const headers = { 'Content-Type': 'application/json', }; @@ -888,7 +888,7 @@ const Api = { return null; } - const url = Api.buildUrl(this.usageDataIncrementUniqueUsersPath); + const url = Api.buildUrl(this.serviceDataIncrementUniqueUsersPath); const headers = { 'Content-Type': 'application/json', }; diff --git a/app/assets/javascripts/design_management/pages/design/index.vue b/app/assets/javascripts/design_management/pages/design/index.vue index ad78433c7ce..19bfa123487 100644 --- a/app/assets/javascripts/design_management/pages/design/index.vue +++ b/app/assets/javascripts/design_management/pages/design/index.vue @@ -41,7 +41,7 @@ import { TOGGLE_TODO_ERROR, designDeletionError, } from '../../utils/error_messages'; -import { trackDesignDetailView, usagePingDesignDetailView } from '../../utils/tracking'; +import { trackDesignDetailView, servicePingDesignDetailView } from '../../utils/tracking'; const DEFAULT_SCALE = 1; @@ -292,7 +292,7 @@ export default { ); if (this.glFeatures.usageDataDesignAction) { - usagePingDesignDetailView(); + servicePingDesignDetailView(); } }, updateActiveDiscussion(id, source = ACTIVE_DISCUSSION_SOURCE_TYPES.discussion) { diff --git a/app/assets/javascripts/design_management/utils/tracking.js b/app/assets/javascripts/design_management/utils/tracking.js index 905134fa985..23aec46c152 100644 --- a/app/assets/javascripts/design_management/utils/tracking.js +++ b/app/assets/javascripts/design_management/utils/tracking.js @@ -14,7 +14,7 @@ export const DESIGN_SNOWPLOW_EVENT_TYPES = { UPDATE_DESIGN: 'update_design', }; -export const DESIGN_USAGE_PING_EVENT_TYPES = { +export const DESIGN_SERVICE_PING_EVENT_TYPES = { DESIGN_ACTION: 'design_action', }; @@ -52,8 +52,8 @@ export function trackDesignUpdate() { } /** - * Track "design detail" view via usage ping + * Track "design detail" view via service ping */ -export function usagePingDesignDetailView() { - Api.trackRedisHllUserEvent(DESIGN_USAGE_PING_EVENT_TYPES.DESIGN_ACTION); +export function servicePingDesignDetailView() { + Api.trackRedisHllUserEvent(DESIGN_SERVICE_PING_EVENT_TYPES.DESIGN_ACTION); } diff --git a/app/assets/javascripts/issues_list/components/issues_list_app.vue b/app/assets/javascripts/issues_list/components/issues_list_app.vue index 051512e9a66..583f8b6ed17 100644 --- a/app/assets/javascripts/issues_list/components/issues_list_app.vue +++ b/app/assets/javascripts/issues_list/components/issues_list_app.vue @@ -11,6 +11,7 @@ import { import fuzzaldrinPlus from 'fuzzaldrin-plus'; import getIssuesQuery from 'ee_else_ce/issues_list/queries/get_issues.query.graphql'; import createFlash from '~/flash'; +import { convertToGraphQLId } from '~/graphql_shared/utils'; import CsvImportExportButtons from '~/issuable/components/csv_import_export_buttons.vue'; import IssuableByEmail from '~/issuable/components/issuable_by_email.vue'; import IssuableList from '~/issuable_list/components/issuable_list_root.vue'; @@ -70,6 +71,10 @@ import LabelToken from '~/vue_shared/components/filtered_search_bar/tokens/label import MilestoneToken from '~/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue'; import WeightToken from '~/vue_shared/components/filtered_search_bar/tokens/weight_token.vue'; import eventHub from '../eventhub'; +import searchIterationsQuery from '../queries/search_iterations.query.graphql'; +import searchLabelsQuery from '../queries/search_labels.query.graphql'; +import searchMilestonesQuery from '../queries/search_milestones.query.graphql'; +import searchUsersQuery from '../queries/search_users.query.graphql'; import IssueCardTimeInfo from './issue_card_time_info.vue'; export default { @@ -94,9 +99,6 @@ export default { autocompleteAwardEmojisPath: { default: '', }, - autocompleteUsersPath: { - default: '', - }, calendarPath: { default: '', }, @@ -118,6 +120,9 @@ export default { hasIssueWeightsFeature: { default: false, }, + hasIterationsFeature: { + default: false, + }, hasMultipleIssueAssigneesFeature: { default: false, }, @@ -139,15 +144,6 @@ export default { newIssuePath: { default: '', }, - projectIterationsPath: { - default: '', - }, - projectLabelsPath: { - default: '', - }, - projectMilestonesPath: { - default: '', - }, projectPath: { default: '', }, @@ -233,7 +229,7 @@ export default { if (gon.current_user_id) { preloadedAuthors.push({ - id: gon.current_user_id, + id: convertToGraphQLId('User', gon.current_user_id), // eslint-disable-line @gitlab/require-i18n-strings name: gon.current_user_fullname, username: gon.current_username, avatar_url: gon.current_user_avatar_url, @@ -308,7 +304,7 @@ export default { }); } - if (this.projectIterationsPath) { + if (this.hasIterationsFeature) { tokens.push({ type: TOKEN_TYPE_ITERATION, title: TOKEN_TITLE_ITERATION, @@ -407,19 +403,42 @@ export default { : epics.filter((epic) => epic.id === number); }, fetchLabels(search) { - return this.fetchWithCache(this.projectLabelsPath, 'labels', 'title', search); + return this.$apollo + .query({ + query: searchLabelsQuery, + variables: { projectPath: this.projectPath, search }, + }) + .then(({ data }) => data.project.labels.nodes); }, fetchMilestones(search) { - return this.fetchWithCache(this.projectMilestonesPath, 'milestones', 'title', search, true); + return this.$apollo + .query({ + query: searchMilestonesQuery, + variables: { projectPath: this.projectPath, search }, + }) + .then(({ data }) => data.project.milestones.nodes); }, fetchIterations(search) { const id = Number(search); - return !search || Number.isNaN(id) - ? axios.get(this.projectIterationsPath, { params: { search } }) - : axios.get(this.projectIterationsPath, { params: { id } }); + const variables = + !search || Number.isNaN(id) + ? { projectPath: this.projectPath, search } + : { projectPath: this.projectPath, id }; + + return this.$apollo + .query({ + query: searchIterationsQuery, + variables, + }) + .then(({ data }) => data.project.iterations.nodes); }, fetchUsers(search) { - return axios.get(this.autocompleteUsersPath, { params: { search } }); + return this.$apollo + .query({ + query: searchUsersQuery, + variables: { projectPath: this.projectPath, search }, + }) + .then(({ data }) => data.project.projectMembers.nodes.map((member) => member.user)); }, getExportCsvPathWithQuery() { return `${this.exportCsvPath}${window.location.search}`; diff --git a/app/assets/javascripts/issues_list/index.js b/app/assets/javascripts/issues_list/index.js index 97b9a9a115d..dc73d8c7cc8 100644 --- a/app/assets/javascripts/issues_list/index.js +++ b/app/assets/javascripts/issues_list/index.js @@ -82,7 +82,6 @@ export function mountIssuesListApp() { const { autocompleteAwardEmojisPath, - autocompleteUsersPath, calendarPath, canBulkUpdate, canEdit, @@ -95,6 +94,7 @@ export function mountIssuesListApp() { hasBlockedIssuesFeature, hasIssuableHealthStatusFeature, hasIssueWeightsFeature, + hasIterationsFeature, hasMultipleIssueAssigneesFeature, hasProjectIssues, importCsvIssuesPath, @@ -106,9 +106,6 @@ export function mountIssuesListApp() { maxAttachmentSize, newIssuePath, projectImportJiraPath, - projectIterationsPath, - projectLabelsPath, - projectMilestonesPath, projectPath, quickActionsHelpPath, resetPath, @@ -122,7 +119,6 @@ export function mountIssuesListApp() { apolloProvider, provide: { autocompleteAwardEmojisPath, - autocompleteUsersPath, calendarPath, canBulkUpdate: parseBoolean(canBulkUpdate), emptyStateSvgPath, @@ -130,15 +126,13 @@ export function mountIssuesListApp() { hasBlockedIssuesFeature: parseBoolean(hasBlockedIssuesFeature), hasIssuableHealthStatusFeature: parseBoolean(hasIssuableHealthStatusFeature), hasIssueWeightsFeature: parseBoolean(hasIssueWeightsFeature), + hasIterationsFeature: parseBoolean(hasIterationsFeature), hasMultipleIssueAssigneesFeature: parseBoolean(hasMultipleIssueAssigneesFeature), hasProjectIssues: parseBoolean(hasProjectIssues), isSignedIn: parseBoolean(isSignedIn), issuesPath, jiraIntegrationPath, newIssuePath, - projectIterationsPath, - projectLabelsPath, - projectMilestonesPath, projectPath, rssPath, showNewIssueLink: parseBoolean(showNewIssueLink), diff --git a/app/assets/javascripts/issues_list/queries/search_iterations.query.graphql b/app/assets/javascripts/issues_list/queries/search_iterations.query.graphql new file mode 100644 index 00000000000..11d9dcea573 --- /dev/null +++ b/app/assets/javascripts/issues_list/queries/search_iterations.query.graphql @@ -0,0 +1,10 @@ +query searchIterations($projectPath: ID!, $search: String, $id: ID) { + project(fullPath: $projectPath) { + iterations(title: $search, id: $id) { + nodes { + id + title + } + } + } +} diff --git a/app/assets/javascripts/issues_list/queries/search_labels.query.graphql b/app/assets/javascripts/issues_list/queries/search_labels.query.graphql new file mode 100644 index 00000000000..de884e1221c --- /dev/null +++ b/app/assets/javascripts/issues_list/queries/search_labels.query.graphql @@ -0,0 +1,12 @@ +query searchLabels($projectPath: ID!, $search: String) { + project(fullPath: $projectPath) { + labels(searchTerm: $search, includeAncestorGroups: true) { + nodes { + id + color + textColor + title + } + } + } +} diff --git a/app/assets/javascripts/issues_list/queries/search_milestones.query.graphql b/app/assets/javascripts/issues_list/queries/search_milestones.query.graphql new file mode 100644 index 00000000000..91f74fd220b --- /dev/null +++ b/app/assets/javascripts/issues_list/queries/search_milestones.query.graphql @@ -0,0 +1,10 @@ +query searchMilestones($projectPath: ID!, $search: String) { + project(fullPath: $projectPath) { + milestones(searchTitle: $search, includeAncestors: true) { + nodes { + id + title + } + } + } +} diff --git a/app/assets/javascripts/issues_list/queries/search_users.query.graphql b/app/assets/javascripts/issues_list/queries/search_users.query.graphql new file mode 100644 index 00000000000..953157cfe3a --- /dev/null +++ b/app/assets/javascripts/issues_list/queries/search_users.query.graphql @@ -0,0 +1,14 @@ +query searchUsers($projectPath: ID!, $search: String) { + project(fullPath: $projectPath) { + projectMembers(search: $search) { + nodes { + user { + id + avatarUrl + name + username + } + } + } + } +} diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index 2309f7a420f..63c25136f74 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -31,7 +31,7 @@ import initFrequentItemDropdowns from './frequent_items'; import initBreadcrumbs from './breadcrumb'; import initPersistentUserCallouts from './persistent_user_callouts'; import { initUserTracking, initDefaultTrackers } from './tracking'; -import initUsagePingConsent from './usage_ping_consent'; +import initServicePingConsent from './service_ping_consent'; import GlFieldErrors from './gl_field_errors'; import initUserPopovers from './user_popovers'; import initBroadcastNotifications from './broadcast_notification'; @@ -86,7 +86,7 @@ function deferredInitialisation() { initBreadcrumbs(); initTodoToggle(); initLogoAnimation(); - initUsagePingConsent(); + initServicePingConsent(); initUserPopovers(); initBroadcastNotifications(); initFrequentItemDropdowns(); diff --git a/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue b/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue index 452420314ed..c7de8516c86 100644 --- a/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue +++ b/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue @@ -1,6 +1,7 @@ <script> import { GlLoadingIcon } from '@gitlab/ui'; import { fetchPolicies } from '~/lib/graphql'; +import { queryToObject } from '~/lib/utils/url_utility'; import { s__ } from '~/locale'; import { unwrapStagesWithNeeds } from '~/pipelines/components/unwrapping_utils'; @@ -41,6 +42,7 @@ export default { }, data() { return { + starterTemplateName: STARTER_TEMPLATE_NAME, ciConfigData: {}, failureType: null, failureReasons: [], @@ -160,7 +162,7 @@ export default { variables() { return { projectPath: this.projectFullPath, - templateName: STARTER_TEMPLATE_NAME, + templateName: this.starterTemplateName, }; }, skip({ isNewCiConfigFile }) { @@ -203,6 +205,9 @@ export default { } }, }, + mounted() { + this.loadTemplateFromURL(); + }, methods: { hideFailure() { this.showFailure = false; @@ -258,6 +263,14 @@ export default { // if the user has made changes to the file that are unsaved. this.lastCommittedContent = this.currentCiFileContent; }, + loadTemplateFromURL() { + const templateName = queryToObject(window.location.search)?.template; + + if (templateName) { + this.starterTemplateName = templateName; + this.setNewEmptyCiConfigFile(); + } + }, }, }; </script> diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/empty_state.vue b/app/assets/javascripts/pipelines/components/pipelines_list/empty_state.vue index 104a3caab4c..1ce6654e0e9 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_list/empty_state.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_list/empty_state.vue @@ -16,7 +16,6 @@ export default { consuming tasks, so you can spend more time creating.`), aboutRunnersBtnText: s__('Pipelines|Learn about Runners'), installRunnersBtnText: s__('Pipelines|Install GitLab Runners'), - getStartedBtnText: s__('Pipelines|Get started with CI/CD'), codeQualityTitle: s__('Pipelines|Improve code quality with GitLab CI/CD'), codeQualityDescription: s__(`Pipelines|To keep your codebase simple, readable, and accessible to contributors, use GitLab CI/CD @@ -55,9 +54,6 @@ export default { ciHelpPagePath() { return helpPagePath('ci/quick_start/index.md'); }, - isPipelineEmptyStateTemplatesExperimentActive() { - return this.canSetCi && Boolean(getExperimentData('pipeline_empty_state_templates')); - }, isCodeQualityExperimentActive() { return this.canSetCi && Boolean(getExperimentData('code_quality_walkthrough')); }, @@ -81,37 +77,8 @@ export default { </script> <template> <div> - <gitlab-experiment - v-if="isPipelineEmptyStateTemplatesExperimentActive" - name="pipeline_empty_state_templates" - > - <template #control> - <gl-empty-state - :title="$options.i18n.title" - :svg-path="emptyStateSvgPath" - :description="$options.i18n.description" - :primary-button-text="$options.i18n.getStartedBtnText" - :primary-button-link="ciHelpPagePath" - /> - </template> - <template #candidate> - <pipelines-ci-templates /> - </template> - </gitlab-experiment> - <gitlab-experiment v-else-if="isCodeQualityExperimentActive" name="code_quality_walkthrough"> - <template #control> - <gl-empty-state - :title="$options.i18n.title" - :svg-path="emptyStateSvgPath" - :description="$options.i18n.description" - > - <template #actions> - <gl-button :href="ciHelpPagePath" variant="confirm" @click="trackClick()"> - {{ $options.i18n.getStartedBtnText }} - </gl-button> - </template> - </gl-empty-state> - </template> + <gitlab-experiment v-if="isCodeQualityExperimentActive" name="code_quality_walkthrough"> + <template #control><pipelines-ci-templates /></template> <template #candidate> <gl-empty-state :title="$options.i18n.codeQualityTitle" @@ -127,23 +94,7 @@ export default { </template> </gitlab-experiment> <gitlab-experiment v-else-if="isCiRunnerTemplatesExperimentActive" name="ci_runner_templates"> - <template #control> - <gl-empty-state - :title="$options.i18n.title" - :svg-path="emptyStateSvgPath" - :description="$options.i18n.description" - > - <template #actions> - <gl-button - :href="ciHelpPagePath" - variant="confirm" - @click="trackCiRunnerTemplatesClick('get_started_button_clicked')" - > - {{ $options.i18n.getStartedBtnText }} - </gl-button> - </template> - </gl-empty-state> - </template> + <template #control><pipelines-ci-templates /></template> <template #candidate> <gl-empty-state :title="$options.i18n.title" @@ -169,14 +120,7 @@ export default { </gl-empty-state> </template> </gitlab-experiment> - <gl-empty-state - v-else-if="canSetCi" - :title="$options.i18n.title" - :svg-path="emptyStateSvgPath" - :description="$options.i18n.description" - :primary-button-text="$options.i18n.getStartedBtnText" - :primary-button-link="ciHelpPagePath" - /> + <pipelines-ci-templates v-else-if="canSetCi" /> <gl-empty-state v-else title="" diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_ci_templates.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_ci_templates.vue index 9bb6075c050..c6c81d5253b 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_ci_templates.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_ci_templates.vue @@ -1,9 +1,9 @@ <script> import { GlAvatar, GlButton, GlCard, GlSprintf } from '@gitlab/ui'; -import ExperimentTracking from '~/experimentation/experiment_tracking'; import { mergeUrlParams } from '~/lib/utils/url_utility'; import { s__, sprintf } from '~/locale'; -import { HELLO_WORLD_TEMPLATE_KEY } from '../../constants'; +import { STARTER_TEMPLATE_NAME } from '~/pipeline_editor/constants'; +import Tracking from '~/tracking'; export default { components: { @@ -12,7 +12,8 @@ export default { GlCard, GlSprintf, }, - HELLO_WORLD_TEMPLATE_KEY, + mixins: [Tracking.mixin()], + STARTER_TEMPLATE_NAME, i18n: { cta: s__('Pipelines|Use template'), testTemplates: { @@ -20,10 +21,10 @@ export default { subtitle: s__( 'Pipelines|Use a sample %{codeStart}.gitlab-ci.yml%{codeEnd} template file to explore how CI/CD works.', ), - helloWorld: { - title: s__('Pipelines|“Hello world” with GitLab CI/CD'), + gettingStarted: { + title: s__('Pipelines|Get started with GitLab CI/CD'), description: s__( - 'Pipelines|Get familiar with GitLab CI/CD syntax by starting with a simple pipeline that runs a “Hello world” script.', + 'Pipelines|Get familiar with GitLab CI/CD syntax by starting with a basic 3 stage CI/CD pipeline.', ), }, }, @@ -35,31 +36,30 @@ export default { description: s__('Pipelines|CI/CD template to test and deploy your %{name} project.'), }, }, - inject: ['addCiYmlPath', 'suggestedCiTemplates'], + inject: ['pipelineEditorPath', 'suggestedCiTemplates'], data() { const templates = this.suggestedCiTemplates.map(({ name, logo }) => { return { name, logo, - link: mergeUrlParams({ template: name }, this.addCiYmlPath), + link: mergeUrlParams({ template: name }, this.pipelineEditorPath), description: sprintf(this.$options.i18n.templates.description, { name }), }; }); return { templates, - helloWorldTemplateUrl: mergeUrlParams( - { template: HELLO_WORLD_TEMPLATE_KEY }, - this.addCiYmlPath, + gettingStartedTemplateUrl: mergeUrlParams( + { template: STARTER_TEMPLATE_NAME }, + this.pipelineEditorPath, ), }; }, methods: { trackEvent(template) { - const tracking = new ExperimentTracking('pipeline_empty_state_templates', { + this.track('template_clicked', { label: template, }); - tracking.event('template_clicked'); }, }, }; @@ -82,18 +82,18 @@ export default { <div class="gl-py-5"><gl-emoji class="gl-font-size-h2-xl" data-name="wave" /></div> <div class="gl-mb-3"> <strong class="gl-text-gray-800 gl-mb-2">{{ - $options.i18n.testTemplates.helloWorld.title + $options.i18n.testTemplates.gettingStarted.title }}</strong> </div> - <p class="gl-font-sm">{{ $options.i18n.testTemplates.helloWorld.description }}</p> + <p class="gl-font-sm">{{ $options.i18n.testTemplates.gettingStarted.description }}</p> </div> <gl-button category="primary" variant="confirm" - :href="helloWorldTemplateUrl" + :href="gettingStartedTemplateUrl" data-testid="test-template-link" - @click="trackEvent($options.HELLO_WORLD_TEMPLATE_KEY)" + @click="trackEvent($options.STARTER_TEMPLATE_NAME)" > {{ $options.i18n.cta }} </gl-button> diff --git a/app/assets/javascripts/pipelines/constants.js b/app/assets/javascripts/pipelines/constants.js index 01705e7726f..21b114825a6 100644 --- a/app/assets/javascripts/pipelines/constants.js +++ b/app/assets/javascripts/pipelines/constants.js @@ -35,6 +35,3 @@ export const POST_FAILURE = 'post_failure'; export const UNSUPPORTED_DATA = 'unsupported_data'; export const CHILD_VIEW = 'child'; - -// The key of the template is the same as the filename -export const HELLO_WORLD_TEMPLATE_KEY = 'Hello-World'; diff --git a/app/assets/javascripts/pipelines/pipelines_index.js b/app/assets/javascripts/pipelines/pipelines_index.js index 925a96ea1aa..c4c2b5f2927 100644 --- a/app/assets/javascripts/pipelines/pipelines_index.js +++ b/app/assets/javascripts/pipelines/pipelines_index.js @@ -29,7 +29,7 @@ export const initPipelinesIndex = (selector = '#pipelines-list-vue') => { errorStateSvgPath, noPipelinesSvgPath, newPipelinePath, - addCiYmlPath, + pipelineEditorPath, suggestedCiTemplates, canCreatePipeline, hasGitlabCi, @@ -44,7 +44,7 @@ export const initPipelinesIndex = (selector = '#pipelines-list-vue') => { return new Vue({ el, provide: { - addCiYmlPath, + pipelineEditorPath, artifactsEndpoint, artifactsEndpointPlaceholder, suggestedCiTemplates: JSON.parse(suggestedCiTemplates), diff --git a/app/assets/javascripts/usage_ping_consent.js b/app/assets/javascripts/service_ping_consent.js index 621a8d9d3b6..f145a1b30db 100644 --- a/app/assets/javascripts/usage_ping_consent.js +++ b/app/assets/javascripts/service_ping_consent.js @@ -5,19 +5,20 @@ import { parseBoolean } from './lib/utils/common_utils'; import { __ } from './locale'; export default () => { - $('body').on('click', '.js-usage-consent-action', (e) => { + $('body').on('click', '.js-service-ping-consent-action', (e) => { e.preventDefault(); e.stopImmediatePropagation(); // overwrite rails listener - const { url, checkEnabled, pingEnabled } = e.target.dataset; + const { url, checkEnabled, servicePingEnabled } = e.target.dataset; const data = { application_setting: { version_check_enabled: parseBoolean(checkEnabled), - usage_ping_enabled: parseBoolean(pingEnabled), + service_ping_enabled: parseBoolean(servicePingEnabled), }, }; - const hideConsentMessage = () => hideFlash(document.querySelector('.ping-consent-message')); + const hideConsentMessage = () => + hideFlash(document.querySelector('.service-ping-consent-message')); axios .put(url, data) diff --git a/app/assets/javascripts/static_site_editor/constants.js b/app/assets/javascripts/static_site_editor/constants.js index b08bf26e1dc..ab7fd0542bf 100644 --- a/app/assets/javascripts/static_site_editor/constants.js +++ b/app/assets/javascripts/static_site_editor/constants.js @@ -28,7 +28,8 @@ export const TRACKING_ACTION_CREATE_COMMIT = 'create_commit'; export const TRACKING_ACTION_CREATE_MERGE_REQUEST = 'create_merge_request'; export const TRACKING_ACTION_INITIALIZE_EDITOR = 'initialize_editor'; -export const USAGE_PING_TRACKING_ACTION_CREATE_COMMIT = 'static_site_editor_commits'; -export const USAGE_PING_TRACKING_ACTION_CREATE_MERGE_REQUEST = 'static_site_editor_merge_requests'; +export const SERVICE_PING_TRACKING_ACTION_CREATE_COMMIT = 'static_site_editor_commits'; +export const SERVICE_PING_TRACKING_ACTION_CREATE_MERGE_REQUEST = + 'static_site_editor_merge_requests'; export const MR_META_LOCAL_STORAGE_KEY = 'sse-merge-request-meta-storage-key'; diff --git a/app/assets/javascripts/static_site_editor/services/submit_content_changes.js b/app/assets/javascripts/static_site_editor/services/submit_content_changes.js index ecb7f60a421..99534413d92 100644 --- a/app/assets/javascripts/static_site_editor/services/submit_content_changes.js +++ b/app/assets/javascripts/static_site_editor/services/submit_content_changes.js @@ -9,8 +9,8 @@ import { SUBMIT_CHANGES_MERGE_REQUEST_ERROR, TRACKING_ACTION_CREATE_COMMIT, TRACKING_ACTION_CREATE_MERGE_REQUEST, - USAGE_PING_TRACKING_ACTION_CREATE_COMMIT, - USAGE_PING_TRACKING_ACTION_CREATE_MERGE_REQUEST, + SERVICE_PING_TRACKING_ACTION_CREATE_COMMIT, + SERVICE_PING_TRACKING_ACTION_CREATE_MERGE_REQUEST, DEFAULT_FORMATTING_CHANGES_COMMIT_MESSAGE, DEFAULT_FORMATTING_CHANGES_COMMIT_DESCRIPTION, } from '../constants'; @@ -58,7 +58,7 @@ const createUpdateSourceFileAction = (sourcePath, content) => [ const commit = (projectId, message, branch, actions) => { Tracking.event(document.body.dataset.page, TRACKING_ACTION_CREATE_COMMIT); - Api.trackRedisCounterEvent(USAGE_PING_TRACKING_ACTION_CREATE_COMMIT); + Api.trackRedisCounterEvent(SERVICE_PING_TRACKING_ACTION_CREATE_COMMIT); return Api.commitMultiple( projectId, @@ -74,7 +74,7 @@ const commit = (projectId, message, branch, actions) => { const createMergeRequest = (projectId, title, description, sourceBranch, targetBranch) => { Tracking.event(document.body.dataset.page, TRACKING_ACTION_CREATE_MERGE_REQUEST); - Api.trackRedisCounterEvent(USAGE_PING_TRACKING_ACTION_CREATE_MERGE_REQUEST); + Api.trackRedisCounterEvent(SERVICE_PING_TRACKING_ACTION_CREATE_MERGE_REQUEST); return Api.createProjectMergeRequest( projectId, diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/base_token.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/base_token.vue index 10be0099fb7..1fc845dfd79 100644 --- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/base_token.vue +++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/base_token.vue @@ -6,6 +6,7 @@ import { GlDropdownSectionHeader, GlLoadingIcon, } from '@gitlab/ui'; +import { debounce } from 'lodash'; import { DEBOUNCE_DELAY } from '../constants'; import { getRecentlyUsedSuggestions, setTokenValueToRecentlyUsed } from '../filtered_search_utils'; @@ -128,12 +129,12 @@ export default { }, }, methods: { - handleInput({ data }) { + handleInput: debounce(function debouncedSearch({ data }) { this.searchKey = data; - setTimeout(() => { - if (!this.suggestionsLoading) this.$emit('fetch-suggestions', data); - }, DEBOUNCE_DELAY); - }, + if (!this.suggestionsLoading) { + this.$emit('fetch-suggestions', data); + } + }, DEBOUNCE_DELAY), handleTokenValueSelected(activeTokenValue) { // Make sure that; // 1. Recently used values feature is enabled diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/iteration_token.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/iteration_token.vue index cdb04ea79e1..15260763329 100644 --- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/iteration_token.vue +++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/iteration_token.vue @@ -7,6 +7,7 @@ import { } from '@gitlab/ui'; import { debounce } from 'lodash'; import createFlash from '~/flash'; +import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { __ } from '~/locale'; import { DEBOUNCE_DELAY, DEFAULT_ITERATIONS } from '../constants'; @@ -30,7 +31,7 @@ export default { data() { return { iterations: this.config.initialIterations || [], - loading: true, + loading: false, }; }, computed: { @@ -38,7 +39,9 @@ export default { return this.value.data; }, activeIteration() { - return this.iterations.find((iteration) => iteration.id === Number(this.currentValue)); + return this.iterations.find( + (iteration) => getIdFromGraphQLId(iteration.id) === Number(this.currentValue), + ); }, defaultIterations() { return this.config.defaultIterations || DEFAULT_ITERATIONS; @@ -55,6 +58,9 @@ export default { }, }, methods: { + getValue(iteration) { + return String(getIdFromGraphQLId(iteration.id)); + }, fetchIterationBySearchTerm(searchTerm) { const fetchPromise = this.config.fetchPath ? this.config.fetchIterations(this.config.fetchPath, searchTerm) @@ -102,7 +108,7 @@ export default { <gl-filtered-search-suggestion v-for="iteration in iterations" :key="iteration.id" - :value="String(iteration.id)" + :value="getValue(iteration)" > {{ iteration.title }} </gl-filtered-search-suggestion> diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue index 4099ac6071c..16738ae52c5 100644 --- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue +++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue @@ -35,7 +35,7 @@ export default { return { milestones: this.config.initialMilestones || [], defaultMilestones: this.config.defaultMilestones || DEFAULT_MILESTONES, - loading: true, + loading: false, }; }, computed: { @@ -60,11 +60,16 @@ export default { }, methods: { fetchMilestoneBySearchTerm(searchTerm = '') { + if (this.loading) { + return; + } + this.loading = true; this.config .fetchMilestones(searchTerm) - .then(({ data }) => { - this.milestones = data.sort(sortMilestonesByDueDate); + .then((response) => { + const data = Array.isArray(response) ? response : response.data; + this.milestones = data.slice().sort(sortMilestonesByDueDate); }) .catch(() => createFlash({ message: __('There was a problem fetching milestones.') })) .finally(() => { diff --git a/app/assets/stylesheets/page_bundles/admin/application_settings_metrics_and_profiling.scss b/app/assets/stylesheets/page_bundles/admin/application_settings_metrics_and_profiling.scss index 41bb6d107f1..db81cc7fdd4 100644 --- a/app/assets/stylesheets/page_bundles/admin/application_settings_metrics_and_profiling.scss +++ b/app/assets/stylesheets/page_bundles/admin/application_settings_metrics_and_profiling.scss @@ -1,3 +1,3 @@ -.usage-data { +.service-data-payload-container { max-height: 400px; } diff --git a/app/controllers/concerns/authenticates_with_two_factor.rb b/app/controllers/concerns/authenticates_with_two_factor.rb index 4f4b204def8..da5b7ccfbf0 100644 --- a/app/controllers/concerns/authenticates_with_two_factor.rb +++ b/app/controllers/concerns/authenticates_with_two_factor.rb @@ -151,14 +151,14 @@ module AuthenticatesWithTwoFactor def handle_two_factor_failure(user, method, message) user.increment_failed_attempts! - log_failed_two_factor(user, method, request.remote_ip) + log_failed_two_factor(user, method) Gitlab::AppLogger.info("Failed Login: user=#{user.username} ip=#{request.remote_ip} method=#{method}") flash.now[:alert] = message prompt_for_two_factor(user) end - def log_failed_two_factor(user, method, ip_address) + def log_failed_two_factor(user, method) # overridden in EE end diff --git a/app/controllers/concerns/authenticates_with_two_factor_for_admin_mode.rb b/app/controllers/concerns/authenticates_with_two_factor_for_admin_mode.rb index a8155f1e639..574fc6c0f37 100644 --- a/app/controllers/concerns/authenticates_with_two_factor_for_admin_mode.rb +++ b/app/controllers/concerns/authenticates_with_two_factor_for_admin_mode.rb @@ -98,7 +98,7 @@ module AuthenticatesWithTwoFactorForAdminMode def admin_handle_two_factor_failure(user, method, message) user.increment_failed_attempts! - log_failed_two_factor(user, method, request.remote_ip) + log_failed_two_factor(user, method) Gitlab::AppLogger.info("Failed Admin Mode Login: user=#{user.username} ip=#{request.remote_ip} method=#{method}") flash.now[:alert] = message diff --git a/app/controllers/projects/artifacts_controller.rb b/app/controllers/projects/artifacts_controller.rb index f6a92b07295..7bb3ed1d109 100644 --- a/app/controllers/projects/artifacts_controller.rb +++ b/app/controllers/projects/artifacts_controller.rb @@ -15,7 +15,7 @@ class Projects::ArtifactsController < Projects::ApplicationController MAX_PER_PAGE = 20 - feature_category :continuous_integration + feature_category :build_artifacts def index # Loading artifacts is very expensive in projects with a lot of artifacts. diff --git a/app/controllers/projects/build_artifacts_controller.rb b/app/controllers/projects/build_artifacts_controller.rb index 148080a71f4..d5655d40429 100644 --- a/app/controllers/projects/build_artifacts_controller.rb +++ b/app/controllers/projects/build_artifacts_controller.rb @@ -8,7 +8,7 @@ class Projects::BuildArtifactsController < Projects::ApplicationController before_action :extract_ref_name_and_path before_action :validate_artifacts!, except: [:download] - feature_category :continuous_integration + feature_category :build_artifacts def download redirect_to download_project_job_artifacts_path(project, job, params: request.query_parameters) diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb index 7779f3c3b65..3caea14479c 100644 --- a/app/controllers/projects/pipelines_controller.rb +++ b/app/controllers/projects/pipelines_controller.rb @@ -49,7 +49,6 @@ class Projects::PipelinesController < Projects::ApplicationController respond_to do |format| format.html do - enable_pipeline_empty_state_templates_experiment enable_code_quality_walkthrough_experiment enable_ci_runner_templates_experiment end @@ -301,18 +300,6 @@ class Projects::PipelinesController < Projects::ApplicationController params.permit(:scope, :username, :ref, :status) end - def enable_pipeline_empty_state_templates_experiment - experiment(:pipeline_empty_state_templates, namespace: project.root_ancestor) do |e| - e.exclude! unless current_user - e.exclude! if @pipelines_count.to_i > 0 - e.exclude! if helpers.has_gitlab_ci?(project) - - e.control {} - e.candidate {} - e.record! - end - end - def enable_code_quality_walkthrough_experiment experiment(:code_quality_walkthrough, namespace: project.root_ancestor) do |e| e.exclude! unless current_user diff --git a/app/controllers/projects/settings/access_tokens_controller.rb b/app/controllers/projects/settings/access_tokens_controller.rb index 696c0a6dcff..1ecede4c7a2 100644 --- a/app/controllers/projects/settings/access_tokens_controller.rb +++ b/app/controllers/projects/settings/access_tokens_controller.rb @@ -50,7 +50,7 @@ module Projects end def create_params - params.require(:project_access_token).permit(:name, :expires_at, scopes: []) + params.require(:project_access_token).permit(:name, :expires_at, :access_level, scopes: []) end def set_index_vars diff --git a/app/graphql/types/issue_type.rb b/app/graphql/types/issue_type.rb index 0ccd1e2cebd..8509c7bdcc3 100644 --- a/app/graphql/types/issue_type.rb +++ b/app/graphql/types/issue_type.rb @@ -127,6 +127,9 @@ module Types field :timelogs, Types::TimelogType.connection_type, null: false, description: 'Timelogs on the issue.' + field :project_id, GraphQL::INT_TYPE, null: false, method: :project_id, + description: 'ID of the issue project.' + def author Gitlab::Graphql::Loaders::BatchModelLoader.new(User, object.author_id).find end diff --git a/app/helpers/ci/pipelines_helper.rb b/app/helpers/ci/pipelines_helper.rb index 49b7d822d0d..6be46b40023 100644 --- a/app/helpers/ci/pipelines_helper.rb +++ b/app/helpers/ci/pipelines_helper.rb @@ -30,9 +30,7 @@ module Ci project.has_ci? && project.builds_enabled? end - # This list of templates is for the pipeline_empty_state_templates experiment - # and will be cleaned up with https://gitlab.com/gitlab-org/gitlab/-/issues/326299 - def experiment_suggested_ci_templates + def suggested_ci_templates [ { name: 'Android', logo: image_path('illustrations/third-party-logos/ci_cd-template-logos/android.svg') }, { name: 'Bash', logo: image_path('illustrations/third-party-logos/ci_cd-template-logos/bash.svg') }, diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index 7690773354f..5bedfc61d46 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -181,7 +181,6 @@ module IssuesHelper def issues_list_data(project, current_user, finder) { - autocomplete_users_path: autocomplete_users_path(active: true, current_user: true, project_id: project.id, format: :json), autocomplete_award_emojis_path: autocomplete_award_emojis_path, calendar_path: url_for(safe_params.merge(calendar_url_options)), can_bulk_update: can?(current_user, :admin_issue, project).to_s, @@ -201,8 +200,6 @@ module IssuesHelper max_attachment_size: number_to_human_size(Gitlab::CurrentSettings.max_attachment_size.megabytes), new_issue_path: new_project_issue_path(project, issue: { milestone_id: finder.milestones.first.try(:id) }), project_import_jira_path: project_import_jira_path(project), - project_labels_path: project_labels_path(project, include_ancestor_groups: true, format: :json), - project_milestones_path: project_milestones_path(project, format: :json), project_path: project.full_path, quick_actions_help_path: help_page_path('user/project/quick_actions'), reset_path: new_issuable_address_project_path(project, issuable_type: 'issue'), diff --git a/app/helpers/user_callouts_helper.rb b/app/helpers/user_callouts_helper.rb index c44da915105..4e6af298fcd 100644 --- a/app/helpers/user_callouts_helper.rb +++ b/app/helpers/user_callouts_helper.rb @@ -43,7 +43,7 @@ module UserCalloutsHelper end def show_customize_homepage_banner? - !user_dismissed?(CUSTOMIZE_HOMEPAGE) + current_user.default_dashboard? && !user_dismissed?(CUSTOMIZE_HOMEPAGE) end def show_feature_flags_new_version? diff --git a/app/models/user.rb b/app/models/user.rb index 11610e4dde3..6b8df50e181 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -808,6 +808,10 @@ class User < ApplicationRecord # Instance methods # + def default_dashboard? + dashboard == self.class.column_defaults['dashboard'] + end + def full_path username end diff --git a/app/presenters/project_presenter.rb b/app/presenters/project_presenter.rb index fcd3189296a..0d038d19af3 100644 --- a/app/presenters/project_presenter.rb +++ b/app/presenters/project_presenter.rb @@ -135,10 +135,6 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated ide_edit_path(project, default_branch_or_main, 'README.md') end - def add_ci_yml_path - add_special_file_path(file_name: ci_config_path_or_default) - end - def add_code_quality_ci_yml_path add_special_file_path( file_name: ci_config_path_or_default, diff --git a/app/services/audit_event_service.rb b/app/services/audit_event_service.rb index 60421f61007..558798c830d 100644 --- a/app/services/audit_event_service.rb +++ b/app/services/audit_event_service.rb @@ -16,7 +16,7 @@ class AuditEventService @author = build_author(author) @entity = entity @details = details - @ip_address = resolve_ip_address(@details, @author) + @ip_address = resolve_ip_address(@author) end # Builds the @details attribute for authentication @@ -64,9 +64,8 @@ class AuditEventService end end - def resolve_ip_address(details, author) - details[:ip_address].presence || - Gitlab::RequestContext.instance.client_ip || + def resolve_ip_address(author) + Gitlab::RequestContext.instance.client_ip || author.current_sign_in_ip end diff --git a/app/services/resource_access_tokens/create_service.rb b/app/services/resource_access_tokens/create_service.rb index 6ff8767a525..34aa414de8f 100644 --- a/app/services/resource_access_tokens/create_service.rb +++ b/app/services/resource_access_tokens/create_service.rb @@ -16,11 +16,12 @@ module ResourceAccessTokens return error(user.errors.full_messages.to_sentence) unless user.persisted? - member = create_membership(resource, user) + access_level = params[:access_level] || Gitlab::Access::MAINTAINER + member = create_membership(resource, user, access_level) unless member.persisted? delete_failed_user(user) - return error("Could not provision maintainer access to project access token") + return error("Could not provision #{Gitlab::Access.human_access(access_level).downcase} access to project access token") end token_response = create_personal_access_token(user) @@ -102,8 +103,8 @@ module ResourceAccessTokens Gitlab::Auth.resource_bot_scopes end - def create_membership(resource, user) - resource.add_user(user, :maintainer, expires_at: params[:expires_at]) + def create_membership(resource, user, access_level) + resource.add_user(user, access_level, expires_at: params[:expires_at]) end def log_event(token) diff --git a/app/views/admin/application_settings/_usage.html.haml b/app/views/admin/application_settings/_usage.html.haml index 64e8751bf31..4bc166697d5 100644 --- a/app/views/admin/application_settings/_usage.html.haml +++ b/app/views/admin/application_settings/_usage.html.haml @@ -1,4 +1,4 @@ -- payload_class = 'js-usage-ping-payload' +- payload_class = 'js-service-ping-payload' = form_for @application_setting, url: metrics_and_profiling_admin_application_settings_path(anchor: 'js-usage-settings'), html: { class: 'fieldset-form' } do |f| = form_errors(@application_setting) @@ -17,23 +17,23 @@ .form-check = f.check_box :usage_ping_enabled, disabled: !can_be_configured, class: 'form-check-input' = f.label :usage_ping_enabled, class: 'form-check-label' do - = _('Enable usage ping') + = _('Enable service ping') .form-text.text-muted - if can_be_configured %p.mb-2= _('To help improve GitLab and its user experience, GitLab will periodically collect usage information.') - - usage_ping_path = help_page_path('user/admin_area/settings/usage_statistics', anchor: 'usage-ping') - - usage_ping_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: usage_ping_path } - %p.mb-2= s_('%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc.').html_safe % { usage_ping_link_start: usage_ping_link_start, usage_ping_link_end: '</a>'.html_safe } + - service_ping_path = help_page_path('user/admin_area/settings/usage_statistics', anchor: 'usage-ping') + - service_ping_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: service_ping_path } + %p.mb-2= s_('%{service_ping_link_start}Learn more%{service_ping_link_end} about what information is shared with GitLab Inc.').html_safe % { service_ping_link_start: service_ping_link_start, service_ping_link_end: '</a>'.html_safe } %button.gl-button.btn.btn-default.js-payload-preview-trigger{ type: 'button', data: { payload_selector: ".#{payload_class}" } } .gl-spinner.js-spinner.gl-display-none.gl-mr-2 .js-text.d-inline= _('Preview payload') - %pre.usage-data.js-syntax-highlight.code.highlight.mt-2.d-none{ class: payload_class, data: { endpoint: usage_data_admin_application_settings_path(format: :html) } } + %pre.service-data-payload-container.js-syntax-highlight.code.highlight.mt-2.d-none{ class: payload_class, data: { endpoint: usage_data_admin_application_settings_path(format: :html) } } - else - = _('The usage ping is disabled, and cannot be configured through this form.') - - deactivating_usage_ping_path = help_page_path('development/usage_ping/index.md', anchor: 'disable-usage-ping') - - deactivating_usage_ping_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: deactivating_usage_ping_path } - = s_('For more information, see the documentation on %{deactivating_usage_ping_link_start}deactivating the usage ping%{deactivating_usage_ping_link_end}.').html_safe % { deactivating_usage_ping_link_start: deactivating_usage_ping_link_start, deactivating_usage_ping_link_end: '</a>'.html_safe } + = _('Service ping is disabled, and cannot be configured through this form.') + - deactivating_service_ping_path = help_page_path('development/usage_ping/index.md', anchor: 'disable-usage-ping') + - deactivating_service_ping_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: deactivating_service_ping_path } + = s_('For more information, see the documentation on %{deactivating_service_ping_link_start}deactivating service ping%{deactivating_service_ping_link_end}.').html_safe % { deactivating_service_ping_link_start: deactivating_service_ping_link_start, deactivating_service_ping_link_end: '</a>'.html_safe } = f.submit _('Save changes'), class: "gl-button btn btn-confirm" diff --git a/app/views/admin/application_settings/metrics_and_profiling.html.haml b/app/views/admin/application_settings/metrics_and_profiling.html.haml index d08f3ea4dcc..14483e4e55e 100644 --- a/app/views/admin/application_settings/metrics_and_profiling.html.haml +++ b/app/views/admin/application_settings/metrics_and_profiling.html.haml @@ -47,7 +47,7 @@ %button.btn.gl-button.btn-default.js-settings-toggle{ type: 'button' } = expanded_by_default? ? _('Collapse') : _('Expand') %p - = _('Enable or disable version check and usage ping.') + = _('Enable or disable version check and service ping.') .settings-content = render 'usage' diff --git a/app/views/dashboard/projects/index.html.haml b/app/views/dashboard/projects/index.html.haml index c24d386c412..4252b60514a 100644 --- a/app/views/dashboard/projects/index.html.haml +++ b/app/views/dashboard/projects/index.html.haml @@ -3,15 +3,6 @@ = content_for :meta_tags do = auto_discovery_link_tag(:atom, dashboard_projects_url(rss_url_options), title: "All activity") -- if show_customize_homepage_banner? - = content_for :customize_homepage_banner do - .gl-display-none.gl-md-display-block{ class: "gl-pt-6! gl-pb-2! #{(container_class unless @no_container)} #{@content_class}" } - .js-customize-homepage-banner{ data: { svg_path: image_path('illustrations/monitoring/getting_started.svg'), - preferences_behavior_path: profile_preferences_path(anchor: 'behavior'), - callouts_path: user_callouts_path, - callouts_feature_id: UserCalloutsHelper::CUSTOMIZE_HOMEPAGE, - track_label: 'home_page' } } - = render_dashboard_ultimate_trial(current_user) - page_title _("Projects") diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml index 1b35755b276..6c959f5e60c 100644 --- a/app/views/layouts/_page.html.haml +++ b/app/views/layouts/_page.html.haml @@ -14,7 +14,7 @@ = render "layouts/header/service_templates_deprecation_callout" = render "layouts/nav/classification_level_banner" = yield :flash_message - = render "shared/ping_consent" + = render "shared/service_ping_consent" = render_account_recovery_regular_check = render_if_exists "layouts/header/ee_subscribable_banner" = render_if_exists "shared/namespace_storage_limit_alert" diff --git a/app/views/profiles/two_factor_auths/show.html.haml b/app/views/profiles/two_factor_auths/show.html.haml index 3cd571c23d3..927b6d4edef 100644 --- a/app/views/profiles/two_factor_auths/show.html.haml +++ b/app/views/profiles/two_factor_auths/show.html.haml @@ -1,5 +1,6 @@ +- breadcrumb_title _('Two-Factor Authentication') - page_title _('Two-Factor Authentication'), _('Account') -- add_to_breadcrumbs(_('Two-Factor Authentication'), profile_account_path) +- add_to_breadcrumbs _('Account'), profile_account_path - @content_class = "limit-container-width" unless fluid_layout - webauthn_enabled = Feature.enabled?(:webauthn) diff --git a/app/views/projects/pipelines/index.html.haml b/app/views/projects/pipelines/index.html.haml index 9669b2e72dc..ae76d4905e0 100644 --- a/app/views/projects/pipelines/index.html.haml +++ b/app/views/projects/pipelines/index.html.haml @@ -22,7 +22,7 @@ "ci-lint-path" => can?(current_user, :create_pipeline, @project) && project_ci_lint_path(@project), "reset-cache-path" => can?(current_user, :admin_pipeline, @project) && reset_cache_project_settings_ci_cd_path(@project), "has-gitlab-ci" => has_gitlab_ci?(@project).to_s, - "add-ci-yml-path" => can?(current_user, :create_pipeline, @project) && @project.present(current_user: current_user).add_ci_yml_path, - "suggested-ci-templates" => experiment_suggested_ci_templates.to_json, + "pipeline-editor-path" => can?(current_user, :create_pipeline, @project) && project_ci_pipeline_editor_path(@project), + "suggested-ci-templates" => suggested_ci_templates.to_json, "code-quality-page-path" => @project.present(current_user: current_user).add_code_quality_ci_yml_path, "ci-runner-settings-path" => project_settings_ci_cd_path(@project, ci_runner_templates: true, anchor: 'js-runners-settings') } } diff --git a/app/views/projects/settings/access_tokens/index.html.haml b/app/views/projects/settings/access_tokens/index.html.haml index 1f5786bafd3..52ef2e7d1ee 100644 --- a/app/views/projects/settings/access_tokens/index.html.haml +++ b/app/views/projects/settings/access_tokens/index.html.haml @@ -33,8 +33,11 @@ = render 'shared/access_tokens/form', type: type, path: project_settings_access_tokens_path(@project), + project: @project, token: @project_access_token, scopes: @scopes, + access_levels: ProjectMember.access_level_roles, + default_access_level: Gitlab::Access::MAINTAINER, prefix: :project_access_token, help_path: help_page_path('user/project/settings/project_access_tokens', anchor: 'limiting-scopes-of-a-project-access-token') diff --git a/app/views/root/index.html.haml b/app/views/root/index.html.haml new file mode 100644 index 00000000000..97dd8e133f5 --- /dev/null +++ b/app/views/root/index.html.haml @@ -0,0 +1,10 @@ +- if show_customize_homepage_banner? + = content_for :customize_homepage_banner do + .gl-display-none.gl-md-display-block{ class: "gl-pt-6! gl-pb-2! #{(container_class unless @no_container)} #{@content_class}" } + .js-customize-homepage-banner{ data: { svg_path: image_path('illustrations/monitoring/getting_started.svg'), + preferences_behavior_path: profile_preferences_path(anchor: 'behavior'), + callouts_path: user_callouts_path, + callouts_feature_id: UserCalloutsHelper::CUSTOMIZE_HOMEPAGE, + track_label: 'home_page' } } + += render template: 'dashboard/projects/index' diff --git a/app/views/shared/_ping_consent.html.haml b/app/views/shared/_service_ping_consent.html.haml index d0f1e4d7221..77597124e5c 100644 --- a/app/views/shared/_ping_consent.html.haml +++ b/app/views/shared/_service_ping_consent.html.haml @@ -1,5 +1,5 @@ - if session[:ask_for_usage_stats_consent] - .ping-consent-message.gl-alert.gl-alert-info + .service-ping-consent-message.gl-alert.gl-alert-info = sprite_icon('information-o', css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title') %button.js-close.gl-alert-dismiss{ type: 'button', 'aria-label' => _('Dismiss') } = sprite_icon('close', css_class: 'gl-icon') @@ -8,7 +8,7 @@ - settings_link = link_to _('your settings'), metrics_and_profiling_admin_application_settings_path(anchor: 'js-usage-settings'), class: 'gl-link' = s_('To help improve GitLab, we would like to periodically %{docs_link}. This can be changed at any time in %{settings_link}.').html_safe % { docs_link: docs_link, settings_link: settings_link } .gl-alert-actions.gl-mt-3 - - send_usage_data_path = admin_application_settings_path(application_setting: { version_check_enabled: 1, usage_ping_enabled: 1 }) + - send_service_data_path = admin_application_settings_path(application_setting: { version_check_enabled: 1, usage_ping_enabled: 1 }) - not_now_path = admin_application_settings_path(application_setting: { version_check_enabled: 0, usage_ping_enabled: 0 }) - = link_to _("Send usage data"), send_usage_data_path, 'data-url' => admin_application_settings_path, method: :put, 'data-check-enabled': true, 'data-ping-enabled': true, class: 'js-usage-consent-action alert-link btn gl-button btn-info' - = link_to _("Don't send usage data"), not_now_path, 'data-url' => admin_application_settings_path, method: :put, 'data-check-enabled': false, 'data-ping-enabled': false, class: 'js-usage-consent-action alert-link btn gl-button btn-default gl-ml-2' + = link_to _("Send service data"), send_service_data_path, 'data-url' => admin_application_settings_path, method: :put, 'data-check-enabled': true, 'data-service-ping-enabled': true, class: 'js-service-ping-consent-action alert-link btn gl-button btn-info' + = link_to _("Don't send service data"), not_now_path, 'data-url' => admin_application_settings_path, method: :put, 'data-check-enabled': false, 'data-service-ping-enabled': false, class: 'js-service-ping-consent-action alert-link btn gl-button btn-default gl-ml-2' diff --git a/app/views/shared/access_tokens/_form.html.haml b/app/views/shared/access_tokens/_form.html.haml index c128e2ccb03..6435475a9a3 100644 --- a/app/views/shared/access_tokens/_form.html.haml +++ b/app/views/shared/access_tokens/_form.html.haml @@ -1,6 +1,9 @@ - title = local_assigns.fetch(:title, _('Add a %{type}') % { type: type }) - prefix = local_assigns.fetch(:prefix, :personal_access_token) - help_path = local_assigns.fetch(:help_path) +- project = local_assigns.fetch(:project, false) +- access_levels = local_assigns.fetch(:access_levels, false) +- default_access_level = local_assigns.fetch(:default_access_level, false) %h5.gl-mt-0 = title @@ -29,6 +32,14 @@ .js-access-tokens-expires-at = f.text_field :expires_at, class: 'datepicker gl-datepicker-input form-control gl-form-input', placeholder: 'YYYY-MM-DD', autocomplete: 'off', data: { js_name: 'expiresAt' } + - if project + .row + .form-group.col-md-6 + = label_tag :access_level, _("Select a role"), class: "label-bold" + .select-wrapper + = select_tag :"#{prefix}[access_level]", options_for_select(access_levels, default_access_level), class: "form-control project-access-select select-control", data: { qa_selector: 'access_token_access_level' } + = sprite_icon('chevron-down', css_class: "gl-icon gl-absolute gl-top-3 gl-right-3 gl-text-gray-200") + .form-group %b{ :'aria-describedby' => 'select_scope_help_text' } = s_('Tokens|Select scopes') diff --git a/app/views/shared/empty_states/_issues.html.haml b/app/views/shared/empty_states/_issues.html.haml index 13d9d71d58e..9842457a2eb 100644 --- a/app/views/shared/empty_states/_issues.html.haml +++ b/app/views/shared/empty_states/_issues.html.haml @@ -47,7 +47,7 @@ = link_to _('New issue'), button_path, class: 'gl-button btn btn-confirm', id: 'new_issue_link' - if show_import_button - .js-csv-import-export-buttons{ data: { show_import_button: show_import_button.to_s, issuable_type: issuable_type, import_csv_issues_path: import_csv_namespace_project_issues_path, can_edit: can_edit.to_s, project_import_jira_path: project_import_jira_path(@project), max_attachment_size: number_to_human_size(Gitlab::CurrentSettings.max_attachment_size.megabytes), container_class: 'gl-display-inline-flex gl-vertical-align-middle', show_label: 'true' } } + .js-csv-import-export-buttons{ data: { show_import_button: 'true', issuable_type: issuable_type, import_csv_issues_path: import_csv_namespace_project_issues_path, can_edit: can_edit.to_s, project_import_jira_path: project_import_jira_path(@project), max_attachment_size: number_to_human_size(Gitlab::CurrentSettings.max_attachment_size.megabytes), container_class: 'gl-display-inline-flex gl-vertical-align-middle', show_label: 'true' } } %hr %p.gl-text-center.gl-mb-0 %strong |