Skip to content

Commit

Permalink
Add latest changes from gitlab-org/gitlab@master
Browse files Browse the repository at this point in the history
  • Loading branch information
GitLab Bot committed Dec 6, 2021
1 parent 7c31b03 commit 5524283
Show file tree
Hide file tree
Showing 48 changed files with 1,198 additions and 817 deletions.
155 changes: 2 additions & 153 deletions app/assets/javascripts/editor/extensions/source_editor_markdown_ext.js
@@ -1,157 +1,6 @@
import { debounce } from 'lodash';
import { BLOB_PREVIEW_ERROR } from '~/blob_edit/constants';
import createFlash from '~/flash';
import { sanitize } from '~/lib/dompurify';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
import syntaxHighlight from '~/syntax_highlight';
import {
EXTENSION_MARKDOWN_PREVIEW_PANEL_CLASS,
EXTENSION_MARKDOWN_PREVIEW_ACTION_ID,
EXTENSION_MARKDOWN_PREVIEW_PANEL_WIDTH,
EXTENSION_MARKDOWN_PREVIEW_PANEL_PARENT_CLASS,
EXTENSION_MARKDOWN_PREVIEW_UPDATE_DELAY,
} from '../constants';
import { SourceEditorExtension } from './source_editor_extension_base';

const getPreview = (text, previewMarkdownPath) => {
return axios
.post(previewMarkdownPath, {
text,
})
.then(({ data }) => {
return data.body;
});
};

const setupDomElement = ({ injectToEl = null } = {}) => {
const previewEl = document.createElement('div');
previewEl.classList.add(EXTENSION_MARKDOWN_PREVIEW_PANEL_CLASS);
previewEl.style.display = 'none';
if (injectToEl) {
injectToEl.appendChild(previewEl);
}
return previewEl;
};

export class EditorMarkdownExtension extends SourceEditorExtension {
constructor({ instance, previewMarkdownPath, ...args } = {}) {
super({ instance, ...args });
Object.assign(instance, {
previewMarkdownPath,
preview: {
el: undefined,
action: undefined,
shown: false,
modelChangeListener: undefined,
},
});
this.setupPreviewAction.call(instance);

instance.getModel().onDidChangeLanguage(({ newLanguage, oldLanguage } = {}) => {
if (newLanguage === 'markdown' && oldLanguage !== newLanguage) {
instance.setupPreviewAction();
} else {
instance.cleanup();
}
});

instance.onDidChangeModel(() => {
const model = instance.getModel();
if (model) {
const { language } = model.getLanguageIdentifier();
instance.cleanup();
if (language === 'markdown') {
instance.setupPreviewAction();
}
}
});
}

static togglePreviewLayout() {
const { width, height } = this.getLayoutInfo();
const newWidth = this.preview.shown
? width / EXTENSION_MARKDOWN_PREVIEW_PANEL_WIDTH
: width * EXTENSION_MARKDOWN_PREVIEW_PANEL_WIDTH;
this.layout({ width: newWidth, height });
}

static togglePreviewPanel() {
const parentEl = this.getDomNode().parentElement;
const { el: previewEl } = this.preview;
parentEl.classList.toggle(EXTENSION_MARKDOWN_PREVIEW_PANEL_PARENT_CLASS);

if (previewEl.style.display === 'none') {
// Show the preview panel
this.fetchPreview();
} else {
// Hide the preview panel
previewEl.style.display = 'none';
}
}

cleanup() {
if (this.preview.modelChangeListener) {
this.preview.modelChangeListener.dispose();
}
this.preview.action.dispose();
if (this.preview.shown) {
EditorMarkdownExtension.togglePreviewPanel.call(this);
EditorMarkdownExtension.togglePreviewLayout.call(this);
}
this.preview.shown = false;
}

fetchPreview() {
const { el: previewEl } = this.preview;
getPreview(this.getValue(), this.previewMarkdownPath)
.then((data) => {
previewEl.innerHTML = sanitize(data);
syntaxHighlight(previewEl.querySelectorAll('.js-syntax-highlight'));
previewEl.style.display = 'block';
})
.catch(() => createFlash(BLOB_PREVIEW_ERROR));
}

setupPreviewAction() {
if (this.getAction(EXTENSION_MARKDOWN_PREVIEW_ACTION_ID)) return;

this.preview.action = this.addAction({
id: EXTENSION_MARKDOWN_PREVIEW_ACTION_ID,
label: __('Preview Markdown'),
keybindings: [
// eslint-disable-next-line no-bitwise,no-undef
monaco.KeyMod.chord(monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.KEY_P),
],
contextMenuGroupId: 'navigation',
contextMenuOrder: 1.5,

// Method that will be executed when the action is triggered.
// @param ed The editor instance is passed in as a convenience
run(instance) {
instance.togglePreview();
},
});
}

togglePreview() {
if (!this.preview?.el) {
this.preview.el = setupDomElement({ injectToEl: this.getDomNode().parentElement });
}
EditorMarkdownExtension.togglePreviewLayout.call(this);
EditorMarkdownExtension.togglePreviewPanel.call(this);

if (!this.preview?.shown) {
this.preview.modelChangeListener = this.onDidChangeModelContent(
debounce(this.fetchPreview.bind(this), EXTENSION_MARKDOWN_PREVIEW_UPDATE_DELAY),
);
} else {
this.preview.modelChangeListener.dispose();
}

this.preview.shown = !this.preview?.shown;
}
import { EditorMarkdownPreviewExtension } from '~/editor/extensions/source_editor_markdown_livepreview_ext';

export class EditorMarkdownExtension extends EditorMarkdownPreviewExtension {
getSelectedText(selection = this.getSelection()) {
const { startLineNumber, endLineNumber, startColumn, endColumn } = selection;
const valArray = this.getValue().split('\n');
Expand Down
@@ -0,0 +1,154 @@
import { debounce } from 'lodash';
import { BLOB_PREVIEW_ERROR } from '~/blob_edit/constants';
import createFlash from '~/flash';
import { sanitize } from '~/lib/dompurify';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
import syntaxHighlight from '~/syntax_highlight';
import {
EXTENSION_MARKDOWN_PREVIEW_PANEL_CLASS,
EXTENSION_MARKDOWN_PREVIEW_ACTION_ID,
EXTENSION_MARKDOWN_PREVIEW_PANEL_WIDTH,
EXTENSION_MARKDOWN_PREVIEW_PANEL_PARENT_CLASS,
EXTENSION_MARKDOWN_PREVIEW_UPDATE_DELAY,
} from '../constants';
import { SourceEditorExtension } from './source_editor_extension_base';

const getPreview = (text, previewMarkdownPath) => {
return axios
.post(previewMarkdownPath, {
text,
})
.then(({ data }) => {
return data.body;
});
};

const setupDomElement = ({ injectToEl = null } = {}) => {
const previewEl = document.createElement('div');
previewEl.classList.add(EXTENSION_MARKDOWN_PREVIEW_PANEL_CLASS);
previewEl.style.display = 'none';
if (injectToEl) {
injectToEl.appendChild(previewEl);
}
return previewEl;
};

export class EditorMarkdownPreviewExtension extends SourceEditorExtension {
constructor({ instance, previewMarkdownPath, ...args } = {}) {
super({ instance, ...args });
Object.assign(instance, {
previewMarkdownPath,
preview: {
el: undefined,
action: undefined,
shown: false,
modelChangeListener: undefined,
},
});
this.setupPreviewAction.call(instance);

instance.getModel().onDidChangeLanguage(({ newLanguage, oldLanguage } = {}) => {
if (newLanguage === 'markdown' && oldLanguage !== newLanguage) {
instance.setupPreviewAction();
} else {
instance.cleanup();
}
});

instance.onDidChangeModel(() => {
const model = instance.getModel();
if (model) {
const { language } = model.getLanguageIdentifier();
instance.cleanup();
if (language === 'markdown') {
instance.setupPreviewAction();
}
}
});
}

static togglePreviewLayout() {
const { width, height } = this.getLayoutInfo();
const newWidth = this.preview.shown
? width / EXTENSION_MARKDOWN_PREVIEW_PANEL_WIDTH
: width * EXTENSION_MARKDOWN_PREVIEW_PANEL_WIDTH;
this.layout({ width: newWidth, height });
}

static togglePreviewPanel() {
const parentEl = this.getDomNode().parentElement;
const { el: previewEl } = this.preview;
parentEl.classList.toggle(EXTENSION_MARKDOWN_PREVIEW_PANEL_PARENT_CLASS);

if (previewEl.style.display === 'none') {
// Show the preview panel
this.fetchPreview();
} else {
// Hide the preview panel
previewEl.style.display = 'none';
}
}

cleanup() {
if (this.preview.modelChangeListener) {
this.preview.modelChangeListener.dispose();
}
this.preview.action.dispose();
if (this.preview.shown) {
EditorMarkdownPreviewExtension.togglePreviewPanel.call(this);
EditorMarkdownPreviewExtension.togglePreviewLayout.call(this);
}
this.preview.shown = false;
}

fetchPreview() {
const { el: previewEl } = this.preview;
getPreview(this.getValue(), this.previewMarkdownPath)
.then((data) => {
previewEl.innerHTML = sanitize(data);
syntaxHighlight(previewEl.querySelectorAll('.js-syntax-highlight'));
previewEl.style.display = 'block';
})
.catch(() => createFlash(BLOB_PREVIEW_ERROR));
}

setupPreviewAction() {
if (this.getAction(EXTENSION_MARKDOWN_PREVIEW_ACTION_ID)) return;

this.preview.action = this.addAction({
id: EXTENSION_MARKDOWN_PREVIEW_ACTION_ID,
label: __('Preview Markdown'),
keybindings: [
// eslint-disable-next-line no-bitwise,no-undef
monaco.KeyMod.chord(monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.KEY_P),
],
contextMenuGroupId: 'navigation',
contextMenuOrder: 1.5,

// Method that will be executed when the action is triggered.
// @param ed The editor instance is passed in as a convenience
run(instance) {
instance.togglePreview();
},
});
}

togglePreview() {
if (!this.preview?.el) {
this.preview.el = setupDomElement({ injectToEl: this.getDomNode().parentElement });
}
EditorMarkdownPreviewExtension.togglePreviewLayout.call(this);
EditorMarkdownPreviewExtension.togglePreviewPanel.call(this);

if (!this.preview?.shown) {
this.preview.modelChangeListener = this.onDidChangeModelContent(
debounce(this.fetchPreview.bind(this), EXTENSION_MARKDOWN_PREVIEW_UPDATE_DELAY),
);
} else {
this.preview.modelChangeListener.dispose();
}

this.preview.shown = !this.preview?.shown;
}
}
Expand Up @@ -165,7 +165,7 @@ export default {
<div class="mr-widget-body media">
<status-icon :show-disabled-button="canUpdate" status="warning" />
<div class="media-body">
<div class="gl-ml-3 float-left">
<div class="float-left">
<span class="gl-font-weight-bold">
{{
__("Merge blocked: merge request must be marked as ready. It's still marked as draft.")
Expand Down
3 changes: 3 additions & 0 deletions app/assets/javascripts/vue_merge_request_widget/constants.js
Expand Up @@ -158,4 +158,7 @@ export const EXTENSION_ICON_CLASS = {
severityUnknown: 'gl-text-gray-400',
};

export const EXTENSION_SUMMARY_FAILED_CLASS = 'gl-text-red-500';
export const EXTENSION_SUMMARY_NEUTRAL_CLASS = 'gl-text-gray-700';

export { STATE_MACHINE };
1 change: 1 addition & 0 deletions app/assets/javascripts/vue_shared/components/file_row.vue
Expand Up @@ -146,6 +146,7 @@ export default {
ref="textOutput"
:style="levelIndentation"
class="file-row-name"
:title="file.name"
data-qa-selector="file_name_content"
:data-qa-file-name="file.name"
data-testid="file-row-name-container"
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/concerns/one_trust_csp.rb
Expand Up @@ -8,11 +8,11 @@ module OneTrustCSP
next unless helpers.one_trust_enabled? || policy.directives.present?

default_script_src = policy.directives['script-src'] || policy.directives['default-src']
script_src_values = Array.wrap(default_script_src) | ["'unsafe-eval'", 'https://cdn.cookielaw.org https://*.onetrust.com']
script_src_values = Array.wrap(default_script_src) | ["'unsafe-eval'", 'https://cdn.cookielaw.org', 'https://*.onetrust.com']
policy.script_src(*script_src_values)

default_connect_src = policy.directives['connect-src'] || policy.directives['default-src']
connect_src_values = Array.wrap(default_connect_src) | ['https://cdn.cookielaw.org']
connect_src_values = Array.wrap(default_connect_src) | ['https://cdn.cookielaw.org', 'https://*.onetrust.com']
policy.connect_src(*connect_src_values)
end
end
Expand Down
2 changes: 0 additions & 2 deletions app/controllers/invites_controller.rb
Expand Up @@ -79,8 +79,6 @@ def track_invite_join_click

if params[:experiment_name] == 'invite_email_preview_text'
experiment(:invite_email_preview_text, actor: member).track(:join_clicked)
elsif params[:experiment_name] == 'invite_email_from'
experiment(:invite_email_from, actor: member).track(:join_clicked)
end

Gitlab::Tracking.event(self.class.name, 'join_clicked', label: 'invite_email', property: member.id.to_s)
Expand Down
2 changes: 2 additions & 0 deletions app/controllers/projects/tree_controller.rb
Expand Up @@ -60,3 +60,5 @@ def assign_dir_vars
}
end
end

Projects::TreeController.prepend_mod
1 change: 0 additions & 1 deletion app/controllers/registrations_controller.rb
Expand Up @@ -212,7 +212,6 @@ def after_pending_invitations_hook

experiment_name = session.delete(:invite_email_experiment_name)
experiment(:invite_email_preview_text, actor: member).track(:accepted) if experiment_name == 'invite_email_preview_text'
experiment(:invite_email_from, actor: member).track(:accepted) if experiment_name == 'invite_email_from'
Gitlab::Tracking.event(self.class.name, 'accepted', label: 'invite_email', property: member.id.to_s)
end

Expand Down
9 changes: 1 addition & 8 deletions app/helpers/notify_helper.rb
Expand Up @@ -24,14 +24,7 @@ def invited_to_description(source)
def invited_join_url(token, member)
additional_params = { invite_type: Emails::Members::INITIAL_INVITE }

# order important below to our scheduled testing of these
# `from` experiment will be after the `text` on, but we may not cleanup
# from the `text` one by the time we run the `from` experiment,
# therefore we want to support `text` being fully enabled
# but if `from` is also enabled, then we only care about `from`
if experiment(:invite_email_from, actor: member).enabled?
additional_params[:experiment_name] = 'invite_email_from'
elsif experiment(:invite_email_preview_text, actor: member).enabled?
if experiment(:invite_email_preview_text, actor: member).enabled?
additional_params[:experiment_name] = 'invite_email_preview_text'
end

Expand Down

0 comments on commit 5524283

Please sign in to comment.