Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
9beaa68169
commit
936139e69c
|
|
@ -43,9 +43,9 @@
|
|||
|
||||
.rules:dont-interrupt:
|
||||
rules:
|
||||
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
|
||||
- if: '$CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH && $CI_MERGE_REQUEST_IID == null'
|
||||
allow_failure: true
|
||||
- if: $CI_MERGE_REQUEST_IID
|
||||
- if: '$CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached"'
|
||||
when: manual
|
||||
allow_failure: true
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
# No specific specs in mr pipeline
|
||||
.all-specs-mr: &all-specs-mr
|
||||
if: $CI_MERGE_REQUEST_IID && $QA_TESTS == ""
|
||||
if: '($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached") && $QA_TESTS == ""'
|
||||
when: manual
|
||||
|
||||
# Triggered by change pattern
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
if: '$FORCE_GITLAB_CI'
|
||||
|
||||
.if-default-refs: &if-default-refs
|
||||
if: '$CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH || $CI_COMMIT_REF_NAME =~ /^[\d-]+-stable(-ee)?$/ || $CI_COMMIT_REF_NAME =~ /^\d+-\d+-auto-deploy-\d+$/ || $CI_COMMIT_REF_NAME =~ /^security\// || $CI_COMMIT_REF_NAME == "ruby2" || $CI_MERGE_REQUEST_IID || $CI_COMMIT_TAG || $FORCE_GITLAB_CI'
|
||||
if: '$CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH || $CI_COMMIT_REF_NAME =~ /^[\d-]+-stable(-ee)?$/ || $CI_COMMIT_REF_NAME =~ /^\d+-\d+-auto-deploy-\d+$/ || $CI_COMMIT_REF_NAME =~ /^security\// || $CI_COMMIT_REF_NAME == "ruby2" || ($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached") || $CI_COMMIT_TAG || $FORCE_GITLAB_CI'
|
||||
|
||||
.if-default-branch-refs: &if-default-branch-refs
|
||||
if: '$CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH && $CI_MERGE_REQUEST_IID == null'
|
||||
|
|
@ -30,33 +30,33 @@
|
|||
if: '$CI_COMMIT_BRANCH =~ /^\d+-\d+-auto-deploy-\d+$/'
|
||||
|
||||
.if-default-branch-or-tag: &if-default-branch-or-tag
|
||||
if: '$CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH || $CI_COMMIT_TAG'
|
||||
if: '($CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH && $CI_MERGE_REQUEST_IID == null) || $CI_COMMIT_TAG'
|
||||
|
||||
.if-tag: &if-tag
|
||||
if: '$CI_COMMIT_TAG'
|
||||
|
||||
.if-merge-request: &if-merge-request
|
||||
if: '$CI_MERGE_REQUEST_IID'
|
||||
if: '$CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached"'
|
||||
|
||||
# Once https://gitlab.com/gitlab-org/gitlab/-/issues/373904 is implemented, we should be able to change this back to
|
||||
# if: '$CI_MERGE_REQUEST_IID && $CI_MERGE_REQUEST_APPROVALS_COUNT > 0'
|
||||
# if: '($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached") && $CI_MERGE_REQUEST_APPROVALS_COUNT > 0'
|
||||
# or any similar condition to check that the MR has *any* approval (not just required approval).
|
||||
#
|
||||
# Temprorarily adding || $CI_MERGE_REQUEST_LABELS =~ /pipeline:run-full-rspec/ for backward compatibility,
|
||||
# remove once https://gitlab.com/gitlab-org/quality/quality-engineering/team-tasks/-/issues/1557 is fully rolled out
|
||||
.if-merge-request-approved: &if-merge-request-approved
|
||||
if: '$CI_MERGE_REQUEST_IID && $CI_MERGE_REQUEST_LABELS =~ /pipeline:mr-approved/ || $CI_MERGE_REQUEST_LABELS =~ /pipeline:run-full-rspec/'
|
||||
if: '($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached") && $CI_MERGE_REQUEST_LABELS =~ /pipeline:mr-approved/ || $CI_MERGE_REQUEST_LABELS =~ /pipeline:run-full-rspec/'
|
||||
|
||||
# Temprorarily adding && $CI_MERGE_REQUEST_LABELS !~ /pipeline:run-full-rspec/ for backward compatibility,
|
||||
# remove once https://gitlab.com/gitlab-org/quality/quality-engineering/team-tasks/-/issues/1557 is fully rolled out
|
||||
.if-merge-request-not-approved: &if-merge-request-not-approved
|
||||
if: '$CI_MERGE_REQUEST_IID && $CI_MERGE_REQUEST_LABELS !~ /pipeline:mr-approved/ && $CI_MERGE_REQUEST_LABELS !~ /pipeline:run-full-rspec/'
|
||||
if: '($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached") && $CI_MERGE_REQUEST_LABELS !~ /pipeline:mr-approved/ && $CI_MERGE_REQUEST_LABELS !~ /pipeline:run-full-rspec/'
|
||||
|
||||
.if-automated-merge-request: &if-automated-merge-request
|
||||
if: '$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME == "release-tools/update-gitaly" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME =~ /stable-ee$/'
|
||||
|
||||
.if-merge-request-targeting-stable-branch: &if-merge-request-targeting-stable-branch
|
||||
if: '$CI_MERGE_REQUEST_IID && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME =~ /^[\d-]+-stable(-ee)?$/'
|
||||
if: '($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached") && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME =~ /^[\d-]+-stable(-ee)?$/'
|
||||
|
||||
.if-merge-request-labels-run-in-ruby2: &if-merge-request-labels-run-in-ruby2
|
||||
if: '$CI_MERGE_REQUEST_LABELS =~ /pipeline:run-in-ruby2/'
|
||||
|
|
@ -104,10 +104,10 @@
|
|||
if: '$CI_MERGE_REQUEST_LABELS =~ /frontend/ && $CI_MERGE_REQUEST_LABELS =~ /feature flag/'
|
||||
|
||||
.if-security-merge-request: &if-security-merge-request
|
||||
if: '$CI_PROJECT_NAMESPACE == "gitlab-org/security" && $CI_MERGE_REQUEST_IID'
|
||||
if: '$CI_PROJECT_NAMESPACE == "gitlab-org/security" && ($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached")'
|
||||
|
||||
.if-fork-merge-request: &if-fork-merge-request
|
||||
if: '$CI_PROJECT_NAMESPACE !~ /^gitlab(-org)?($|\/)/ && $CI_MERGE_REQUEST_IID && $CI_MERGE_REQUEST_LABELS !~ /pipeline:run-all-rspec/'
|
||||
if: '$CI_PROJECT_NAMESPACE !~ /^gitlab(-org)?($|\/)/ && ($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached") && $CI_MERGE_REQUEST_LABELS !~ /pipeline:run-all-rspec/'
|
||||
|
||||
.if-schedule-pipeline: &if-schedule-pipeline
|
||||
if: '$CI_PIPELINE_SOURCE == "schedule"'
|
||||
|
|
@ -140,16 +140,16 @@
|
|||
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE == "gitlab-org" && $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH'
|
||||
|
||||
.if-dot-com-gitlab-org-merge-request: &if-dot-com-gitlab-org-merge-request
|
||||
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE == "gitlab-org" && $CI_MERGE_REQUEST_IID'
|
||||
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE == "gitlab-org" && ($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached")'
|
||||
|
||||
.if-dot-com-gitlab-org-and-security-merge-request: &if-dot-com-gitlab-org-and-security-merge-request
|
||||
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE =~ /^gitlab-org($|\/security$)/ && $CI_MERGE_REQUEST_IID'
|
||||
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE =~ /^gitlab-org($|\/security$)/ && ($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached")'
|
||||
|
||||
.if-dot-com-gitlab-org-and-security-merge-request-and-qa-tests-specified: &if-dot-com-gitlab-org-and-security-merge-request-and-qa-tests-specified
|
||||
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE =~ /^gitlab-org($|\/security$)/ && $CI_MERGE_REQUEST_IID && $QA_TESTS'
|
||||
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE =~ /^gitlab-org($|\/security$)/ && ($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached") && $QA_TESTS'
|
||||
|
||||
.if-dot-com-gitlab-org-and-security-merge-request-manual-ff-package-and-e2e: &if-dot-com-gitlab-org-and-security-merge-request-manual-ff-package-and-e2e
|
||||
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE =~ /^gitlab-org($|\/security$)/ && $CI_MERGE_REQUEST_IID && $QA_MANUAL_FF_PACKAGE_AND_QA'
|
||||
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE =~ /^gitlab-org($|\/security$)/ && ($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached") && $QA_MANUAL_FF_PACKAGE_AND_QA'
|
||||
|
||||
.if-dot-com-gitlab-org-and-security-tag: &if-dot-com-gitlab-org-and-security-tag
|
||||
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE =~ /^gitlab-org($|\/security$)/ && $CI_COMMIT_TAG'
|
||||
|
|
@ -1062,7 +1062,7 @@
|
|||
- <<: *if-default-branch-refs
|
||||
changes: *frontend-build-patterns
|
||||
allow_failure: true
|
||||
- if: '$DANGER_GITLAB_API_TOKEN && $CI_MERGE_REQUEST_IID && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH'
|
||||
- if: '$DANGER_GITLAB_API_TOKEN && ($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached") && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH'
|
||||
changes: *frontend-build-patterns
|
||||
allow_failure: true
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import {
|
|||
GlModal,
|
||||
GlSprintf,
|
||||
} from '@gitlab/ui';
|
||||
import { helpPagePath } from '~/helpers/help_page_helper';
|
||||
import { getCookie, setCookie } from '~/lib/utils/common_utils';
|
||||
import { __ } from '~/locale';
|
||||
import Tracking from '~/tracking';
|
||||
|
|
@ -31,6 +32,7 @@ import {
|
|||
EVENT_ACTION,
|
||||
EXPANDED_VARIABLES_NOTE,
|
||||
EDIT_VARIABLE_ACTION,
|
||||
FLAG_LINK_TITLE,
|
||||
VARIABLE_ACTIONS,
|
||||
variableOptions,
|
||||
} from '../constants';
|
||||
|
|
@ -41,13 +43,6 @@ import { awsTokens, awsTokenList } from './ci_variable_autocomplete_tokens';
|
|||
const trackingMixin = Tracking.mixin({ label: EVENT_LABEL });
|
||||
|
||||
export default {
|
||||
modalId: ADD_CI_VARIABLE_MODAL_ID,
|
||||
tokens: awsTokens,
|
||||
tokenList: awsTokenList,
|
||||
awsTipMessage: AWS_TIP_MESSAGE,
|
||||
containsVariableReferenceMessage: CONTAINS_VARIABLE_REFERENCE_MESSAGE,
|
||||
environmentScopeLinkTitle: ENVIRONMENT_SCOPE_LINK_TITLE,
|
||||
expandedVariablesNote: EXPANDED_VARIABLES_NOTE,
|
||||
components: {
|
||||
CiEnvironmentsDropdown,
|
||||
GlAlert,
|
||||
|
|
@ -75,7 +70,6 @@ export default {
|
|||
'isProtectedByDefault',
|
||||
'maskedEnvironmentVariablesLink',
|
||||
'maskableRegex',
|
||||
'protectedEnvironmentVariablesLink',
|
||||
],
|
||||
props: {
|
||||
areScopedVariablesAvailable: {
|
||||
|
|
@ -273,7 +267,20 @@ export default {
|
|||
this.validationErrorEventProperty = '';
|
||||
},
|
||||
},
|
||||
defaultScope: allEnvironments.text,
|
||||
i18n: {
|
||||
awsTipMessage: AWS_TIP_MESSAGE,
|
||||
containsVariableReferenceMessage: CONTAINS_VARIABLE_REFERENCE_MESSAGE,
|
||||
defaultScope: allEnvironments.text,
|
||||
environmentScopeLinkTitle: ENVIRONMENT_SCOPE_LINK_TITLE,
|
||||
expandedVariablesNote: EXPANDED_VARIABLES_NOTE,
|
||||
flagsLinkTitle: FLAG_LINK_TITLE,
|
||||
},
|
||||
flagLink: helpPagePath('ci/variables/index', {
|
||||
anchor: 'define-a-cicd-variable-in-the-ui',
|
||||
}),
|
||||
modalId: ADD_CI_VARIABLE_MODAL_ID,
|
||||
tokens: awsTokens,
|
||||
tokenList: awsTokenList,
|
||||
variableOptions,
|
||||
};
|
||||
</script>
|
||||
|
|
@ -340,15 +347,20 @@ export default {
|
|||
data-testid="environment-scope"
|
||||
>
|
||||
<template #label>
|
||||
{{ __('Environment scope') }}
|
||||
<gl-link
|
||||
:title="$options.environmentScopeLinkTitle"
|
||||
:href="environmentScopeLink"
|
||||
target="_blank"
|
||||
data-testid="environment-scope-link"
|
||||
>
|
||||
<gl-icon name="question" :size="12" />
|
||||
</gl-link>
|
||||
<div class="gl-display-flex gl-align-items-center">
|
||||
<span class="gl-mr-2">
|
||||
{{ __('Environment scope') }}
|
||||
</span>
|
||||
<gl-link
|
||||
class="gl-display-flex"
|
||||
:title="$options.i18n.environmentScopeLinkTitle"
|
||||
:href="environmentScopeLink"
|
||||
target="_blank"
|
||||
data-testid="environment-scope-link"
|
||||
>
|
||||
<gl-icon name="question-o" :size="14" />
|
||||
</gl-link>
|
||||
</div>
|
||||
</template>
|
||||
<ci-environments-dropdown
|
||||
v-if="areScopedVariablesAvailable"
|
||||
|
|
@ -358,12 +370,27 @@ export default {
|
|||
@create-environment-scope="createEnvironmentScope"
|
||||
/>
|
||||
|
||||
<gl-form-input v-else :value="$options.defaultScope" class="gl-w-full" readonly />
|
||||
<gl-form-input v-else :value="$options.i18n.defaultScope" class="gl-w-full" readonly />
|
||||
</gl-form-group>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<gl-form-group :label="__('Flags')" label-for="ci-variable-flags">
|
||||
<gl-form-group>
|
||||
<template #label>
|
||||
<div class="gl-display-flex gl-align-items-center">
|
||||
<span class="gl-mr-2">
|
||||
{{ __('Flags') }}
|
||||
</span>
|
||||
<gl-link
|
||||
class="gl-display-flex"
|
||||
:title="$options.i18n.flagsLinkTitle"
|
||||
:href="$options.flagLink"
|
||||
target="_blank"
|
||||
>
|
||||
<gl-icon name="question-o" :size="14" />
|
||||
</gl-link>
|
||||
</div>
|
||||
</template>
|
||||
<gl-form-checkbox
|
||||
v-model="variable.protected"
|
||||
class="gl-mb-0"
|
||||
|
|
@ -371,9 +398,6 @@ export default {
|
|||
:data-is-protected-checked="variable.protected"
|
||||
>
|
||||
{{ __('Protect variable') }}
|
||||
<gl-link target="_blank" :href="protectedEnvironmentVariablesLink">
|
||||
<gl-icon name="question" :size="12" />
|
||||
</gl-link>
|
||||
<p class="gl-mt-2 text-secondary">
|
||||
{{ __('Export variable to pipelines running on protected branches and tags only.') }}
|
||||
</p>
|
||||
|
|
@ -384,9 +408,6 @@ export default {
|
|||
data-testid="ci-variable-masked-checkbox"
|
||||
>
|
||||
{{ __('Mask variable') }}
|
||||
<gl-link target="_blank" :href="maskedEnvironmentVariablesLink">
|
||||
<gl-icon name="question" :size="12" />
|
||||
</gl-link>
|
||||
<p class="gl-mt-2 text-secondary">
|
||||
{{ __('Variable will be masked in job logs.') }}
|
||||
<span
|
||||
|
|
@ -397,7 +418,7 @@ export default {
|
|||
{{ __('Requires values to meet regular expression requirements.') }}</span
|
||||
>
|
||||
<gl-link target="_blank" :href="maskedEnvironmentVariablesLink">{{
|
||||
__('More information')
|
||||
__('Learn more.')
|
||||
}}</gl-link>
|
||||
</p>
|
||||
</gl-form-checkbox>
|
||||
|
|
@ -408,11 +429,8 @@ export default {
|
|||
@change="setVariableRaw"
|
||||
>
|
||||
{{ __('Expand variable reference') }}
|
||||
<gl-link target="_blank" :href="containsVariableReferenceLink">
|
||||
<gl-icon name="question" :size="12" />
|
||||
</gl-link>
|
||||
<p class="gl-mt-2 gl-mb-0 gl-text-secondary">
|
||||
<gl-sprintf :message="$options.expandedVariablesNote">
|
||||
<gl-sprintf :message="$options.i18n.expandedVariablesNote">
|
||||
<template #code="{ content }">
|
||||
<code>{{ content }}</code>
|
||||
</template>
|
||||
|
|
@ -431,7 +449,7 @@ export default {
|
|||
<div class="gl-display-flex gl-flex-direction-row gl-flex-wrap-wrap gl-md-flex-wrap-nowrap">
|
||||
<div>
|
||||
<p>
|
||||
<gl-sprintf :message="$options.awsTipMessage">
|
||||
<gl-sprintf :message="$options.i18n.awsTipMessage">
|
||||
<template #deployLink="{ content }">
|
||||
<gl-link :href="awsTipDeployLink" target="_blank">{{ content }}</gl-link>
|
||||
</template>
|
||||
|
|
@ -467,7 +485,7 @@ export default {
|
|||
variant="warning"
|
||||
data-testid="contains-variable-reference"
|
||||
>
|
||||
<gl-sprintf :message="$options.containsVariableReferenceMessage">
|
||||
<gl-sprintf :message="$options.i18n.containsVariableReferenceMessage">
|
||||
<template #code="{ content }">
|
||||
<code>{{ content }}</code>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -72,14 +72,14 @@ export const AWS_TOKEN_CONSTANTS = [AWS_ACCESS_KEY_ID, AWS_DEFAULT_REGION, AWS_S
|
|||
export const CONTAINS_VARIABLE_REFERENCE_MESSAGE = __(
|
||||
'Unselect "Expand variable reference" if you want to use the variable value as a raw string.',
|
||||
);
|
||||
|
||||
export const DEFAULT_EXCEEDS_VARIABLE_LIMIT_TEXT = s__(
|
||||
'CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables.',
|
||||
);
|
||||
export const ENVIRONMENT_SCOPE_LINK_TITLE = __('Learn more');
|
||||
export const EXCEEDS_VARIABLE_LIMIT_TEXT = s__(
|
||||
'CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables.',
|
||||
);
|
||||
export const DEFAULT_EXCEEDS_VARIABLE_LIMIT_TEXT = s__(
|
||||
'CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables.',
|
||||
);
|
||||
export const FLAG_LINK_TITLE = s__('CiVariable|Define a CI/CD variable in the UI');
|
||||
export const MAXIMUM_VARIABLE_LIMIT_REACHED = s__(
|
||||
'CiVariables|Maximum number of variables reached.',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ const mountCiVariableListApp = (containerEl) => {
|
|||
projectFullPath,
|
||||
projectId,
|
||||
protectedByDefault,
|
||||
protectedEnvironmentVariablesLink,
|
||||
} = containerEl.dataset;
|
||||
|
||||
const parsedIsProject = parseBoolean(isProject);
|
||||
|
|
@ -66,7 +65,6 @@ const mountCiVariableListApp = (containerEl) => {
|
|||
maskableRegex,
|
||||
projectFullPath,
|
||||
projectId,
|
||||
protectedEnvironmentVariablesLink,
|
||||
},
|
||||
render(createElement) {
|
||||
return createElement(component);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
<script>
|
||||
import { mapGetters, mapState } from 'vuex';
|
||||
import { mapState } from 'vuex';
|
||||
import { __ } from '~/locale';
|
||||
import { rightSidebarViews, SIDEBAR_INIT_WIDTH, SIDEBAR_NAV_WIDTH } from '../../constants';
|
||||
import JobsDetail from '../jobs/detail.vue';
|
||||
import PipelinesList from '../pipelines/list.vue';
|
||||
import Clientside from '../preview/clientside.vue';
|
||||
import ResizablePanel from '../resizable_panel.vue';
|
||||
import TerminalView from '../terminal/view.vue';
|
||||
import CollapsibleSidebar from './collapsible_sidebar.vue';
|
||||
|
|
@ -20,12 +19,8 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
...mapState('terminal', { isTerminalVisible: 'isVisible' }),
|
||||
...mapState(['currentMergeRequestId', 'clientsidePreviewEnabled']),
|
||||
...mapGetters(['packageJson']),
|
||||
...mapState(['currentMergeRequestId']),
|
||||
...mapState('rightPane', ['isOpen']),
|
||||
showLivePreview() {
|
||||
return this.packageJson && this.clientsidePreviewEnabled;
|
||||
},
|
||||
rightExtensionTabs() {
|
||||
return [
|
||||
{
|
||||
|
|
@ -37,12 +32,6 @@ export default {
|
|||
],
|
||||
icon: 'rocket',
|
||||
},
|
||||
{
|
||||
show: this.showLivePreview,
|
||||
title: __('Live preview'),
|
||||
views: [{ component: Clientside, ...rightSidebarViews.clientSidePreview }],
|
||||
icon: 'live-preview',
|
||||
},
|
||||
{
|
||||
show: this.isTerminalVisible,
|
||||
title: __('Terminal'),
|
||||
|
|
|
|||
|
|
@ -1,191 +0,0 @@
|
|||
<script>
|
||||
import { GlLoadingIcon } from '@gitlab/ui';
|
||||
import { listen } from 'codesandbox-api';
|
||||
import { isEmpty, debounce } from 'lodash';
|
||||
import { SandpackClient } from '@codesandbox/sandpack-client';
|
||||
import { mapActions, mapGetters, mapState } from 'vuex';
|
||||
import {
|
||||
packageJsonPath,
|
||||
LIVE_PREVIEW_DEBOUNCE,
|
||||
PING_USAGE_PREVIEW_KEY,
|
||||
PING_USAGE_PREVIEW_SUCCESS_KEY,
|
||||
} from '../../constants';
|
||||
import eventHub from '../../eventhub';
|
||||
import { createPathWithExt } from '../../utils';
|
||||
import Navigator from './navigator.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Navigator,
|
||||
GlLoadingIcon,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
client: {},
|
||||
loading: false,
|
||||
sandpackReady: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(['entries', 'promotionSvgPath', 'links', 'codesandboxBundlerUrl']),
|
||||
...mapGetters(['packageJson', 'currentProject']),
|
||||
normalizedEntries() {
|
||||
return Object.keys(this.entries).reduce((acc, path) => {
|
||||
const file = this.entries[path];
|
||||
|
||||
if (file.type === 'tree' || !(file.raw || file.content)) return acc;
|
||||
|
||||
return {
|
||||
...acc,
|
||||
[`/${path}`]: {
|
||||
code: file.content || file.raw,
|
||||
},
|
||||
};
|
||||
}, {});
|
||||
},
|
||||
mainEntry() {
|
||||
if (!this.packageJson.raw) return false;
|
||||
|
||||
const parsedPackage = JSON.parse(this.packageJson.raw);
|
||||
|
||||
return parsedPackage.main;
|
||||
},
|
||||
showPreview() {
|
||||
return this.mainEntry && !this.loading;
|
||||
},
|
||||
showEmptyState() {
|
||||
return !this.mainEntry && !this.loading;
|
||||
},
|
||||
showOpenInCodeSandbox() {
|
||||
return this.currentProject && this.currentProject.visibility === 'public';
|
||||
},
|
||||
sandboxOpts() {
|
||||
return {
|
||||
files: { ...this.normalizedEntries },
|
||||
entry: `/${this.mainEntry}`,
|
||||
showOpenInCodeSandbox: this.showOpenInCodeSandbox,
|
||||
};
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
sandpackReady: {
|
||||
handler(val) {
|
||||
if (val) {
|
||||
this.pingUsage(PING_USAGE_PREVIEW_SUCCESS_KEY);
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.onFilesChangeCallback = debounce(() => this.update(), LIVE_PREVIEW_DEBOUNCE);
|
||||
eventHub.$on('ide.files.change', this.onFilesChangeCallback);
|
||||
|
||||
this.loading = true;
|
||||
|
||||
return this.loadFileContent(packageJsonPath)
|
||||
.then(() => {
|
||||
this.loading = false;
|
||||
})
|
||||
.then(() => this.$nextTick())
|
||||
.then(() => this.initPreview());
|
||||
},
|
||||
beforeDestroy() {
|
||||
// Setting sandpackReady = false protects us form a phantom `update()` being called when `debounce` finishes.
|
||||
this.sandpackReady = false;
|
||||
eventHub.$off('ide.files.change', this.onFilesChangeCallback);
|
||||
|
||||
if (!isEmpty(this.client)) {
|
||||
this.client.cleanup();
|
||||
}
|
||||
|
||||
this.client = {};
|
||||
|
||||
if (this.listener) {
|
||||
this.listener();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['getFileData', 'getRawFileData']),
|
||||
...mapActions('clientside', ['pingUsage']),
|
||||
loadFileContent(path) {
|
||||
return this.getFileData({ path, makeFileActive: false }).then(() =>
|
||||
this.getRawFileData({ path }),
|
||||
);
|
||||
},
|
||||
initPreview() {
|
||||
if (!this.mainEntry) return null;
|
||||
|
||||
this.pingUsage(PING_USAGE_PREVIEW_KEY);
|
||||
|
||||
return this.loadFileContent(this.mainEntry)
|
||||
.then(() => this.$nextTick())
|
||||
.then(() => {
|
||||
this.initClient();
|
||||
|
||||
this.listener = listen((e) => {
|
||||
switch (e.type) {
|
||||
case 'done':
|
||||
this.sandpackReady = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
update() {
|
||||
if (!this.sandpackReady) return;
|
||||
|
||||
if (isEmpty(this.client)) {
|
||||
this.initPreview();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.client.updatePreview(this.sandboxOpts);
|
||||
},
|
||||
initClient() {
|
||||
const { codesandboxBundlerUrl: bundlerURL } = this;
|
||||
|
||||
const settings = {
|
||||
fileResolver: {
|
||||
isFile: (p) => Promise.resolve(Boolean(this.entries[createPathWithExt(p)])),
|
||||
readFile: (p) => this.loadFileContent(createPathWithExt(p)).then((content) => content),
|
||||
},
|
||||
...(bundlerURL ? { bundlerURL } : {}),
|
||||
};
|
||||
|
||||
this.client = new SandpackClient('#ide-preview', this.sandboxOpts, settings);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="preview h-100 w-100 d-flex flex-column gl-bg-white">
|
||||
<template v-if="showPreview">
|
||||
<navigator :client="client" />
|
||||
<div id="ide-preview"></div>
|
||||
</template>
|
||||
<div
|
||||
v-else-if="showEmptyState"
|
||||
v-once
|
||||
class="d-flex h-100 flex-column align-items-center justify-content-center svg-content"
|
||||
>
|
||||
<img :src="promotionSvgPath" :alt="s__('IDE|Live Preview')" width="130" height="100" />
|
||||
<h3>{{ s__('IDE|Live Preview') }}</h3>
|
||||
<p class="text-center">
|
||||
{{ s__('IDE|Preview your web application using Web IDE client-side evaluation.') }}
|
||||
</p>
|
||||
<a
|
||||
:href="links.webIDEHelpPagePath"
|
||||
class="btn gl-button btn-confirm"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{{ s__('IDE|Get started with Live Preview') }}
|
||||
</a>
|
||||
</div>
|
||||
<gl-loading-icon v-else size="lg" class="align-self-center mt-auto mb-auto" />
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,136 +0,0 @@
|
|||
<script>
|
||||
import { GlLoadingIcon, GlIcon } from '@gitlab/ui';
|
||||
import { listen } from 'codesandbox-api';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlIcon,
|
||||
GlLoadingIcon,
|
||||
},
|
||||
props: {
|
||||
client: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentBrowsingIndex: null,
|
||||
navigationStack: [],
|
||||
forwardNavigationStack: [],
|
||||
path: '',
|
||||
loading: true,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
backButtonDisabled() {
|
||||
return this.navigationStack.length <= 1;
|
||||
},
|
||||
forwardButtonDisabled() {
|
||||
return !this.forwardNavigationStack.length;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.listener = listen((e) => {
|
||||
switch (e.type) {
|
||||
case 'urlchange':
|
||||
this.onUrlChange(e);
|
||||
break;
|
||||
case 'done':
|
||||
this.loading = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.listener();
|
||||
},
|
||||
methods: {
|
||||
onUrlChange(e) {
|
||||
const lastPath = this.path;
|
||||
|
||||
this.path = e.url.replace(this.client.bundlerURL, '') || '/';
|
||||
|
||||
if (lastPath !== this.path) {
|
||||
this.currentBrowsingIndex =
|
||||
this.currentBrowsingIndex === null ? 0 : this.currentBrowsingIndex + 1;
|
||||
this.navigationStack.push(this.path);
|
||||
}
|
||||
},
|
||||
back() {
|
||||
const lastPath = this.path;
|
||||
|
||||
this.visitPath(this.navigationStack[this.currentBrowsingIndex - 1]);
|
||||
|
||||
this.forwardNavigationStack.push(lastPath);
|
||||
|
||||
if (this.currentBrowsingIndex === 1) {
|
||||
this.currentBrowsingIndex = null;
|
||||
this.navigationStack = [];
|
||||
}
|
||||
},
|
||||
forward() {
|
||||
this.visitPath(this.forwardNavigationStack.splice(0, 1)[0]);
|
||||
},
|
||||
refresh() {
|
||||
this.visitPath(this.path);
|
||||
},
|
||||
visitPath(path) {
|
||||
// eslint-disable-next-line vue/no-mutating-props
|
||||
this.client.iframe.src = `${this.client.bundlerURL}${path}`;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<header class="ide-preview-header d-flex align-items-center">
|
||||
<button
|
||||
:aria-label="s__('IDE|Back')"
|
||||
:disabled="backButtonDisabled"
|
||||
:class="{
|
||||
'disabled-content': backButtonDisabled,
|
||||
}"
|
||||
type="button"
|
||||
class="ide-navigator-btn d-flex align-items-center d-transparent border-0 bg-transparent"
|
||||
@click="back"
|
||||
>
|
||||
<gl-icon :size="24" name="chevron-left" class="m-auto" />
|
||||
</button>
|
||||
<button
|
||||
:aria-label="s__('IDE|Back')"
|
||||
:disabled="forwardButtonDisabled"
|
||||
:class="{
|
||||
'disabled-content': forwardButtonDisabled,
|
||||
}"
|
||||
type="button"
|
||||
class="ide-navigator-btn d-flex align-items-center d-transparent border-0 bg-transparent"
|
||||
@click="forward"
|
||||
>
|
||||
<gl-icon :size="24" name="chevron-right" class="m-auto" />
|
||||
</button>
|
||||
<button
|
||||
:aria-label="s__('IDE|Refresh preview')"
|
||||
type="button"
|
||||
class="ide-navigator-btn d-flex align-items-center d-transparent border-0 bg-transparent"
|
||||
@click="refresh"
|
||||
>
|
||||
<gl-icon :size="16" name="retry" class="m-auto" />
|
||||
</button>
|
||||
<div class="position-relative w-100 gl-ml-2">
|
||||
<input
|
||||
:value="path || '/'"
|
||||
type="text"
|
||||
class="ide-navigator-location form-control bg-white"
|
||||
readonly
|
||||
/>
|
||||
<gl-loading-icon
|
||||
v-if="loading"
|
||||
size="sm"
|
||||
class="position-absolute ide-preview-loading-icon"
|
||||
/>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
|
@ -64,7 +64,6 @@ export const rightSidebarViews = {
|
|||
pipelines: { name: 'pipelines-list', keepAlive: true },
|
||||
jobsDetail: { name: 'jobs-detail', keepAlive: false },
|
||||
mergeRequestInfo: { name: 'merge-request-info', keepAlive: true },
|
||||
clientSidePreview: { name: 'clientside', keepAlive: false },
|
||||
terminal: { name: 'terminal', keepAlive: true },
|
||||
};
|
||||
|
||||
|
|
@ -101,22 +100,13 @@ export const commitActionTypes = {
|
|||
update: 'update',
|
||||
};
|
||||
|
||||
export const packageJsonPath = 'package.json';
|
||||
|
||||
export const SIDE_LEFT = 'left';
|
||||
export const SIDE_RIGHT = 'right';
|
||||
|
||||
// Live Preview feature
|
||||
export const LIVE_PREVIEW_DEBOUNCE = 2000;
|
||||
|
||||
// This is the maximum number of files to auto open when opening the Web IDE
|
||||
// from a merge request
|
||||
export const MAX_MR_FILES_AUTO_OPEN = 10;
|
||||
|
||||
export const DEFAULT_BRANCH = 'main';
|
||||
|
||||
// Ping Usage Metrics Keys
|
||||
export const PING_USAGE_PREVIEW_KEY = 'web_ide_clientside_preview';
|
||||
export const PING_USAGE_PREVIEW_SUCCESS_KEY = 'web_ide_clientside_preview_success';
|
||||
|
||||
export const GITLAB_WEB_IDE_FEEDBACK_ISSUE = 'https://gitlab.com/gitlab-org/gitlab/-/issues/377367';
|
||||
|
|
|
|||
|
|
@ -67,10 +67,8 @@ export const initLegacyWebIDE = (el, options = {}) => {
|
|||
forkInfo: el.dataset.forkInfo ? JSON.parse(el.dataset.forkInfo) : null,
|
||||
});
|
||||
this.init({
|
||||
clientsidePreviewEnabled: parseBoolean(el.dataset.clientsidePreviewEnabled),
|
||||
renderWhitespaceInCode: parseBoolean(el.dataset.renderWhitespaceInCode),
|
||||
editorTheme: window.gon?.user_color_scheme || DEFAULT_THEME,
|
||||
codesandboxBundlerUrl: el.dataset.codesandboxBundlerUrl,
|
||||
environmentsGuidanceAlertDismissed: !parseBoolean(el.dataset.enableEnvironmentsGuidance),
|
||||
previewMarkdownPath: el.dataset.previewMarkdownPath,
|
||||
userPreferencesPath: el.dataset.userPreferencesPath,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import Api from '~/api';
|
|||
import { addNumericSuffix } from '~/ide/utils';
|
||||
import {
|
||||
leftSidebarViews,
|
||||
packageJsonPath,
|
||||
DEFAULT_PERMISSIONS,
|
||||
PERMISSION_READ_MR,
|
||||
PERMISSION_CREATE_MR,
|
||||
|
|
@ -153,8 +152,6 @@ export const currentBranch = (state, getters) =>
|
|||
|
||||
export const branchName = (_state, getters) => getters.currentBranch && getters.currentBranch.name;
|
||||
|
||||
export const packageJson = (state) => state.entries[packageJsonPath];
|
||||
|
||||
export const isOnDefaultBranch = (_state, getters) =>
|
||||
getters.currentProject && getters.currentProject.default_branch === getters.branchName;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import Vuex from 'vuex';
|
|||
import * as actions from './actions';
|
||||
import * as getters from './getters';
|
||||
import branches from './modules/branches';
|
||||
import clientsideModule from './modules/clientside';
|
||||
import commitModule from './modules/commit';
|
||||
import editorModule from './modules/editor';
|
||||
import { setupFileEditorsSync } from './modules/editor/setup';
|
||||
|
|
@ -29,7 +28,6 @@ export const createStoreOptions = () => ({
|
|||
branches,
|
||||
fileTemplates: fileTemplates(),
|
||||
rightPane: paneModule(),
|
||||
clientside: clientsideModule(),
|
||||
router: routerModule,
|
||||
editor: editorModule,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
import axios from '~/lib/utils/axios_utils';
|
||||
|
||||
export const pingUsage = ({ rootGetters }, metricName) => {
|
||||
const { web_url: projectUrl } = rootGetters.currentProject;
|
||||
|
||||
const url = `${projectUrl}/service_ping/${metricName}`;
|
||||
|
||||
return axios.post(url);
|
||||
};
|
||||
|
||||
export default pingUsage;
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
import * as actions from './actions';
|
||||
|
||||
export default () => ({
|
||||
namespaced: true,
|
||||
actions,
|
||||
});
|
||||
|
|
@ -26,10 +26,8 @@ export default () => ({
|
|||
path: '',
|
||||
entry: {},
|
||||
},
|
||||
clientsidePreviewEnabled: false,
|
||||
renderWhitespaceInCode: false,
|
||||
editorTheme: DEFAULT_THEME,
|
||||
codesandboxBundlerUrl: null,
|
||||
environmentsGuidanceAlertDismissed: false,
|
||||
environmentsGuidanceAlertDetected: false,
|
||||
previewMarkdownPath: '',
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ export default {
|
|||
},
|
||||
i18n: {
|
||||
signInButtonTextWithSubscriptions: s__('Integrations|Sign in to add namespaces'),
|
||||
signInText: s__('JiraService|Sign in to GitLab.com to get started.'),
|
||||
signInText: s__('JiraService|Sign in to GitLab to get started.'),
|
||||
},
|
||||
GITLAB_COM_BASE_PATH,
|
||||
methods: {
|
||||
|
|
|
|||
|
|
@ -334,7 +334,7 @@ export const timeToHoursMinutes = (time = '') => {
|
|||
* @param {String} offset An optional Date-compatible offset.
|
||||
* @returns {String} The combined Date's ISO string representation.
|
||||
*/
|
||||
export const dateAndTimeToISOString = (date, time = '00:00', offset = '') => {
|
||||
export const dateAndTimeToISOString = (date, time, offset = '') => {
|
||||
const { year, month, day } = dateToYearMonthDate(date);
|
||||
const { hours, minutes } = timeToHoursMinutes(time);
|
||||
const dateString = `${year}-${month}-${day}T${hours}:${minutes}:00.000${offset || 'Z'}`;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
<script>
|
||||
import { GlDisclosureDropdown, GlTooltipDirective } from '@gitlab/ui';
|
||||
import { GlDisclosureDropdown, GlTooltip } from '@gitlab/ui';
|
||||
import { __ } from '~/locale';
|
||||
|
||||
export default {
|
||||
directives: {
|
||||
GlTooltip: GlTooltipDirective,
|
||||
},
|
||||
components: {
|
||||
GlDisclosureDropdown,
|
||||
GlTooltip,
|
||||
},
|
||||
i18n: {
|
||||
createNew: __('Create new...'),
|
||||
|
|
@ -18,17 +16,23 @@ export default {
|
|||
required: true,
|
||||
},
|
||||
},
|
||||
toggleId: 'create-menu-toggle',
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<gl-disclosure-dropdown
|
||||
v-gl-tooltip:super-sidebar.bottom="$options.i18n.createNew"
|
||||
category="tertiary"
|
||||
icon="plus"
|
||||
:items="groups"
|
||||
no-caret
|
||||
text-sr-only
|
||||
:toggle-text="$options.i18n.createNew"
|
||||
/>
|
||||
<div>
|
||||
<gl-disclosure-dropdown
|
||||
category="tertiary"
|
||||
icon="plus"
|
||||
:items="groups"
|
||||
no-caret
|
||||
text-sr-only
|
||||
:toggle-text="$options.i18n.createNew"
|
||||
:toggle-id="$options.toggleId"
|
||||
/>
|
||||
<gl-tooltip :target="`#${$options.toggleId}`" placement="bottom" container="#super-sidebar">
|
||||
{{ $options.i18n.createNew }}
|
||||
</gl-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -906,8 +906,7 @@ $ide-commit-header-height: 48px;
|
|||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.ide-right-sidebar-terminal,
|
||||
.ide-right-sidebar-clientside {
|
||||
.ide-right-sidebar-terminal {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1083,43 +1082,6 @@ $ide-commit-header-height: 48px;
|
|||
}
|
||||
}
|
||||
|
||||
.ide-preview-header {
|
||||
padding: 0 $grid-size;
|
||||
border-bottom: 1px solid var(--ide-border-color-alt, $white-dark);
|
||||
background-color: var(--ide-highlight-background, $gray-light);
|
||||
min-height: 44px;
|
||||
}
|
||||
|
||||
.ide-navigator-btn {
|
||||
height: 24px;
|
||||
min-width: 24px;
|
||||
max-width: 24px;
|
||||
padding: 0;
|
||||
margin: 0 ($grid-size / 2);
|
||||
color: var(--ide-text-color-secondary, $gray-600);
|
||||
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ide-navigator-location {
|
||||
padding-top: ($grid-size / 2);
|
||||
padding-bottom: ($grid-size / 2);
|
||||
|
||||
&:focus {
|
||||
outline: 0;
|
||||
box-shadow: none;
|
||||
border-color: var(--ide-border-color, $gray-100);
|
||||
}
|
||||
}
|
||||
|
||||
.ide-preview-loading-icon {
|
||||
right: $grid-size;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.ide-file-templates {
|
||||
padding: $grid-size $gl-padding;
|
||||
background-color: var(--ide-background, $gray-light);
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ClientsidePreviewCSP
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
content_security_policy do |p|
|
||||
next if p.directives.blank?
|
||||
next unless Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?
|
||||
|
||||
default_frame_src = p.directives['frame-src'] || p.directives['default-src']
|
||||
frame_src_values = Array.wrap(default_frame_src) | [Gitlab::CurrentSettings.web_ide_clientside_preview_bundler_url].compact
|
||||
|
||||
p.frame_src(*frame_src_values)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -20,6 +20,7 @@ module RecordUserLastActivity
|
|||
return if Gitlab::Database.read_only?
|
||||
return unless current_user && current_user.last_activity_on != Date.today
|
||||
|
||||
Users::ActivityService.new(current_user).execute
|
||||
# TODO: add namespace & project - https://gitlab.com/gitlab-org/gitlab/-/issues/387952
|
||||
Users::ActivityService.new(author: current_user).execute
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -144,7 +144,8 @@ class GraphqlController < ApplicationController
|
|||
def set_user_last_activity
|
||||
return unless current_user
|
||||
|
||||
Users::ActivityService.new(current_user).execute
|
||||
# TODO: add namespace & project - https://gitlab.com/gitlab-org/gitlab/-/issues/387951
|
||||
Users::ActivityService.new(author: current_user).execute
|
||||
end
|
||||
|
||||
def track_vs_code_usage
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
class IdeController < ApplicationController
|
||||
include VSCodeCDNCSP
|
||||
include ClientsidePreviewCSP
|
||||
include StaticObjectExternalStorageCSP
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
|
||||
|
|
|
|||
|
|
@ -5,24 +5,6 @@ class Projects::ServicePingController < Projects::ApplicationController
|
|||
|
||||
feature_category :web_ide
|
||||
|
||||
def web_ide_clientside_preview
|
||||
return render_404 unless Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?
|
||||
|
||||
Gitlab::UsageDataCounters::WebIdeCounter.increment_previews_count
|
||||
|
||||
head(:ok)
|
||||
end
|
||||
|
||||
def web_ide_clientside_preview_success
|
||||
return render_404 unless Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?
|
||||
|
||||
Gitlab::UsageDataCounters::WebIdeCounter.increment_previews_success_count
|
||||
Gitlab::UsageDataCounters::EditorUniqueCounter.track_live_preview_edit_action(author: current_user,
|
||||
project: project)
|
||||
|
||||
head(:ok)
|
||||
end
|
||||
|
||||
def web_ide_pipelines_count
|
||||
Gitlab::UsageDataCounters::WebIdeCounter.increment_pipelines_count
|
||||
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ module Repositories
|
|||
end
|
||||
|
||||
def log_user_activity
|
||||
Users::ActivityService.new(user).execute
|
||||
Users::ActivityService.new(author: user, project: project, namespace: project&.namespace).execute
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -289,7 +289,7 @@ class SessionsController < Devise::SessionsController
|
|||
|
||||
def log_user_activity(user)
|
||||
login_counter.increment
|
||||
Users::ActivityService.new(user).execute
|
||||
Users::ActivityService.new(author: user).execute
|
||||
end
|
||||
|
||||
def load_recaptcha
|
||||
|
|
|
|||
|
|
@ -384,7 +384,6 @@ module ApplicationSettingsHelper
|
|||
:user_default_internal_regex,
|
||||
:user_oauth_applications,
|
||||
:version_check_enabled,
|
||||
:web_ide_clientside_preview_enabled,
|
||||
:diff_max_patch_bytes,
|
||||
:diff_max_files,
|
||||
:diff_max_lines,
|
||||
|
|
|
|||
|
|
@ -43,9 +43,7 @@ module IdeHelper
|
|||
'promotion-svg-path': image_path('illustrations/web-ide_promotion.svg'),
|
||||
'ci-help-page-path' => help_page_path('ci/quick_start/index'),
|
||||
'web-ide-help-page-path' => help_page_path('user/project/web_ide/index.md'),
|
||||
'clientside-preview-enabled': Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?.to_s,
|
||||
'render-whitespace-in-code': current_user.render_whitespace_in_code.to_s,
|
||||
'codesandbox-bundler-url': Gitlab::CurrentSettings.web_ide_clientside_preview_bundler_url,
|
||||
'default-branch' => @project && @project.default_branch,
|
||||
'project' => convert_to_project_entity_json(@project),
|
||||
'enable-environments-guidance' => enable_environments_guidance?.to_s,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ class ApplicationSetting < ApplicationRecord
|
|||
ignore_columns %i[static_objects_external_storage_auth_token], remove_with: '14.9', remove_after: '2022-03-22'
|
||||
ignore_column :user_email_lookup_limit, remove_with: '15.0', remove_after: '2022-04-18'
|
||||
ignore_column :send_user_confirmation_email, remove_with: '15.8', remove_after: '2022-12-18'
|
||||
ignore_column :web_ide_clientside_preview_enabled, remove_with: '15.11', remove_after: '2023-04-22'
|
||||
|
||||
INSTANCE_REVIEW_MIN_USERS = 50
|
||||
GRAFANA_URL_ERROR_MESSAGE = 'Please check your Grafana URL setting in ' \
|
||||
|
|
|
|||
|
|
@ -523,12 +523,6 @@ module ApplicationSettingImplementation
|
|||
static_objects_external_storage_url.present?
|
||||
end
|
||||
|
||||
# This will eventually be configurable
|
||||
# https://gitlab.com/gitlab-org/gitlab/issues/208161
|
||||
def web_ide_clientside_preview_bundler_url
|
||||
'https://sandbox-prod.gitlab-static.net'
|
||||
end
|
||||
|
||||
def ensure_key_restrictions!
|
||||
return if Gitlab::Database.read_only?
|
||||
return unless Gitlab::FIPS.enabled?
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ class EventCreateService
|
|||
Users::LastPushEventService.new(current_user)
|
||||
.cache_last_push_event(event)
|
||||
|
||||
Users::ActivityService.new(current_user).execute
|
||||
Users::ActivityService.new(author: current_user, namespace: namespace, project: project).execute
|
||||
end
|
||||
|
||||
def create_event(resource_parent, current_user, status, attributes = {})
|
||||
|
|
|
|||
|
|
@ -4,38 +4,56 @@ module Users
|
|||
class ActivityService
|
||||
LEASE_TIMEOUT = 1.minute.to_i
|
||||
|
||||
def initialize(author)
|
||||
def initialize(author:, namespace: nil, project: nil)
|
||||
@user = if author.respond_to?(:username)
|
||||
author
|
||||
elsif author.respond_to?(:user)
|
||||
author.user
|
||||
end
|
||||
|
||||
@user = nil unless @user.is_a?(User)
|
||||
@user = nil unless user.is_a?(User)
|
||||
@namespace = namespace
|
||||
@project = project
|
||||
end
|
||||
|
||||
def execute
|
||||
return unless @user
|
||||
return unless user
|
||||
|
||||
::Gitlab::Database::LoadBalancing::Session.without_sticky_writes { record_activity }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :user, :namespace, :project
|
||||
|
||||
def record_activity
|
||||
return if Gitlab::Database.read_only?
|
||||
|
||||
today = Date.today
|
||||
|
||||
return if @user.last_activity_on == today
|
||||
return if user.last_activity_on == today
|
||||
|
||||
lease = Gitlab::ExclusiveLease.new("activity_service:#{@user.id}",
|
||||
lease = Gitlab::ExclusiveLease.new("activity_service:#{user.id}",
|
||||
timeout: LEASE_TIMEOUT)
|
||||
return unless lease.try_obtain
|
||||
|
||||
@user.update_attribute(:last_activity_on, today)
|
||||
user.update_attribute(:last_activity_on, today)
|
||||
|
||||
Gitlab::UsageDataCounters::HLLRedisCounter.track_event('unique_active_user', values: @user.id)
|
||||
Gitlab::UsageDataCounters::HLLRedisCounter.track_event('unique_active_user', values: user.id)
|
||||
|
||||
return unless Feature.enabled?(:route_hll_to_snowplow_phase3)
|
||||
|
||||
Gitlab::Tracking.event(
|
||||
'Users::ActivityService',
|
||||
'perform_action',
|
||||
user: user,
|
||||
namespace: namespace,
|
||||
project: project,
|
||||
label: 'redis_hll_counters.manage.unique_active_users_monthly',
|
||||
context: [
|
||||
Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: 'unique_active_user').to_context
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -89,26 +89,6 @@
|
|||
.settings-content
|
||||
= render 'terminal'
|
||||
|
||||
%section.settings.no-animate#js-web-ide-settings{ class: ('expanded' if expanded_by_default?) }
|
||||
.settings-header
|
||||
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
|
||||
= _('Web IDE')
|
||||
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
|
||||
= expanded_by_default? ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Manage Web IDE features.')
|
||||
.settings-content
|
||||
= gitlab_ui_form_for @application_setting, url: general_admin_application_settings_path(anchor: "js-web-ide-settings"), html: { class: 'fieldset-form', id: 'web-ide-settings' } do |f|
|
||||
= form_errors(@application_setting)
|
||||
|
||||
%fieldset
|
||||
.form-group
|
||||
- link_start = '<a href="%{url}">'.html_safe % { url: help_page_path('user/project/web_ide/index', anchor: 'enable-live-preview') }
|
||||
= f.gitlab_ui_checkbox_component :web_ide_clientside_preview_enabled,
|
||||
s_('IDE|Live Preview'),
|
||||
help_text: s_('Preview JavaScript projects in the Web IDE with CodeSandbox Live Preview. %{link_start}Learn more.%{link_end} ').html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
|
||||
= f.submit _('Save changes'), pajamas_button: true
|
||||
|
||||
= render_if_exists 'admin/application_settings/maintenance_mode_settings_form'
|
||||
= render 'admin/application_settings/gitpod'
|
||||
= render 'admin/application_settings/kroki'
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@
|
|||
aws_tip_commands_link: help_page_path('ci/cloud_deployment/index.md', anchor: 'use-an-image-to-run-aws-commands'),
|
||||
aws_tip_learn_link: help_page_path('ci/cloud_deployment/index.md'),
|
||||
contains_variable_reference_link: help_page_path('ci/variables/index', anchor: 'prevent-cicd-variable-expansion'),
|
||||
protected_environment_variables_link: help_page_path('ci/variables/index', anchor: 'protect-a-cicd-variable'),
|
||||
masked_environment_variables_link: help_page_path('ci/variables/index', anchor: 'mask-a-cicd-variable'),
|
||||
environment_scope_link: help_page_path('ci/environments/index', anchor: 'limit-the-environment-scope-of-a-cicd-variable') } }
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
description: User's last_activity_on gets updated
|
||||
category: Users::ActivityService
|
||||
action: perform_action
|
||||
label_description: key_path of Service Ping metric redis_hll_counters.manage.unique_active_users_monthly
|
||||
property_description:
|
||||
value_description:
|
||||
extra_properties:
|
||||
identifiers:
|
||||
product_section: dev
|
||||
product_stage: manage
|
||||
product_group: manage
|
||||
product_category:
|
||||
milestone: "15.8"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108108
|
||||
distributions:
|
||||
- ce
|
||||
- ee
|
||||
tiers:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
||||
|
|
@ -590,8 +590,6 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
|
|||
end
|
||||
|
||||
scope :service_ping, controller: :service_ping do
|
||||
post :web_ide_clientside_preview # rubocop:todo Cop/PutProjectRoutesUnderScope
|
||||
post :web_ide_clientside_preview_success # rubocop:todo Cop/PutProjectRoutesUnderScope
|
||||
post :web_ide_pipelines_count # rubocop:todo Cop/PutProjectRoutesUnderScope
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
stage: verify # (required) String value of the stage that the feature was created in. e.g., Growth
|
||||
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/381669 # (required) Link to the deprecation issue in GitLab
|
||||
body: | # (required) Do not modify this line, instead modify the lines below.
|
||||
The `POST ci/lint` API endpoint is deprecated in 15.7, and will be removed in 16.0. This endpoint does not validate the full range of CI/CD configuration options. Instead, use [`POST /projects/:id/ci/lint`](https://docs.gitlab.com/15.5/ee/api/lint.html#validate-a-ci-yaml-configuration-with-a-namespace), which properly validates CI/CD configuration.
|
||||
The `POST ci/lint` API endpoint is deprecated in 15.7, and will be removed in 16.0. This endpoint does not validate the full range of CI/CD configuration options. Instead, use [`POST /projects/:id/ci/lint`](https://docs.gitlab.com/ee/api/lint.html#validate-a-ci-yaml-configuration-with-a-namespace), which properly validates CI/CD configuration.
|
||||
#
|
||||
# OPTIONAL END OF SUPPORT FIELDS
|
||||
#
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddDeployKeyIdToCreateAccessLevels < Gitlab::Database::Migration[2.1]
|
||||
def up
|
||||
add_column :protected_tag_create_access_levels, :deploy_key_id, :integer
|
||||
end
|
||||
|
||||
def down
|
||||
remove_column :protected_tag_create_access_levels, :deploy_key_id
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddIndexForProtectedTagCreateAccessLevels < Gitlab::Database::Migration[2.1]
|
||||
disable_ddl_transaction!
|
||||
|
||||
DEPLOY_KEY_INDEX_NAME = 'index_protected_tag_create_access_levels_on_deploy_key_id'
|
||||
|
||||
def up
|
||||
add_concurrent_foreign_key :protected_tag_create_access_levels, :keys, column: :deploy_key_id, on_delete: :cascade
|
||||
add_concurrent_index :protected_tag_create_access_levels, :deploy_key_id,
|
||||
name: DEPLOY_KEY_INDEX_NAME
|
||||
end
|
||||
|
||||
def down
|
||||
remove_foreign_key_if_exists :protected_tag_create_access_levels, column: :deploy_key_id
|
||||
remove_concurrent_index_by_name :protected_tag_create_access_levels, name: DEPLOY_KEY_INDEX_NAME
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
be87eb6052d3f853f05f59a6deb8669857047ca95d28b209b1c19c66fa96ff15
|
||||
|
|
@ -0,0 +1 @@
|
|||
277c1abd9cc4f9fb6aca4991b7643d8b9964ef466f4d209848c90b34c8eec9c0
|
||||
|
|
@ -21005,7 +21005,8 @@ CREATE TABLE protected_tag_create_access_levels (
|
|||
user_id integer,
|
||||
group_id integer,
|
||||
created_at timestamp without time zone NOT NULL,
|
||||
updated_at timestamp without time zone NOT NULL
|
||||
updated_at timestamp without time zone NOT NULL,
|
||||
deploy_key_id integer
|
||||
);
|
||||
|
||||
CREATE SEQUENCE protected_tag_create_access_levels_id_seq
|
||||
|
|
@ -31069,6 +31070,8 @@ CREATE UNIQUE INDEX index_protected_environments_on_project_id_and_name ON prote
|
|||
|
||||
CREATE INDEX index_protected_tag_create_access ON protected_tag_create_access_levels USING btree (protected_tag_id);
|
||||
|
||||
CREATE INDEX index_protected_tag_create_access_levels_on_deploy_key_id ON protected_tag_create_access_levels USING btree (deploy_key_id);
|
||||
|
||||
CREATE INDEX index_protected_tag_create_access_levels_on_group_id ON protected_tag_create_access_levels USING btree (group_id);
|
||||
|
||||
CREATE INDEX index_protected_tag_create_access_levels_on_user_id ON protected_tag_create_access_levels USING btree (user_id);
|
||||
|
|
@ -33597,6 +33600,9 @@ ALTER TABLE ONLY sprints
|
|||
ALTER TABLE ONLY push_event_payloads
|
||||
ADD CONSTRAINT fk_36c74129da FOREIGN KEY (event_id) REFERENCES events(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY protected_tag_create_access_levels
|
||||
ADD CONSTRAINT fk_386a642e13 FOREIGN KEY (deploy_key_id) REFERENCES keys(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY incident_management_timeline_events
|
||||
ADD CONSTRAINT fk_38a74279df FOREIGN KEY (updated_by_user_id) REFERENCES users(id) ON DELETE SET NULL;
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,10 @@ To enable the Atlassian OmniAuth provider for passwordless authentication you mu
|
|||
sudo -u git -H editor /home/git/gitlab/config/gitlab.yml
|
||||
```
|
||||
|
||||
1. See [Configure initial settings](../../integration/omniauth.md#configure-initial-settings) for initial settings to enable single sign-on and add `atlassian_oauth2` as an OAuth provider.
|
||||
1. Edit the [common configuration file settings](../../integration/omniauth.md#configure-common-settings)
|
||||
to add `atlassian_oauth2` as a single sign-on provider. This enables
|
||||
Just-In-Time account provisioning for users who do not have an existing
|
||||
GitLab account.
|
||||
1. Add the provider configuration for Atlassian:
|
||||
|
||||
For Omnibus GitLab installations:
|
||||
|
|
|
|||
|
|
@ -27,7 +27,9 @@ Authentiq generates a Client ID and the accompanying Client Secret for you to us
|
|||
sudo -u git -H editor /home/git/gitlab/config/gitlab.yml
|
||||
```
|
||||
|
||||
1. See [Configure initial settings](../../integration/omniauth.md#configure-initial-settings) for initial settings to enable single sign-on and add Authentiq as an OAuth provider.
|
||||
1. Edit the [common configuration file settings](../../integration/omniauth.md#configure-common-settings)
|
||||
to add `authentiq` as a single sign-on provider. This enables Just-In-Time
|
||||
account provisioning for users who do not have an existing GitLab account.
|
||||
|
||||
1. Add the provider configuration for Authentiq:
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,9 @@ To enable AWS Cognito as an authentication provider, complete the following step
|
|||
|
||||
## Configure GitLab
|
||||
|
||||
1. See [Configure initial settings](../../integration/omniauth.md#configure-initial-settings) for initial settings.
|
||||
1. Edit the [common configuration file settings](../../integration/omniauth.md#configure-common-settings)
|
||||
to add `cognito` as a single sign-on provider. This enables Just-In-Time
|
||||
account provisioning for users who do not have an existing GitLab account.
|
||||
1. On your GitLab server, open the configuration file.
|
||||
|
||||
**For Omnibus installations**
|
||||
|
|
@ -95,4 +97,4 @@ Select this option to begin the authentication process.
|
|||
AWS Cognito then asks you to sign in and authorize the GitLab application.
|
||||
If the authorization is successful, you're redirected and signed in to your GitLab instance.
|
||||
|
||||
For more information, see [Configure initial settings](../../integration/omniauth.md#configure-initial-settings).
|
||||
For more information, see [Configure common settings](../../integration/omniauth.md#configure-common-settings).
|
||||
|
|
|
|||
|
|
@ -40,8 +40,9 @@ this provider also allows Crowd authentication for Git-over-https requests.
|
|||
sudo -u git -H editor config/gitlab.yml
|
||||
```
|
||||
|
||||
1. See [Configure initial settings](../../integration/omniauth.md#configure-initial-settings)
|
||||
for initial settings.
|
||||
1. Edit the [common configuration file settings](../../integration/omniauth.md#configure-common-settings)
|
||||
to add `crowd` as a single sign-on provider. This enables Just-In-Time
|
||||
account provisioning for users who do not have an existing GitLab account.
|
||||
|
||||
1. Add the provider configuration:
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,9 @@ JWT provides you with a secret key for you to use.
|
|||
sudo -u git -H editor config/gitlab.yml
|
||||
```
|
||||
|
||||
1. See [Configure initial settings](../../integration/omniauth.md#configure-initial-settings) for initial settings.
|
||||
1. Edit the [common configuration file settings](../../integration/omniauth.md#configure-common-settings)
|
||||
to add `jwt` as a single sign-on provider. This enables Just-In-Time
|
||||
account provisioning for users who do not have an existing GitLab account.
|
||||
1. Add the provider configuration.
|
||||
|
||||
For Omnibus GitLab:
|
||||
|
|
|
|||
|
|
@ -29,7 +29,9 @@ The OpenID Connect provides you with a client's details and secret for you to us
|
|||
sudo -u git -H editor config/gitlab.yml
|
||||
```
|
||||
|
||||
1. [Configure initial settings](../../integration/omniauth.md#configure-initial-settings).
|
||||
1. Edit the [common configuration file settings](../../integration/omniauth.md#configure-common-settings)
|
||||
to add `openid_connect` as a single sign-on provider. This enables Just-In-Time
|
||||
account provisioning for users who do not have an existing GitLab account.
|
||||
|
||||
1. Add the provider configuration.
|
||||
|
||||
|
|
@ -254,7 +256,7 @@ Azure B2C [offers two ways of defining the business logic for logging in a user]
|
|||
Custom policies are required because standard Azure B2C user flows
|
||||
[do not send the OpenID `email` claim](https://github.com/MicrosoftDocs/azure-docs/issues/16566).
|
||||
Therefore, the standard user flows do not work with the
|
||||
[`allow_single_sign_on` or `auto_link_user` parameters](../../integration/omniauth.md#configure-initial-settings).
|
||||
[`allow_single_sign_on` or `auto_link_user` parameters](../../integration/omniauth.md#configure-common-settings).
|
||||
With a standard Azure B2C policy, GitLab cannot create a new account or
|
||||
link to an existing account with an email address.
|
||||
|
||||
|
|
|
|||
|
|
@ -522,7 +522,6 @@ listed in the descriptions of the relevant settings.
|
|||
| `user_show_add_ssh_key_message` | boolean | no | When set to `false` disable the `You won't be able to pull or push project code via SSH` warning shown to users with no uploaded SSH key. |
|
||||
| `version_check_enabled` | boolean | no | Let GitLab inform you when an update is available. |
|
||||
| `whats_new_variant` | string | no | What's new variant, possible values: `all_tiers`, `current_tier`, and `disabled`. |
|
||||
| `web_ide_clientside_preview_enabled` | boolean | no | Live Preview (allow live previews of JavaScript projects in the Web IDE using CodeSandbox Live Preview). |
|
||||
| `wiki_page_max_content_bytes` | integer | no | Maximum wiki page content size in **bytes**. Default: 52428800 Bytes (50 MB). The minimum value is 1024 bytes. |
|
||||
| `jira_connect_application_key` | String | no | Application ID of the OAuth application that should be used to authenticate with the GitLab for Jira Cloud app |
|
||||
| `jira_connect_proxy_url` | String | no | URL of the GitLab instance that should be used as a proxy for the GitLab for Jira Cloud app |
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ The current production [Web IDE](../../../user/project/web_ide/index.md).
|
|||
|
||||
An advanced editor with commit staging that currently supports:
|
||||
|
||||
- [Live Preview](../../../user/project/web_ide/index.md#live-preview)
|
||||
- [Live Preview](../../../user/project/web_ide/index.md#live-preview-removed)
|
||||
- [Interactive Web Terminals](../../../user/project/web_ide/index.md#interactive-web-terminals-for-the-web-ide)
|
||||
|
||||
### Web IDE
|
||||
|
|
|
|||
|
|
@ -200,10 +200,8 @@ associated with your project, you can configure these deployments from your
|
|||
`.gitlab-ci.yml` file.
|
||||
|
||||
NOTE:
|
||||
Kubernetes configuration isn't supported for Kubernetes clusters that are
|
||||
Kubernetes configuration isn't supported for Kubernetes clusters
|
||||
[managed by GitLab](../../user/project/clusters/gitlab_managed_clusters.md).
|
||||
To follow progress on support for GitLab-managed clusters, see the
|
||||
[relevant issue](https://gitlab.com/gitlab-org/gitlab/-/issues/38054).
|
||||
|
||||
The following configuration options are supported:
|
||||
|
||||
|
|
|
|||
|
|
@ -1780,9 +1780,7 @@ environment, using the `production`
|
|||
**Additional details**:
|
||||
|
||||
- Kubernetes configuration is not supported for Kubernetes clusters
|
||||
that are [managed by GitLab](../../user/project/clusters/gitlab_managed_clusters.md).
|
||||
To follow progress on support for GitLab-managed clusters, see the
|
||||
[relevant issue](https://gitlab.com/gitlab-org/gitlab/-/issues/38054).
|
||||
[managed by GitLab](../../user/project/clusters/gitlab_managed_clusters.md).
|
||||
|
||||
**Related topics**:
|
||||
|
||||
|
|
|
|||
|
|
@ -2,12 +2,17 @@
|
|||
stage: none
|
||||
group: Development
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
remove_date: '2023-02-01'
|
||||
---
|
||||
|
||||
# Set up local CodeSandbox development environment
|
||||
# Set up local CodeSandbox development environment (removed)
|
||||
|
||||
WARNING:
|
||||
This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108627) in GitLab 15.8
|
||||
and is planned for removal in 15.9. This change is a breaking change.
|
||||
|
||||
This guide walks through setting up a local [CodeSandbox repository](https://github.com/codesandbox/codesandbox-client) and integrating it with a local GitLab instance. CodeSandbox
|
||||
is used to power the Web IDE [Live Preview feature](../../user/project/web_ide/index.md#live-preview). Having a local CodeSandbox setup is useful for debugging upstream issues or
|
||||
is used to power the Web IDE [Live Preview feature](../../user/project/web_ide/index.md#live-preview-removed). Having a local CodeSandbox setup is useful for debugging upstream issues or
|
||||
creating upstream contributions like [this one](https://github.com/codesandbox/codesandbox-client/pull/5137).
|
||||
|
||||
## Initial setup
|
||||
|
|
@ -114,7 +119,11 @@ out of the box:
|
|||
npx http-server --proxy http://localhost:3000 -S -C $PATH_TO_CERT_PEM -K $PATH_TO_KEY_PEM -p 8044 -d false
|
||||
```
|
||||
|
||||
### Update `bundler_url` setting in GitLab
|
||||
### Update `bundler_url` setting in GitLab (removed)
|
||||
|
||||
WARNING:
|
||||
This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108627) in GitLab 15.8
|
||||
and is planned for removal in 15.9. This change is a breaking change.
|
||||
|
||||
We need to update our `application_setting_implementation.rb` to point to the server that hosts the
|
||||
CodeSandbox `sandpack` assets. For instance, if these assets are hosted by a server at `https://sandpack.local:8044`:
|
||||
|
|
|
|||
|
|
@ -210,7 +210,6 @@ The following is example content of the Service Ping payload.
|
|||
"prometheus_metrics_enabled": false,
|
||||
"reply_by_email_enabled": "incoming+%{key}@incoming.gitlab.com",
|
||||
"signup_enabled": true,
|
||||
"web_ide_clientside_preview_enabled": true,
|
||||
"projects_with_expiration_policy_disabled": 999,
|
||||
"projects_with_expiration_policy_enabled": 999,
|
||||
...
|
||||
|
|
|
|||
|
|
@ -59,7 +59,9 @@ Sign in to the AliCloud platform and create an application on it. AliCloud gener
|
|||
sudo -u git -H editor config/gitlab.yml
|
||||
```
|
||||
|
||||
1. [Configure the initial settings](omniauth.md#configure-initial-settings).
|
||||
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
|
||||
to add `alicloud` as a single sign-on provider. This enables Just-In-Time
|
||||
account provisioning for users who do not have an existing GitLab account.
|
||||
|
||||
1. Add the provider configuration. Replace `YOUR_APP_ID` with the ID on the application details page
|
||||
and `YOUR_APP_SECRET` with the **SecretValue** you got when you registered the AliCloud application.
|
||||
|
|
|
|||
|
|
@ -42,8 +42,9 @@ application.
|
|||
sudo -u git -H editor config/gitlab.yml
|
||||
```
|
||||
|
||||
1. Read [Configure initial settings](omniauth.md#configure-initial-settings)
|
||||
for initial settings.
|
||||
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
|
||||
to add `auth0` as a single sign-on provider. This enables Just-In-Time
|
||||
account provisioning for users who do not have an existing GitLab account.
|
||||
|
||||
1. Add the provider configuration:
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,9 @@ Alternatively, add the `User.Read.All` application permission.
|
|||
sudo -u git -H editor config/gitlab.yml
|
||||
```
|
||||
|
||||
1. [Configure the initial settings](omniauth.md#configure-initial-settings).
|
||||
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
|
||||
to add `azure_oauth2` as a single sign-on provider. This enables Just-In-Time
|
||||
account provisioning for users who do not have an existing GitLab account.
|
||||
|
||||
1. Add the provider configuration. Replace `<client_id>`, `<client_secret>`, and `<tenant_id>`
|
||||
with the values you got when you registered the Azure application.
|
||||
|
|
|
|||
|
|
@ -32,7 +32,9 @@ configure CAS for back-channel logout.
|
|||
sudo -u git -H editor config/gitlab.yml
|
||||
```
|
||||
|
||||
1. See [Configure initial settings](omniauth.md#configure-initial-settings) for initial settings.
|
||||
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
|
||||
to add `cas3` as a single sign-on provider. This enables Just-In-Time
|
||||
account provisioning for users who do not have an existing GitLab account.
|
||||
|
||||
1. Add the provider configuration:
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,9 @@ Sign in to DingTalk Open Platform and create an application on it. DingTalk gene
|
|||
sudo -u git -H editor config/gitlab.yml
|
||||
```
|
||||
|
||||
1. See [Configure initial settings](omniauth.md#configure-initial-settings) for initial settings.
|
||||
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
|
||||
to add `dingtalk` as a single sign-on provider. This enables Just-In-Time
|
||||
account provisioning for users who do not have an existing GitLab account.
|
||||
|
||||
1. Add the provider configuration:
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,9 @@ Facebook. Facebook generates an app ID and secret key for you to use.
|
|||
sudo -u git -H editor config/gitlab.yml
|
||||
```
|
||||
|
||||
1. See [Configure initial settings](omniauth.md#configure-initial-settings) for initial settings.
|
||||
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
|
||||
to add `facebook` as a single sign-on provider. This enables Just-In-Time
|
||||
account provisioning for users who do not have an existing GitLab account.
|
||||
|
||||
1. Add the provider configuration:
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,9 @@ your website could enable the covert redirect attack.
|
|||
|
||||
## Enable GitHub OAuth in GitLab
|
||||
|
||||
1. [Configure the initial settings](omniauth.md#configure-initial-settings) in GitLab.
|
||||
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
|
||||
to add `github` as a single sign-on provider. This enables Just-In-Time
|
||||
account provisioning for users who do not have an existing GitLab account.
|
||||
|
||||
1. Edit the GitLab configuration file using the following information:
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,9 @@ GitLab.com generates an application ID and secret key for you to use.
|
|||
sudo -u git -H editor config/gitlab.yml
|
||||
```
|
||||
|
||||
1. See [Configure initial settings](omniauth.md#configure-initial-settings) for initial settings.
|
||||
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
|
||||
to add `gitlab` as a single sign-on provider. This enables Just-In-Time
|
||||
account provisioning for users who do not have an existing GitLab account.
|
||||
1. Add the provider configuration:
|
||||
|
||||
For Omnibus installations authenticating against **GitLab.com**:
|
||||
|
|
|
|||
|
|
@ -71,7 +71,9 @@ On your GitLab server:
|
|||
sudo -u git -H editor config/gitlab.yml
|
||||
```
|
||||
|
||||
1. See [Configure initial settings](omniauth.md#configure-initial-settings) for initial settings.
|
||||
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
|
||||
to add `google_oauth2` as a single sign-on provider. This enables Just-In-Time
|
||||
account provisioning for users who do not have an existing GitLab account.
|
||||
1. Add the provider configuration:
|
||||
|
||||
For Omnibus GitLab:
|
||||
|
|
|
|||
|
|
@ -99,9 +99,9 @@ to authenticate with Kerberos tokens.
|
|||
|
||||
#### Enable single sign-on
|
||||
|
||||
See [Configure initial settings](omniauth.md#configure-initial-settings)
|
||||
for initial settings to enable single sign-on and add Kerberos servers
|
||||
as an identity provider.
|
||||
Edit the [common configuration file settings](omniauth.md#configure-common-settings)
|
||||
to add `kerberos` as a single sign-on provider. This enables Just-In-Time
|
||||
account provisioning for users who do not have an existing GitLab account.
|
||||
|
||||
## Create and link Kerberos accounts
|
||||
|
||||
|
|
@ -138,7 +138,8 @@ with your Kerberos credentials.
|
|||
|
||||
The first time users sign in to GitLab with their Kerberos accounts,
|
||||
GitLab creates a matching account.
|
||||
Before you continue, review the [Configure initial settings](omniauth.md#configure-initial-settings) options in Omnibus and GitLab source. You must also include `kerberos`.
|
||||
Before you continue, review the [common configuration settings](omniauth.md#configure-common-settings)
|
||||
options in Omnibus and GitLab source. You must also include `kerberos`.
|
||||
|
||||
With that information at hand:
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,9 @@ To configure the provider:
|
|||
|
||||
:::TabTitle Linux package (Omnibus)
|
||||
|
||||
1. [Configure the initial settings](omniauth.md#configure-initial-settings).
|
||||
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
|
||||
to add `oauth2_generic` as a single sign-on provider. This enables Just-In-Time
|
||||
account provisioning for users who do not have an existing GitLab account.
|
||||
1. Edit `/etc/gitlab/gitlab.rb` to add the configuration for your provider. For example:
|
||||
|
||||
```ruby
|
||||
|
|
@ -96,7 +98,9 @@ To configure the provider:
|
|||
|
||||
:::TabTitle Helm chart (Kubernetes)
|
||||
|
||||
1. [Configure the initial settings](omniauth.md#configure-initial-settings).
|
||||
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
|
||||
to add `oauth2_generic` as a single sign-on provider. This enables Just-In-Time
|
||||
account provisioning for users who do not have an existing GitLab account.
|
||||
1. Export the Helm values:
|
||||
|
||||
```shell
|
||||
|
|
@ -146,7 +150,9 @@ To configure the provider:
|
|||
|
||||
:::TabTitle Self-compiled (source)
|
||||
|
||||
1. [Configure the initial settings](omniauth.md#configure-initial-settings).
|
||||
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
|
||||
to add `oauth2_generic` as a single sign-on provider. This enables Just-In-Time
|
||||
account provisioning for users who do not have an existing GitLab account.
|
||||
1. Edit `/home/git/gitlab/config/gitlab.yml`:
|
||||
|
||||
```yaml
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ GitLab supports the following OmniAuth providers.
|
|||
| [SAML](saml.md) | `saml` |
|
||||
| [Twitter](twitter.md) | `twitter` |
|
||||
|
||||
## Initial settings
|
||||
## Configure common settings
|
||||
|
||||
Before you configure the OmniAuth provider,
|
||||
configure the settings that are common for all providers.
|
||||
|
|
@ -503,7 +503,7 @@ There are two methods to update the `extern_uid`:
|
|||
Identity.where(extern_uid: 'old-id').update!(extern_uid: 'new-id')`
|
||||
```
|
||||
|
||||
## Limitations
|
||||
## Known issues
|
||||
|
||||
Most supported OmniAuth providers don't support Git over HTTP password authentication.
|
||||
As a workaround, you can authenticate using a [personal access token](../user/profile/personal_access_tokens.md).
|
||||
|
|
|
|||
|
|
@ -48,7 +48,9 @@ To get the credentials (a pair of Client ID and Client Secret), you must [create
|
|||
sudo -u git -H editor config/gitlab.yml
|
||||
```
|
||||
|
||||
1. See [Configure initial settings](omniauth.md#configure-initial-settings) for initial settings.
|
||||
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
|
||||
to add `salesforce` as a single sign-on provider. This enables Just-In-Time
|
||||
account provisioning for users who do not have an existing GitLab account.
|
||||
|
||||
1. Add the provider configuration:
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,9 @@ For more information on:
|
|||
sudo -u git -H editor config/gitlab.yml
|
||||
```
|
||||
|
||||
1. Edit the initial [configuration settings](omniauth.md#configure-initial-settings).
|
||||
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
|
||||
to add `saml` as a single sign-on provider. This enables Just-In-Time
|
||||
account provisioning for users who do not have an existing GitLab account.
|
||||
|
||||
1. To allow your users to use SAML to sign up without having to manually create
|
||||
an account first, add the following values to your configuration.
|
||||
|
|
|
|||
|
|
@ -62,7 +62,9 @@ Twitter. Twitter generates a client ID and secret key for you to use.
|
|||
sudo -u git -H editor config/gitlab.yml
|
||||
```
|
||||
|
||||
1. See [Configure initial settings](omniauth.md#configure-initial-settings) for initial settings.
|
||||
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
|
||||
to add `twitter` as a single sign-on provider. This enables Just-In-Time
|
||||
account provisioning for users who do not have an existing GitLab account.
|
||||
|
||||
1. Add the provider configuration.
|
||||
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ GitLab has several features which can help you manage the number of users:
|
|||
|
||||
- Enable the [**Require administrator approval for new sign ups**](../../user/admin_area/settings/sign_up_restrictions.md#require-administrator-approval-for-new-sign-ups)
|
||||
option.
|
||||
- Enable `block_auto_created_users` for new sign-ups via [LDAP](../../administration/auth/ldap/index.md#basic-configuration-settings) or [OmniAuth](../../integration/omniauth.md#configure-initial-settings).
|
||||
- Enable `block_auto_created_users` for new sign-ups via [LDAP](../../administration/auth/ldap/index.md#basic-configuration-settings) or [OmniAuth](../../integration/omniauth.md#configure-common-settings).
|
||||
- Enable the [User cap](../../user/admin_area/settings/sign_up_restrictions.md#user-cap)
|
||||
option. **Available in GitLab 13.7 and later**.
|
||||
- [Disable new sign-ups](../../user/admin_area/settings/sign_up_restrictions.md), and instead manage new
|
||||
|
|
|
|||
|
|
@ -836,7 +836,7 @@ WARNING:
|
|||
This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
|
||||
Review the details carefully before upgrading.
|
||||
|
||||
The `POST ci/lint` API endpoint is deprecated in 15.7, and will be removed in 16.0. This endpoint does not validate the full range of CI/CD configuration options. Instead, use [`POST /projects/:id/ci/lint`](https://docs.gitlab.com/15.5/ee/api/lint.html#validate-a-ci-yaml-configuration-with-a-namespace), which properly validates CI/CD configuration.
|
||||
The `POST ci/lint` API endpoint is deprecated in 15.7, and will be removed in 16.0. This endpoint does not validate the full range of CI/CD configuration options. Instead, use [`POST /projects/:id/ci/lint`](https://docs.gitlab.com/ee/api/lint.html#validate-a-ci-yaml-configuration-with-a-namespace), which properly validates CI/CD configuration.
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ pending approval state because an administrator has enabled any of the following
|
|||
|
||||
- [Require administrator approval for new sign-ups](settings/sign_up_restrictions.md#require-administrator-approval-for-new-sign-ups) setting.
|
||||
- [User cap](settings/sign_up_restrictions.md#user-cap).
|
||||
- [Block auto-created users (OmniAuth)](../../integration/omniauth.md#configure-initial-settings)
|
||||
- [Block auto-created users (OmniAuth)](../../integration/omniauth.md#configure-common-settings)
|
||||
- [Block auto-created users (LDAP)](../../administration/auth/ldap/index.md#basic-configuration-settings)
|
||||
|
||||
When a user registers for an account while this setting is enabled:
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@ The **General** settings contain:
|
|||
- [External Authentication](external_authorization.md#configuration) - External Classification Policy Authorization.
|
||||
- [Web terminal](../../../administration/integration/terminal.md#limiting-websocket-connection-time) -
|
||||
Set max session time for web terminal.
|
||||
- [Web IDE](../../project/web_ide/index.md#enable-live-preview) - Manage Web IDE features.
|
||||
- [FLoC](floc.md) - Enable or disable
|
||||
[Federated Learning of Cohorts (FLoC)](https://en.wikipedia.org/wiki/Federated_Learning_of_Cohorts) tracking.
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ automatically approved in a background job.
|
|||
NOTE:
|
||||
This setting doesn't apply to LDAP or OmniAuth users. To enforce approvals for new users
|
||||
signing up using OmniAuth or LDAP, set `block_auto_created_users` to `true` in the
|
||||
[OmniAuth configuration](../../../integration/omniauth.md#configure-initial-settings) or
|
||||
[OmniAuth configuration](../../../integration/omniauth.md#configure-common-settings) or
|
||||
[LDAP configuration](../../../administration/auth/ldap/index.md#basic-configuration-settings).
|
||||
|
||||
## Require email confirmation
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ On self-managed GitLab, by default this feature is not available. To make it ava
|
|||
Cluster cost management provides insights into cluster resource usage. GitLab provides an example
|
||||
[`kubecost-cost-model`](https://gitlab.com/gitlab-examples/kubecost-cost-model/)
|
||||
project that uses the GitLab Prometheus integration and
|
||||
[Kubecost's `cost-model`](https://github.com/kubecost/cost-model) to provide cluster cost
|
||||
[OpenCost `cost-model`](https://github.com/opencost/opencost) to provide cluster cost
|
||||
insights within GitLab:
|
||||
|
||||

|
||||
|
|
|
|||
|
|
@ -109,9 +109,9 @@ Users granted:
|
|||
|
||||
### Automatic member removal
|
||||
|
||||
After a group sync, for GitLab subgroups, users who are not members of a mapped SAML
|
||||
group are removed from the group. Users in the top-level group are assigned the
|
||||
[default membership role](index.md#role).
|
||||
After a group sync, users who are not members of a mapped SAML group are removed from the group.
|
||||
On GitLab.com, users in the top-level group are assigned the
|
||||
[default membership role](index.md#role) instead of being removed.
|
||||
|
||||
For example, in the following diagram:
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
# Authenticate with the Container Registry **(FREE)**
|
||||
|
||||
<!--- start_remove The following content will be removed on remove_date: '2023-11-22' -->
|
||||
WARNING:
|
||||
[External authorization](../../admin_area/settings/external_authorization.md) will be enabled by default in GitLab 16.0. External authorization prevents personal access tokens and deploy tokens from accessing container and package registries and affects all users who use these tokens to access the registries. You can disable external authorization if you want to use personal access tokens and deploy tokens with the container or package registries.
|
||||
<!--- end_remove -->
|
||||
|
||||
To authenticate with the Container Registry, you can use a:
|
||||
|
||||
- [Personal access token](../../profile/personal_access_tokens.md).
|
||||
|
|
|
|||
|
|
@ -43,6 +43,11 @@ For information on how to create and upload a package, view the GitLab documenta
|
|||
|
||||
## Authenticate with the registry
|
||||
|
||||
<!--- start_remove The following content will be removed on remove_date: '2023-11-22' -->
|
||||
WARNING:
|
||||
[External authorization](../../admin_area/settings/external_authorization.md) will be enabled by default in GitLab 16.0. External authorization prevents personal access tokens and deploy tokens from accessing container and package registries and affects all users who use these tokens to access the registries. You can disable external authorization if you want to use personal access tokens and deploy tokens with the container or package registries.
|
||||
<!--- end_remove -->
|
||||
|
||||
Authentication depends on the package manager being used. For more information, see the docs on the
|
||||
specific package format you want to use.
|
||||
|
||||
|
|
@ -59,7 +64,6 @@ For most package types, the following credential types are valid:
|
|||
- [Job token](../../../ci/jobs/ci_job_token.md):
|
||||
allows access to packages in the project running the job for the users running the pipeline.
|
||||
Access to other external projects can be configured.
|
||||
|
||||
- If your organization uses two factor authentication (2FA), you must use a personal access token with the scope set to `api`.
|
||||
- If you are publishing a package via CI/CD pipelines, you must use a CI job token.
|
||||
|
||||
|
|
|
|||
|
|
@ -96,6 +96,14 @@ When selected, GitLab creates a [to-do list item](../../todos.md) for each revie
|
|||
|
||||
To learn more, read [Review a merge request](reviews/index.md).
|
||||
|
||||
#### Multiple reviewers for merge requests **(PREMIUM)**
|
||||
|
||||
> Introduced in GitLab 13.7.
|
||||
|
||||
Merge requests may often require multiple team members to review parts of the
|
||||
proposed changes. You can add multiple reviewers to a merge request, making it
|
||||
easier to see who is reviewing changes and who has approved changes.
|
||||
|
||||
### Merge requests to close issues
|
||||
|
||||
To create a merge request to close an issue when it's merged, you can either:
|
||||
|
|
|
|||
|
|
@ -15,21 +15,21 @@ Suggested Reviewers is the first user-facing GitLab machine learning (ML) powere
|
|||
|
||||
When a Project Maintainer or Owner enables Suggested Reviewers in project settings GitLab kicks off a data extraction job for the project which leverages the Merge Request API to understand pattern of review including recency, domain experience, and frequency to suggest an appropriate reviewer.
|
||||
|
||||
This data extraction job can take a few hours to complete (possibly up to a day), which is largely dependent on the size of the project. The process is automated and no action is needed during this process. Once data extraction is complete, you will start getting suggestions in merge requests.
|
||||
This data extraction job can take a few hours to complete (possibly up to a day), which is largely dependent on the size of the project. The process is automated and no action is needed during this process. Once data extraction is complete, you start getting suggestions in merge requests.
|
||||
|
||||
### Generating suggestions
|
||||
|
||||
Once Suggested Reviewers is enabled and the data extraction is complete, new merge requests or new commits to existing merge requests will automatically trigger a Suggested Reviewers ML model inference and generate up to 5 suggested reviewers. These suggestions are contextual to the changes in the merge request. Additional commits to merge requests may change the reviewer suggestions which will automatically update in the reviewer dropdown list.
|
||||
Once Suggested Reviewers is enabled and the data extraction is complete, new merge requests or new commits to existing merge requests automatically trigger a Suggested Reviewers ML model inference and generate up to 5 suggested reviewers. These suggestions are contextual to the changes in the merge request. Additional commits to merge requests may change the reviewer suggestions, which are automatically updated in the reviewer dropdown list.
|
||||
|
||||
## Progressive enhancement
|
||||
|
||||
This feature is designed as a progressive enhancement to the existing GitLab Reviewers functionality. The GitLab Reviewer UI will only offer suggestions if the ML engine is able to provide a recommendation. In the event of an issue or model inference failure, the feature will gracefully degrade. At no point with the usage of Suggested Reviewers prevent a user from being able to manually set a reviewer.
|
||||
This feature is designed as a progressive enhancement to the existing GitLab Reviewers functionality. The GitLab Reviewer UI only offers suggestions if the ML engine is able to provide a recommendation. In the event of an issue or model inference failure, the feature gracefully degrades. At no point with the usage of Suggested Reviewers prevent a user from being able to manually set a reviewer.
|
||||
|
||||
## Model Accuracy
|
||||
|
||||
Organizations use many different processes for code review. Some focus on senior engineers reviewing junior engineer's code, others have hierarchical organizational structure based reviews. Suggested Reviewers is focused on contextual reviewers based on historical merge request activity by users. While we will continue evolving the underlying ML model to better serve various code review use cases and processes Suggested Reviewers does not replace the usage of other code review features like Code Owners and [Approval Rules](../approvals/rules.md). Reviewer selection is highly subjective therefore, we do not expect Suggested Reviewers to provide perfect suggestions every time.
|
||||
Organizations use many different processes for code review. Some focus on senior engineers reviewing junior engineer's code, others have hierarchical organizational structure based reviews. Suggested Reviewers is focused on contextual reviewers based on historical merge request activity by users. While we continue evolving the underlying ML model to better serve various code review use cases and processes Suggested Reviewers does not replace the usage of other code review features like Code Owners and [Approval Rules](../approvals/rules.md). Reviewer selection is highly subjective therefore, we do not expect Suggested Reviewers to provide perfect suggestions every time.
|
||||
|
||||
Through analysis of beta customer usage, we find that the Suggested Reviewers ML model provides suggestions that are adopted in 60% of cases. We will be introducing a feedback mechanism into the Suggested Reviewers feature in the future to allow users to flag bad reviewer suggestions to help improve the model. Additionally we will be offering an opt-in feature in the future which will allow the model to use your project's data for training the underlying model.
|
||||
Through analysis of beta customer usage, we find that the Suggested Reviewers ML model provides suggestions that are adopted in 60% of cases. We plan to introduce a feedback mechanism into the Suggested Reviewers feature in the future to allow users to flag bad reviewer suggestions to help improve the model. Additionally we plan to offer an opt-in feature in the future which allows the model to use your project's data for training the underlying model.
|
||||
|
||||
## Off by default
|
||||
|
||||
|
|
|
|||
|
|
@ -238,7 +238,13 @@ There are two ways to preview Markdown content in the Web IDE:
|
|||
1. Right-click or use the keyboard shortcut `Command/Control + Shift + P` and
|
||||
select **Preview Markdown** to toggle a live Markdown preview panel.
|
||||
|
||||
## Live Preview
|
||||
<!--- start_remove The following content will be removed on remove_date: '2023-02-01' -->
|
||||
|
||||
## Live Preview (removed)
|
||||
|
||||
WARNING:
|
||||
This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108627) in GitLab 15.8
|
||||
and is planned for removal in 15.9. This change is a breaking change.
|
||||
|
||||
> [Renamed](https://gitlab.com/gitlab-org/gitlab/-/issues/213853) from _Client Side Evaluation_ to _Live Preview_ in GitLab 13.0.
|
||||
|
||||
|
|
@ -283,6 +289,8 @@ An example `package.json`:
|
|||
}
|
||||
```
|
||||
|
||||
<!--- end_remove -->
|
||||
|
||||
## Interactive Web Terminals for the Web IDE
|
||||
|
||||
> [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/211685) from GitLab Ultimate to GitLab Free in 13.1.
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ If you do not want to use the Web IDE Beta, you can change your personal prefere
|
|||
## Known issues
|
||||
|
||||
The [Web Terminal](../web_ide/index.md#interactive-web-terminals-for-the-web-ide)
|
||||
and [Live Preview](../web_ide/index.md#live-preview) are not available in the Web IDE Beta.
|
||||
and [Live Preview](../web_ide/index.md#live-preview-removed) are not available in the Web IDE Beta.
|
||||
|
||||
These features might become available at a later date.
|
||||
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ module API
|
|||
|
||||
namespace do
|
||||
after do
|
||||
::Users::ActivityService.new(@current_user).execute
|
||||
::Users::ActivityService.new(author: @current_user, project: @project, namespace: @group).execute
|
||||
end
|
||||
|
||||
# Mount endpoints to include in the OpenAPI V2 documentation here
|
||||
|
|
|
|||
|
|
@ -58,7 +58,9 @@ module API
|
|||
def log_user_activity(actor)
|
||||
commands = Gitlab::GitAccess::DOWNLOAD_COMMANDS
|
||||
|
||||
::Users::ActivityService.new(actor).execute if commands.include?(params[:action])
|
||||
return unless commands.include?(params[:action])
|
||||
|
||||
::Users::ActivityService.new(author: actor, namespace: project&.namespace, project: project).execute
|
||||
end
|
||||
|
||||
def redis_ping
|
||||
|
|
|
|||
|
|
@ -250,8 +250,8 @@ module Gitlab
|
|||
prometheus_enabled: alt_usage_data(fallback: nil) { Gitlab::Prometheus::Internal.prometheus_enabled? },
|
||||
prometheus_metrics_enabled: alt_usage_data(fallback: nil) { Gitlab::Metrics.prometheus_metrics_enabled? },
|
||||
reply_by_email_enabled: alt_usage_data(fallback: nil) { Gitlab::IncomingEmail.enabled? },
|
||||
web_ide_clientside_preview_enabled: alt_usage_data(fallback: nil) { false },
|
||||
signup_enabled: alt_usage_data(fallback: nil) { Gitlab::CurrentSettings.allow_signup? },
|
||||
web_ide_clientside_preview_enabled: alt_usage_data(fallback: nil) { Gitlab::CurrentSettings.web_ide_clientside_preview_enabled? },
|
||||
grafana_link_enabled: alt_usage_data(fallback: nil) { Gitlab::CurrentSettings.grafana_enabled? },
|
||||
gitpod_enabled: alt_usage_data(fallback: nil) { Gitlab::CurrentSettings.gitpod_enabled? }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ module Gitlab
|
|||
EDIT_BY_SFE = 'g_edit_by_sfe'
|
||||
EDIT_BY_WEB_IDE = 'g_edit_by_web_ide'
|
||||
EDIT_CATEGORY = 'ide_edit'
|
||||
EDIT_BY_LIVE_PREVIEW = 'g_edit_by_live_preview'
|
||||
|
||||
class << self
|
||||
def track_web_ide_edit_action(author:, time: Time.zone.now, project:)
|
||||
|
|
@ -39,10 +38,6 @@ module Gitlab
|
|||
count_unique(events, date_from, date_to)
|
||||
end
|
||||
|
||||
def track_live_preview_edit_action(author:, time: Time.zone.now, project:)
|
||||
track_unique_action(EDIT_BY_LIVE_PREVIEW, author, time, project)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def track_unique_action(event_name, author, time, project = nil)
|
||||
|
|
|
|||
|
|
@ -27,18 +27,6 @@ module Gitlab
|
|||
count('pipelines')
|
||||
end
|
||||
|
||||
def increment_previews_count
|
||||
return unless Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?
|
||||
|
||||
count('previews')
|
||||
end
|
||||
|
||||
def increment_previews_success_count
|
||||
return unless Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?
|
||||
|
||||
count('previews_success')
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def redis_key(event)
|
||||
|
|
|
|||
|
|
@ -5152,6 +5152,9 @@ msgstr ""
|
|||
msgid "Approved"
|
||||
msgstr ""
|
||||
|
||||
msgid "Approved MRs"
|
||||
msgstr ""
|
||||
|
||||
msgid "Approved the current merge request."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -5445,6 +5448,9 @@ msgstr ""
|
|||
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
|
||||
msgstr ""
|
||||
|
||||
msgid "Ascending"
|
||||
msgstr ""
|
||||
|
||||
msgid "Ask again later"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -8765,6 +8771,9 @@ msgstr ""
|
|||
msgid "CiVariable|Create wildcard"
|
||||
msgstr ""
|
||||
|
||||
msgid "CiVariable|Define a CI/CD variable in the UI"
|
||||
msgstr ""
|
||||
|
||||
msgid "CiVariable|New environment"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -8959,6 +8968,9 @@ msgstr ""
|
|||
msgid "Closed %{epicTimeagoDate}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Closed MRs"
|
||||
msgstr ""
|
||||
|
||||
msgid "Closed date"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -11060,27 +11072,12 @@ msgstr ""
|
|||
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
|
||||
msgstr ""
|
||||
|
||||
msgid "ContributionAnalytics|%{pushes} by %{contributors}."
|
||||
msgstr ""
|
||||
|
||||
msgid "ContributionAnalytics|Approved MRs"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContributionAnalytics|Closed MRs"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContributionAnalytics|Closed issues"
|
||||
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
|
||||
msgstr ""
|
||||
|
||||
msgid "ContributionAnalytics|Contribution analytics for issues, merge requests and push events since %{start_date}"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContributionAnalytics|Contributions per group member"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContributionAnalytics|Failed to load the contribution stats"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContributionAnalytics|Issues"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -11093,18 +11090,9 @@ msgstr ""
|
|||
msgid "ContributionAnalytics|Last week"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContributionAnalytics|Loading contribution stats for group members"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContributionAnalytics|Merge requests"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContributionAnalytics|Merged MRs"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContributionAnalytics|Name"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContributionAnalytics|No issues for the selected time period."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -11114,15 +11102,6 @@ msgstr ""
|
|||
msgid "ContributionAnalytics|No pushes for the selected time period."
|
||||
msgstr ""
|
||||
|
||||
msgid "ContributionAnalytics|Opened MRs"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContributionAnalytics|Opened issues"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContributionAnalytics|Pushed"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContributionAnalytics|The given date range is larger than 31 days"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -11132,10 +11111,10 @@ msgstr ""
|
|||
msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
|
||||
msgstr ""
|
||||
|
||||
msgid "ContributionAnalytics|Total Contributions"
|
||||
msgid "Contributions for %{calendar_date}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Contributions for %{calendar_date}"
|
||||
msgid "Contributions per group member"
|
||||
msgstr ""
|
||||
|
||||
msgid "Contributor"
|
||||
|
|
@ -14110,6 +14089,9 @@ msgstr ""
|
|||
msgid "Deprioritize label"
|
||||
msgstr ""
|
||||
|
||||
msgid "Descending"
|
||||
msgstr ""
|
||||
|
||||
msgid "Describe the goal of the changes and what reviewers should be aware of."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -20816,9 +20798,6 @@ msgstr ""
|
|||
msgid "IDE"
|
||||
msgstr ""
|
||||
|
||||
msgid "IDE|Back"
|
||||
msgstr ""
|
||||
|
||||
msgid "IDE|Commit"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -20828,21 +20807,9 @@ msgstr ""
|
|||
msgid "IDE|Edit"
|
||||
msgstr ""
|
||||
|
||||
msgid "IDE|Get started with Live Preview"
|
||||
msgstr ""
|
||||
|
||||
msgid "IDE|Go to project"
|
||||
msgstr ""
|
||||
|
||||
msgid "IDE|Live Preview"
|
||||
msgstr ""
|
||||
|
||||
msgid "IDE|Preview your web application using Web IDE client-side evaluation."
|
||||
msgstr ""
|
||||
|
||||
msgid "IDE|Refresh preview"
|
||||
msgstr ""
|
||||
|
||||
msgid "IDE|Review"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -23958,10 +23925,10 @@ msgstr ""
|
|||
msgid "JiraService|Set a custom final state by using transition IDs. %{linkStart}Learn about transition IDs%{linkEnd}"
|
||||
msgstr ""
|
||||
|
||||
msgid "JiraService|Sign in to GitLab to link namespaces."
|
||||
msgid "JiraService|Sign in to GitLab to get started."
|
||||
msgstr ""
|
||||
|
||||
msgid "JiraService|Sign in to GitLab.com to get started."
|
||||
msgid "JiraService|Sign in to GitLab to link namespaces."
|
||||
msgstr ""
|
||||
|
||||
msgid "JiraService|This feature requires a Premium plan."
|
||||
|
|
@ -25255,9 +25222,6 @@ msgstr ""
|
|||
msgid "List your Bitbucket Server repositories"
|
||||
msgstr ""
|
||||
|
||||
msgid "Live preview"
|
||||
msgstr ""
|
||||
|
||||
msgid "Load more"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -25270,6 +25234,9 @@ msgstr ""
|
|||
msgid "Loading %{name}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loading contribution stats for group members"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loading files, directories, and submodules in the path %{path} for commit reference %{ref}"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -25501,9 +25468,6 @@ msgstr ""
|
|||
msgid "Manage %{workspace} labels"
|
||||
msgstr ""
|
||||
|
||||
msgid "Manage Web IDE features."
|
||||
msgstr ""
|
||||
|
||||
msgid "Manage access"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -26525,6 +26489,9 @@ msgstr ""
|
|||
msgid "Merged"
|
||||
msgstr ""
|
||||
|
||||
msgid "Merged MRs"
|
||||
msgstr ""
|
||||
|
||||
msgid "Merged branches are being deleted. This can take some time depending on the number of branches. Please refresh the page to see changes."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -29427,6 +29394,12 @@ msgstr ""
|
|||
msgid "Opened"
|
||||
msgstr ""
|
||||
|
||||
msgid "Opened MRs"
|
||||
msgstr ""
|
||||
|
||||
msgid "Opened issues"
|
||||
msgstr ""
|
||||
|
||||
msgid "OpenedNDaysAgo|Created"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -31937,9 +31910,6 @@ msgstr ""
|
|||
msgid "Preview"
|
||||
msgstr ""
|
||||
|
||||
msgid "Preview JavaScript projects in the Web IDE with CodeSandbox Live Preview. %{link_start}Learn more.%{link_end} "
|
||||
msgstr ""
|
||||
|
||||
msgid "Preview Markdown"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -34634,6 +34604,9 @@ msgstr ""
|
|||
msgid "PushRule|Reject unverified users"
|
||||
msgstr ""
|
||||
|
||||
msgid "Pushed"
|
||||
msgstr ""
|
||||
|
||||
msgid "Pushes"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -39957,6 +39930,9 @@ msgstr ""
|
|||
msgid "Something went wrong while fetching details"
|
||||
msgstr ""
|
||||
|
||||
msgid "Something went wrong while fetching group member contributions"
|
||||
msgstr ""
|
||||
|
||||
msgid "Something went wrong while fetching latest comments."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -44494,6 +44470,9 @@ msgstr ""
|
|||
msgid "Total"
|
||||
msgstr ""
|
||||
|
||||
msgid "Total Contributions"
|
||||
msgstr ""
|
||||
|
||||
msgid "Total Score"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -51,14 +51,13 @@
|
|||
"@apollo/client": "^3.5.10",
|
||||
"@babel/core": "^7.18.5",
|
||||
"@babel/preset-env": "^7.18.2",
|
||||
"@codesandbox/sandpack-client": "^1.2.2",
|
||||
"@cubejs-client/core": "^0.31.15",
|
||||
"@cubejs-client/vue": "^0.31.19",
|
||||
"@gitlab/at.js": "1.5.7",
|
||||
"@gitlab/favicon-overlay": "2.0.0",
|
||||
"@gitlab/fonts": "^1.2.0",
|
||||
"@gitlab/svgs": "3.18.0",
|
||||
"@gitlab/ui": "54.1.1",
|
||||
"@gitlab/ui": "54.1.2",
|
||||
"@gitlab/visual-review-tools": "1.7.3",
|
||||
"@gitlab/web-ide": "0.0.1-dev-20230120231236",
|
||||
"@rails/actioncable": "6.1.4-7",
|
||||
|
|
@ -109,7 +108,6 @@
|
|||
"cache-loader": "^4.1.0",
|
||||
"canvas-confetti": "^1.4.0",
|
||||
"clipboard": "^2.0.8",
|
||||
"codesandbox-api": "0.0.23",
|
||||
"compression-webpack-plugin": "^5.0.2",
|
||||
"copy-webpack-plugin": "^6.4.1",
|
||||
"core-js": "^3.27.2",
|
||||
|
|
@ -228,10 +226,10 @@
|
|||
"cheerio": "^1.0.0-rc.9",
|
||||
"commander": "^2.20.3",
|
||||
"custom-jquery-matchers": "^2.1.0",
|
||||
"eslint": "8.29.0",
|
||||
"eslint": "8.32.0",
|
||||
"eslint-import-resolver-jest": "3.0.2",
|
||||
"eslint-import-resolver-webpack": "0.13.2",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-no-jquery": "2.7.0",
|
||||
"eslint-plugin-no-unsanitized": "^4.0.2",
|
||||
"gettext-extractor": "^3.5.3",
|
||||
|
|
|
|||
|
|
@ -42,83 +42,6 @@ RSpec.describe Projects::ServicePingController do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'POST #web_ide_clientside_preview' do
|
||||
subject { post :web_ide_clientside_preview, params: { namespace_id: project.namespace, project_id: project } }
|
||||
|
||||
context 'when web ide clientside preview is enabled' do
|
||||
before do
|
||||
stub_application_setting(web_ide_clientside_preview_enabled: true)
|
||||
end
|
||||
|
||||
it_behaves_like 'counter is not increased'
|
||||
it_behaves_like 'counter is increased', 'WEB_IDE_PREVIEWS_COUNT'
|
||||
end
|
||||
|
||||
context 'when web ide clientside preview is not enabled' do
|
||||
let(:user) { project.first_owner }
|
||||
|
||||
before do
|
||||
stub_application_setting(web_ide_clientside_preview_enabled: false)
|
||||
end
|
||||
|
||||
it 'returns 404' do
|
||||
subject
|
||||
|
||||
expect(response).to have_gitlab_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #web_ide_clientside_preview_success' do
|
||||
subject { post :web_ide_clientside_preview_success, params: { namespace_id: project.namespace, project_id: project } }
|
||||
|
||||
context 'when web ide clientside preview is enabled' do
|
||||
before do
|
||||
stub_application_setting(web_ide_clientside_preview_enabled: true)
|
||||
end
|
||||
|
||||
it_behaves_like 'counter is not increased'
|
||||
it_behaves_like 'counter is increased', 'WEB_IDE_PREVIEWS_SUCCESS_COUNT'
|
||||
|
||||
context 'when the user has access to the project', :snowplow do
|
||||
let(:user) { project.owner }
|
||||
|
||||
it 'increases the live preview view counter' do
|
||||
expect(Gitlab::UsageDataCounters::EditorUniqueCounter).to receive(:track_live_preview_edit_action).with(author: user, project: project)
|
||||
|
||||
subject
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
end
|
||||
|
||||
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
|
||||
let(:project) { create(:project) }
|
||||
let(:namespace) { project.namespace }
|
||||
let(:category) { 'Gitlab::UsageDataCounters::EditorUniqueCounter' }
|
||||
let(:action) { 'ide_edit' }
|
||||
let(:property) { 'g_edit_by_live_preview' }
|
||||
let(:label) { 'usage_activity_by_stage_monthly.create.action_monthly_active_users_ide_edit' }
|
||||
let(:context) { [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: event_name).to_context] }
|
||||
let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when web ide clientside preview is not enabled' do
|
||||
let(:user) { project.owner }
|
||||
|
||||
before do
|
||||
stub_application_setting(web_ide_clientside_preview_enabled: false)
|
||||
end
|
||||
|
||||
it 'returns 404' do
|
||||
subject
|
||||
|
||||
expect(response).to have_gitlab_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #web_ide_pipelines_count' do
|
||||
subject { post :web_ide_pipelines_count, params: { namespace_id: project.namespace, project_id: project } }
|
||||
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ RSpec.describe SessionsController do
|
|||
expect(Gitlab::Metrics).to receive(:counter)
|
||||
.with(:successful_login_captcha_total, anything)
|
||||
.and_return(counter)
|
||||
expect(Gitlab::Metrics).to receive(:counter).and_call_original
|
||||
expect(Gitlab::Metrics).to receive(:counter).at_least(1).time.and_call_original
|
||||
|
||||
post(:create, params: { user: user_params }, session: sesion_params)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,31 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'IDE Clientside Preview CSP', feature_category: :web_ide do
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
shared_context 'disable feature' do
|
||||
before do
|
||||
stub_application_setting(web_ide_clientside_preview_enabled: false)
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'setting CSP', 'frame-src' do
|
||||
let(:allowlisted_url) { 'https://sandbox.gitlab-static.test' }
|
||||
let(:extended_controller_class) { IdeController }
|
||||
|
||||
subject do
|
||||
visit ide_path
|
||||
|
||||
response_headers['Content-Security-Policy']
|
||||
end
|
||||
|
||||
before do
|
||||
stub_application_setting(web_ide_clientside_preview_enabled: true)
|
||||
stub_application_setting(web_ide_clientside_preview_bundler_url: allowlisted_url)
|
||||
|
||||
sign_in(user)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -33,7 +33,6 @@ describe('Ci variable modal', () => {
|
|||
isProtectedByDefault: false,
|
||||
maskedEnvironmentVariablesLink: '/variables-link',
|
||||
maskableRegex,
|
||||
protectedEnvironmentVariablesLink: '/protected-link',
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
|
|
|
|||
|
|
@ -68,31 +68,6 @@ describe('ide/components/panes/right.vue', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('clientside live preview tab', () => {
|
||||
it('is shown if there is a packageJson and clientsidePreviewEnabled', () => {
|
||||
Vue.set(store.state.entries, 'package.json', {
|
||||
name: 'package.json',
|
||||
});
|
||||
store.state.clientsidePreviewEnabled = true;
|
||||
|
||||
createComponent();
|
||||
|
||||
expect(wrapper.findComponent(CollapsibleSidebar).props('extensionTabs')).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
show: true,
|
||||
title: 'Live preview',
|
||||
views: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
name: rightSidebarViews.clientSidePreview.name,
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
]),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('terminal tab', () => {
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
|
|
|
|||
|
|
@ -1,416 +0,0 @@
|
|||
import { GlLoadingIcon } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import { dispatch } from 'codesandbox-api';
|
||||
import { SandpackClient } from '@codesandbox/sandpack-client';
|
||||
import Vuex from 'vuex';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import Clientside from '~/ide/components/preview/clientside.vue';
|
||||
import { PING_USAGE_PREVIEW_KEY, PING_USAGE_PREVIEW_SUCCESS_KEY } from '~/ide/constants';
|
||||
import eventHub from '~/ide/eventhub';
|
||||
|
||||
jest.mock('@codesandbox/sandpack-client', () => ({
|
||||
SandpackClient: jest.fn(),
|
||||
}));
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
const dummyPackageJson = () => ({
|
||||
raw: JSON.stringify({
|
||||
main: 'index.js',
|
||||
}),
|
||||
});
|
||||
const expectedSandpackOptions = () => ({
|
||||
files: {},
|
||||
entry: '/index.js',
|
||||
showOpenInCodeSandbox: true,
|
||||
});
|
||||
const expectedSandpackSettings = () => ({
|
||||
fileResolver: {
|
||||
isFile: expect.any(Function),
|
||||
readFile: expect.any(Function),
|
||||
},
|
||||
});
|
||||
|
||||
describe('IDE clientside preview', () => {
|
||||
let wrapper;
|
||||
let store;
|
||||
const storeActions = {
|
||||
getFileData: jest.fn().mockReturnValue(Promise.resolve({})),
|
||||
getRawFileData: jest.fn().mockReturnValue(Promise.resolve('')),
|
||||
};
|
||||
const storeClientsideActions = {
|
||||
pingUsage: jest.fn().mockReturnValue(Promise.resolve({})),
|
||||
};
|
||||
const dispatchCodesandboxReady = () => dispatch({ type: 'done' });
|
||||
|
||||
const createComponent = ({ state, getters } = {}) => {
|
||||
store = new Vuex.Store({
|
||||
state: {
|
||||
entries: {},
|
||||
links: {},
|
||||
...state,
|
||||
},
|
||||
getters: {
|
||||
packageJson: () => '',
|
||||
currentProject: () => ({
|
||||
visibility: 'public',
|
||||
}),
|
||||
...getters,
|
||||
},
|
||||
actions: storeActions,
|
||||
modules: {
|
||||
clientside: {
|
||||
namespaced: true,
|
||||
actions: storeClientsideActions,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
wrapper = shallowMount(Clientside, {
|
||||
store,
|
||||
});
|
||||
};
|
||||
|
||||
const createInitializedComponent = () => {
|
||||
createComponent();
|
||||
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
wrapper.setData({
|
||||
sandpackReady: true,
|
||||
client: {
|
||||
cleanup: jest.fn(),
|
||||
updatePreview: jest.fn(),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
describe('without main entry', () => {
|
||||
it('creates sandpack client', () => {
|
||||
createComponent();
|
||||
expect(SandpackClient).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
describe('with main entry', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({ getters: { packageJson: dummyPackageJson } });
|
||||
|
||||
return waitForPromises();
|
||||
});
|
||||
|
||||
it('creates sandpack client', () => {
|
||||
expect(SandpackClient).toHaveBeenCalledWith(
|
||||
'#ide-preview',
|
||||
expectedSandpackOptions(),
|
||||
expectedSandpackSettings(),
|
||||
);
|
||||
});
|
||||
|
||||
it('pings usage', () => {
|
||||
expect(storeClientsideActions.pingUsage).toHaveBeenCalledTimes(1);
|
||||
expect(storeClientsideActions.pingUsage).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
PING_USAGE_PREVIEW_KEY,
|
||||
);
|
||||
});
|
||||
|
||||
it('pings usage success', async () => {
|
||||
dispatchCodesandboxReady();
|
||||
await nextTick();
|
||||
expect(storeClientsideActions.pingUsage).toHaveBeenCalledTimes(2);
|
||||
expect(storeClientsideActions.pingUsage).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
PING_USAGE_PREVIEW_SUCCESS_KEY,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with codesandboxBundlerUrl', () => {
|
||||
const TEST_BUNDLER_URL = 'https://test.gitlab-static.test';
|
||||
|
||||
beforeEach(() => {
|
||||
createComponent({
|
||||
getters: { packageJson: dummyPackageJson },
|
||||
state: { codesandboxBundlerUrl: TEST_BUNDLER_URL },
|
||||
});
|
||||
|
||||
return waitForPromises();
|
||||
});
|
||||
|
||||
it('creates sandpack client with bundlerURL', () => {
|
||||
expect(SandpackClient).toHaveBeenCalledWith('#ide-preview', expectedSandpackOptions(), {
|
||||
...expectedSandpackSettings(),
|
||||
bundlerURL: TEST_BUNDLER_URL,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with codesandboxBundlerURL', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({ getters: { packageJson: dummyPackageJson } });
|
||||
|
||||
return waitForPromises();
|
||||
});
|
||||
|
||||
it('creates sandpack client', () => {
|
||||
expect(SandpackClient).toHaveBeenCalledWith(
|
||||
'#ide-preview',
|
||||
{
|
||||
files: {},
|
||||
entry: '/index.js',
|
||||
showOpenInCodeSandbox: true,
|
||||
},
|
||||
{
|
||||
fileResolver: {
|
||||
isFile: expect.any(Function),
|
||||
readFile: expect.any(Function),
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('computed', () => {
|
||||
describe('normalizedEntries', () => {
|
||||
it('returns flattened list of blobs with content', () => {
|
||||
createComponent({
|
||||
state: {
|
||||
entries: {
|
||||
'index.js': { type: 'blob', raw: 'test' },
|
||||
'index2.js': { type: 'blob', content: 'content' },
|
||||
tree: { type: 'tree' },
|
||||
empty: { type: 'blob' },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.vm.normalizedEntries).toEqual({
|
||||
'/index.js': {
|
||||
code: 'test',
|
||||
},
|
||||
'/index2.js': {
|
||||
code: 'content',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('mainEntry', () => {
|
||||
it('returns false when package.json is empty', () => {
|
||||
createComponent();
|
||||
expect(wrapper.vm.mainEntry).toBe(false);
|
||||
});
|
||||
|
||||
it('returns main key from package.json', () => {
|
||||
createComponent({ getters: { packageJson: dummyPackageJson } });
|
||||
expect(wrapper.vm.mainEntry).toBe('index.js');
|
||||
});
|
||||
});
|
||||
|
||||
describe('showPreview', () => {
|
||||
it('returns false if no mainEntry', () => {
|
||||
createComponent();
|
||||
expect(wrapper.vm.showPreview).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false if loading and mainEntry exists', () => {
|
||||
createComponent({ getters: { packageJson: dummyPackageJson } });
|
||||
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
wrapper.setData({ loading: true });
|
||||
|
||||
expect(wrapper.vm.showPreview).toBe(false);
|
||||
});
|
||||
|
||||
it('returns true if not loading and mainEntry exists', () => {
|
||||
createComponent({ getters: { packageJson: dummyPackageJson } });
|
||||
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
wrapper.setData({ loading: false });
|
||||
|
||||
expect(wrapper.vm.showPreview).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('showEmptyState', () => {
|
||||
it('returns true if no mainEntry exists', () => {
|
||||
createComponent();
|
||||
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
wrapper.setData({ loading: false });
|
||||
expect(wrapper.vm.showEmptyState).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false if loading', () => {
|
||||
createComponent();
|
||||
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
wrapper.setData({ loading: true });
|
||||
|
||||
expect(wrapper.vm.showEmptyState).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false if not loading and mainEntry exists', () => {
|
||||
createComponent({ getters: { packageJson: dummyPackageJson } });
|
||||
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
wrapper.setData({ loading: false });
|
||||
|
||||
expect(wrapper.vm.showEmptyState).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('showOpenInCodeSandbox', () => {
|
||||
it('returns true when visibility is public', () => {
|
||||
createComponent({ getters: { currentProject: () => ({ visibility: 'public' }) } });
|
||||
|
||||
expect(wrapper.vm.showOpenInCodeSandbox).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false when visibility is private', () => {
|
||||
createComponent({ getters: { currentProject: () => ({ visibility: 'private' }) } });
|
||||
|
||||
expect(wrapper.vm.showOpenInCodeSandbox).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('sandboxOpts', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({
|
||||
state: {
|
||||
entries: {
|
||||
'index.js': { type: 'blob', raw: 'test' },
|
||||
'package.json': dummyPackageJson(),
|
||||
},
|
||||
},
|
||||
getters: {
|
||||
packageJson: dummyPackageJson,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('returns sandbox options', () => {
|
||||
expect(wrapper.vm.sandboxOpts).toEqual({
|
||||
files: {
|
||||
'/index.js': {
|
||||
code: 'test',
|
||||
},
|
||||
'/package.json': {
|
||||
code: '{"main":"index.js"}',
|
||||
},
|
||||
},
|
||||
entry: '/index.js',
|
||||
showOpenInCodeSandbox: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('methods', () => {
|
||||
describe('loadFileContent', () => {
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
return wrapper.vm.loadFileContent('package.json');
|
||||
});
|
||||
|
||||
it('calls getFileData', () => {
|
||||
expect(storeActions.getFileData).toHaveBeenCalledWith(expect.any(Object), {
|
||||
path: 'package.json',
|
||||
makeFileActive: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('calls getRawFileData', () => {
|
||||
expect(storeActions.getRawFileData).toHaveBeenCalledWith(expect.any(Object), {
|
||||
path: 'package.json',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('update', () => {
|
||||
it('initializes client if client is empty', () => {
|
||||
createComponent({ getters: { packageJson: dummyPackageJson } });
|
||||
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
wrapper.setData({ sandpackReady: true });
|
||||
wrapper.vm.update();
|
||||
|
||||
return waitForPromises().then(() => {
|
||||
expect(SandpackClient).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('calls updatePreview', () => {
|
||||
createInitializedComponent();
|
||||
|
||||
wrapper.vm.update();
|
||||
|
||||
expect(wrapper.vm.client.updatePreview).toHaveBeenCalledWith(wrapper.vm.sandboxOpts);
|
||||
});
|
||||
});
|
||||
|
||||
describe('on ide.files.change event', () => {
|
||||
beforeEach(() => {
|
||||
createInitializedComponent();
|
||||
|
||||
eventHub.$emit('ide.files.change');
|
||||
});
|
||||
|
||||
it('calls updatePreview', () => {
|
||||
expect(wrapper.vm.client.updatePreview).toHaveBeenCalledWith(wrapper.vm.sandboxOpts);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('template', () => {
|
||||
it('renders ide-preview element when showPreview is true', async () => {
|
||||
createComponent({ getters: { packageJson: dummyPackageJson } });
|
||||
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
wrapper.setData({ loading: false });
|
||||
|
||||
await nextTick();
|
||||
expect(wrapper.find('#ide-preview').exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('renders empty state', async () => {
|
||||
createComponent();
|
||||
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
wrapper.setData({ loading: false });
|
||||
|
||||
await nextTick();
|
||||
expect(wrapper.text()).toContain(
|
||||
'Preview your web application using Web IDE client-side evaluation.',
|
||||
);
|
||||
});
|
||||
|
||||
it('renders loading icon', async () => {
|
||||
createComponent();
|
||||
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
wrapper.setData({ loading: true });
|
||||
|
||||
await nextTick();
|
||||
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when destroyed', () => {
|
||||
let spy;
|
||||
|
||||
beforeEach(() => {
|
||||
createInitializedComponent();
|
||||
spy = wrapper.vm.client.updatePreview;
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
it('does not call updatePreview', () => {
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,161 +0,0 @@
|
|||
import { GlLoadingIcon } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import { listen } from 'codesandbox-api';
|
||||
import { nextTick } from 'vue';
|
||||
import { TEST_HOST } from 'helpers/test_constants';
|
||||
import ClientsideNavigator from '~/ide/components/preview/navigator.vue';
|
||||
|
||||
jest.mock('codesandbox-api', () => ({
|
||||
listen: jest.fn().mockReturnValue(jest.fn()),
|
||||
}));
|
||||
|
||||
describe('IDE clientside preview navigator', () => {
|
||||
let wrapper;
|
||||
let client;
|
||||
let listenHandler;
|
||||
|
||||
const findBackButton = () => wrapper.findAll('button').at(0);
|
||||
const findForwardButton = () => wrapper.findAll('button').at(1);
|
||||
const findRefreshButton = () => wrapper.findAll('button').at(2);
|
||||
|
||||
beforeEach(() => {
|
||||
listen.mockClear();
|
||||
client = { bundlerURL: TEST_HOST, iframe: { src: '' } };
|
||||
|
||||
wrapper = shallowMount(ClientsideNavigator, { propsData: { client } });
|
||||
[[listenHandler]] = listen.mock.calls;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
it('renders readonly URL bar', async () => {
|
||||
listenHandler({ type: 'urlchange', url: client.bundlerURL });
|
||||
await nextTick();
|
||||
expect(wrapper.find('input[readonly]').element.value).toBe('/');
|
||||
});
|
||||
|
||||
it('renders loading icon by default', () => {
|
||||
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('removes loading icon when done event is fired', async () => {
|
||||
listenHandler({ type: 'done' });
|
||||
await nextTick();
|
||||
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('does not count visiting same url multiple times', async () => {
|
||||
listenHandler({ type: 'done' });
|
||||
listenHandler({ type: 'done', url: `${TEST_HOST}/url1` });
|
||||
listenHandler({ type: 'done', url: `${TEST_HOST}/url1` });
|
||||
await nextTick();
|
||||
expect(findBackButton().attributes('disabled')).toBe('disabled');
|
||||
});
|
||||
|
||||
it('unsubscribes from listen on destroy', () => {
|
||||
const unsubscribeFn = listen();
|
||||
|
||||
wrapper.destroy();
|
||||
expect(unsubscribeFn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('back button', () => {
|
||||
beforeEach(async () => {
|
||||
listenHandler({ type: 'done' });
|
||||
listenHandler({ type: 'urlchange', url: TEST_HOST });
|
||||
await nextTick();
|
||||
});
|
||||
|
||||
it('is disabled by default', () => {
|
||||
expect(findBackButton().attributes('disabled')).toBe('disabled');
|
||||
});
|
||||
|
||||
it('is enabled when there is previous entry', async () => {
|
||||
listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url1` });
|
||||
await nextTick();
|
||||
findBackButton().trigger('click');
|
||||
expect(findBackButton().attributes()).not.toHaveProperty('disabled');
|
||||
});
|
||||
|
||||
it('is disabled when there is no previous entry', async () => {
|
||||
listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url1` });
|
||||
|
||||
await nextTick();
|
||||
findBackButton().trigger('click');
|
||||
|
||||
await nextTick();
|
||||
expect(findBackButton().attributes('disabled')).toBe('disabled');
|
||||
});
|
||||
|
||||
it('updates client iframe src', async () => {
|
||||
listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url1` });
|
||||
listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url2` });
|
||||
await nextTick();
|
||||
findBackButton().trigger('click');
|
||||
|
||||
expect(client.iframe.src).toBe(`${TEST_HOST}/url1`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('forward button', () => {
|
||||
beforeEach(async () => {
|
||||
listenHandler({ type: 'done' });
|
||||
listenHandler({ type: 'urlchange', url: TEST_HOST });
|
||||
await nextTick();
|
||||
});
|
||||
|
||||
it('is disabled by default', () => {
|
||||
expect(findForwardButton().attributes('disabled')).toBe('disabled');
|
||||
});
|
||||
|
||||
it('is enabled when there is next entry', async () => {
|
||||
listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url1` });
|
||||
|
||||
await nextTick();
|
||||
findBackButton().trigger('click');
|
||||
|
||||
await nextTick();
|
||||
expect(findForwardButton().attributes()).not.toHaveProperty('disabled');
|
||||
});
|
||||
|
||||
it('is disabled when there is no next entry', async () => {
|
||||
listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url1` });
|
||||
|
||||
await nextTick();
|
||||
findBackButton().trigger('click');
|
||||
|
||||
await nextTick();
|
||||
findForwardButton().trigger('click');
|
||||
|
||||
await nextTick();
|
||||
expect(findForwardButton().attributes('disabled')).toBe('disabled');
|
||||
});
|
||||
|
||||
it('updates client iframe src', async () => {
|
||||
listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url1` });
|
||||
listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url2` });
|
||||
await nextTick();
|
||||
findBackButton().trigger('click');
|
||||
|
||||
expect(client.iframe.src).toBe(`${TEST_HOST}/url1`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('refresh button', () => {
|
||||
const url = `${TEST_HOST}/some_url`;
|
||||
beforeEach(async () => {
|
||||
listenHandler({ type: 'done' });
|
||||
listenHandler({ type: 'urlchange', url });
|
||||
await nextTick();
|
||||
});
|
||||
|
||||
it('calls refresh with current path', () => {
|
||||
client.iframe.src = 'something-other';
|
||||
findRefreshButton().trigger('click');
|
||||
|
||||
expect(client.iframe.src).toBe(url);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -294,18 +294,6 @@ describe('IDE store getters', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('packageJson', () => {
|
||||
it('returns package.json entry', () => {
|
||||
localState.entries['package.json'] = {
|
||||
name: 'package.json',
|
||||
};
|
||||
|
||||
expect(getters.packageJson(localState)).toEqual({
|
||||
name: 'package.json',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('canPushToBranch', () => {
|
||||
it.each`
|
||||
currentBranch | canPushCode | expectedValue
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { TEST_HOST } from 'helpers/test_constants';
|
||||
import testAction from 'helpers/vuex_action_helper';
|
||||
import { PING_USAGE_PREVIEW_KEY } from '~/ide/constants';
|
||||
import * as actions from '~/ide/stores/modules/clientside/actions';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
|
||||
const TEST_PROJECT_URL = `${TEST_HOST}/lorem/ipsum`;
|
||||
const TEST_USAGE_URL = `${TEST_PROJECT_URL}/service_ping/${PING_USAGE_PREVIEW_KEY}`;
|
||||
|
||||
describe('IDE store module clientside actions', () => {
|
||||
let rootGetters;
|
||||
let mock;
|
||||
|
||||
beforeEach(() => {
|
||||
rootGetters = {
|
||||
currentProject: {
|
||||
web_url: TEST_PROJECT_URL,
|
||||
},
|
||||
};
|
||||
mock = new MockAdapter(axios);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mock.restore();
|
||||
});
|
||||
|
||||
describe('pingUsage', () => {
|
||||
it('posts to usage endpoint', async () => {
|
||||
const usageSpy = jest.fn(() => [200]);
|
||||
|
||||
mock.onPost(TEST_USAGE_URL).reply(() => usageSpy());
|
||||
|
||||
await testAction(actions.pingUsage, PING_USAGE_PREVIEW_KEY, rootGetters, [], []);
|
||||
expect(usageSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -82,10 +82,6 @@ describe('date_format_utility.js', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('defaults to 00:00 if no time is provided', () => {
|
||||
expect(utils.dateAndTimeToISOString(new Date('2021-08-21'))).toBe('2021-08-21T00:00:00.000Z');
|
||||
});
|
||||
|
||||
it('throws if date in invalid', () => {
|
||||
expect(() => utils.dateAndTimeToISOString('Invalid date', '10:00')).toThrow(
|
||||
'Argument should be a Date instance',
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue