Commit 88836247 authored by Douglas Barbosa Alexandre's avatar Douglas Barbosa Alexandre

Merge branch '215975-remove-monaco-snippets-flag' into 'master'

Resolve "[:monaco_snippets] Enable Monaco as default editor for Snippets by default"

Closes #198608 and #215975

See merge request gitlab-org/gitlab!30892
parents 876c59cf e590578e
/* global ace */
import Editor from '~/editor/editor_lite';
export function initEditorLite({ el, blobPath, blobContent }) {
if (!el) {
throw new Error(`"el" parameter is required to initialize Editor`);
}
let editor;
if (window?.gon?.features?.monacoSnippets) {
editor = new Editor();
editor.createInstance({
el,
blobPath,
blobContent,
});
} else {
editor = ace.edit(el);
}
const editor = new Editor();
editor.createInstance({
el,
blobPath,
blobContent,
});
return editor;
}
......
......@@ -3,18 +3,6 @@ import setupCollapsibleInputs from './collapsible_input';
let editor;
const initAce = () => {
const editorEl = document.getElementById('editor');
const form = document.querySelector('.snippet-form-holder form');
const content = document.querySelector('.snippet-file-content');
editor = initEditorLite({ el: editorEl });
form.addEventListener('submit', () => {
content.value = editor.getValue();
});
};
const initMonaco = () => {
const editorEl = document.getElementById('editor');
const contentEl = document.querySelector('.snippet-file-content');
......@@ -36,15 +24,7 @@ const initMonaco = () => {
});
};
export const initEditor = () => {
if (window?.gon?.features?.monacoSnippets) {
initMonaco();
} else {
initAce();
}
setupCollapsibleInputs();
};
export default () => {
initEditor();
initMonaco();
setupCollapsibleInputs();
};
- if Feature.disabled?(:monaco_snippets)
- content_for :page_specific_javascripts do
= page_specific_javascript_tag('lib/ace.js')
- if Feature.enabled?(:snippets_edit_vue)
#js-snippet-edit.snippet-form{ data: {'project_path': @snippet.project&.full_path, 'snippet-gid': @snippet.new_record? ? '' : @snippet.to_global_id, 'markdown-preview-path': preview_markdown_path(parent), 'markdown-docs-path': help_page_path('user/markdown'), 'visibility-help-link': help_page_path("public_access/public_access") } }
- else
......
---
title: Enable Monaco for editing Snippets by default
merge_request: 30892
author:
type: added
......@@ -43,7 +43,6 @@ module Gitlab
# Initialize gon.features with any flags that should be
# made globally available to the frontend
push_frontend_feature_flag(:snippets_vue, default_enabled: false)
push_frontend_feature_flag(:monaco_snippets, default_enabled: false)
push_frontend_feature_flag(:monaco_blobs, default_enabled: false)
push_frontend_feature_flag(:monaco_ci, default_enabled: false)
push_frontend_feature_flag(:snippets_edit_vue, default_enabled: false)
......
......@@ -5,7 +5,6 @@ require 'spec_helper'
shared_examples_for 'snippet editor' do
before do
stub_feature_flags(snippets_edit_vue: false)
stub_feature_flags(monaco_snippets: flag)
end
def description_field
......@@ -20,7 +19,7 @@ shared_examples_for 'snippet editor' do
fill_in 'project_snippet_description', with: 'My Snippet **Description**'
page.within('.file-editor') do
el = flag == true ? find('.inputarea') : find('.ace_text-input', visible: false)
el = find('.inputarea')
el.send_keys 'Hello World!'
end
end
......@@ -145,15 +144,5 @@ describe 'Projects > Snippets > Create Snippet', :js do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :public) }
context 'when using Monaco' do
it_behaves_like "snippet editor" do
let(:flag) { true }
end
end
context 'when using ACE' do
it_behaves_like "snippet editor" do
let(:flag) { false }
end
end
it_behaves_like "snippet editor"
end
......@@ -13,7 +13,6 @@ shared_examples_for 'snippet editor' do
stub_feature_flags(allow_possible_spam: false)
stub_feature_flags(snippets_vue: false)
stub_feature_flags(snippets_edit_vue: false)
stub_feature_flags(monaco_snippets: flag)
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
Gitlab::CurrentSettings.update!(
......@@ -35,7 +34,7 @@ shared_examples_for 'snippet editor' do
find('#personal_snippet_visibility_level_20').set(true)
page.within('.file-editor') do
el = flag == true ? find('.inputarea') : find('.ace_text-input', visible: false)
el = find('.inputarea')
el.send_keys 'Hello World!'
end
end
......@@ -126,15 +125,5 @@ end
describe 'User creates snippet', :js do
let_it_be(:user) { create(:user) }
context 'when using Monaco' do
it_behaves_like "snippet editor" do
let(:flag) { true }
end
end
context 'when using ACE' do
it_behaves_like "snippet editor" do
let(:flag) { false }
end
end
it_behaves_like "snippet editor"
end
......@@ -6,7 +6,6 @@ shared_examples_for 'snippet editor' do
before do
stub_feature_flags(snippets_vue: false)
stub_feature_flags(snippets_edit_vue: false)
stub_feature_flags(monaco_snippets: flag)
sign_in(user)
visit new_snippet_path
end
......@@ -23,7 +22,7 @@ shared_examples_for 'snippet editor' do
fill_in 'personal_snippet_description', with: 'My Snippet **Description**'
page.within('.file-editor') do
el = flag == true ? find('.inputarea') : find('.ace_text-input', visible: false)
el = find('.inputarea')
el.send_keys 'Hello World!'
end
end
......@@ -136,7 +135,7 @@ shared_examples_for 'snippet editor' do
fill_in 'personal_snippet_title', with: 'My Snippet Title'
page.within('.file-editor') do
find(:xpath, "//input[@id='personal_snippet_file_name']").set 'snippet+file+name'
el = flag == true ? find('.inputarea') : find('.ace_text-input', visible: false)
el = find('.inputarea')
el.send_keys 'Hello World!'
end
......@@ -154,15 +153,5 @@ describe 'User creates snippet', :js do
let_it_be(:user) { create(:user) }
context 'when using Monaco' do
it_behaves_like "snippet editor" do
let(:flag) { true }
end
end
context 'when using ACE' do
it_behaves_like "snippet editor" do
let(:flag) { false }
end
end
it_behaves_like "snippet editor"
end
......@@ -8,11 +8,6 @@ jest.mock('~/editor/editor_lite', () => {
});
});
const mockCreateAceInstance = jest.fn();
global.ace = {
edit: mockCreateAceInstance,
};
describe('Blob utilities', () => {
beforeEach(() => {
Editor.mockClear();
......@@ -29,21 +24,6 @@ describe('Blob utilities', () => {
});
describe('Monaco editor', () => {
let origProp;
beforeEach(() => {
origProp = window.gon;
window.gon = {
features: {
monacoSnippets: true,
},
};
});
afterEach(() => {
window.gon = origProp;
});
it('initializes the Editor Lite', () => {
utils.initEditorLite({ el: editorEl });
expect(Editor).toHaveBeenCalled();
......@@ -69,27 +49,5 @@ describe('Blob utilities', () => {
]);
});
});
describe('ACE editor', () => {
let origProp;
beforeEach(() => {
origProp = window.gon;
window.gon = {
features: {
monacoSnippets: false,
},
};
});
afterEach(() => {
window.gon = origProp;
});
it('does not initialize the Editor Lite', () => {
utils.initEditorLite({ el: editorEl });
expect(Editor).not.toHaveBeenCalled();
expect(mockCreateAceInstance).toHaveBeenCalledWith(editorEl);
});
});
});
});
import Editor from '~/editor/editor_lite';
import { initEditor } from '~/snippet/snippet_bundle';
import initEditor from '~/snippet/snippet_bundle';
import { setHTMLFixture } from 'helpers/fixtures';
jest.mock('~/editor/editor_lite', () => jest.fn());
describe('Snippet editor', () => {
describe('Monaco editor for Snippets', () => {
let oldGon;
let editorEl;
let contentEl;
let fileNameEl;
let form;
const mockName = 'foo.bar';
const mockContent = 'Foo Bar';
const updatedMockContent = 'New Foo Bar';
const mockEditor = {
createInstance: jest.fn(),
updateModelLanguage: jest.fn(),
getValue: jest.fn().mockReturnValueOnce(updatedMockContent),
};
Editor.mockImplementation(() => mockEditor);
function setUpFixture(name, content) {
setHTMLFixture(`
<div class="snippet-form-holder">
<form>
<input class="js-snippet-file-name" type="text" value="${name}">
<input class="snippet-file-content" type="hidden" value="${content}">
<pre id="editor"></pre>
</form>
</div>
`);
}
function bootstrap(name = '', content = '') {
setUpFixture(name, content);
editorEl = document.getElementById('editor');
contentEl = document.querySelector('.snippet-file-content');
fileNameEl = document.querySelector('.js-snippet-file-name');
form = document.querySelector('.snippet-form-holder form');
initEditor();
}
function createEvent(name) {
return new Event(name, {
view: window,
bubbles: true,
cancelable: true,
});
}
beforeEach(() => {
oldGon = window.gon;
window.gon = { features: { monacoSnippets: true } };
bootstrap(mockName, mockContent);
let editorEl;
let contentEl;
let fileNameEl;
let form;
const mockName = 'foo.bar';
const mockContent = 'Foo Bar';
const updatedMockContent = 'New Foo Bar';
const mockEditor = {
createInstance: jest.fn(),
updateModelLanguage: jest.fn(),
getValue: jest.fn().mockReturnValueOnce(updatedMockContent),
};
Editor.mockImplementation(() => mockEditor);
function setUpFixture(name, content) {
setHTMLFixture(`
<div class="snippet-form-holder">
<form>
<input class="js-snippet-file-name" type="text" value="${name}">
<input class="snippet-file-content" type="hidden" value="${content}">
<pre id="editor"></pre>
</form>
</div>
`);
}
function bootstrap(name = '', content = '') {
setUpFixture(name, content);
editorEl = document.getElementById('editor');
contentEl = document.querySelector('.snippet-file-content');
fileNameEl = document.querySelector('.js-snippet-file-name');
form = document.querySelector('.snippet-form-holder form');
initEditor();
}
function createEvent(name) {
return new Event(name, {
view: window,
bubbles: true,
cancelable: true,
});
}
afterEach(() => {
window.gon = oldGon;
});
beforeEach(() => {
bootstrap(mockName, mockContent);
});
it('correctly initializes Editor', () => {
expect(mockEditor.createInstance).toHaveBeenCalledWith({
el: editorEl,
blobPath: mockName,
blobContent: mockContent,
});
it('correctly initializes Editor', () => {
expect(mockEditor.createInstance).toHaveBeenCalledWith({
el: editorEl,
blobPath: mockName,
blobContent: mockContent,
});
});
it('listens to file name changes and updates syntax highlighting of code', () => {
expect(mockEditor.updateModelLanguage).not.toHaveBeenCalled();
it('listens to file name changes and updates syntax highlighting of code', () => {
expect(mockEditor.updateModelLanguage).not.toHaveBeenCalled();
const event = createEvent('change');
const event = createEvent('change');
fileNameEl.value = updatedMockContent;
fileNameEl.dispatchEvent(event);
fileNameEl.value = updatedMockContent;
fileNameEl.dispatchEvent(event);
expect(mockEditor.updateModelLanguage).toHaveBeenCalledWith(updatedMockContent);
});
expect(mockEditor.updateModelLanguage).toHaveBeenCalledWith(updatedMockContent);
});
it('listens to form submit event and populates the hidden field with most recent version of the content', () => {
expect(contentEl.value).toBe(mockContent);
it('listens to form submit event and populates the hidden field with most recent version of the content', () => {
expect(contentEl.value).toBe(mockContent);
const event = createEvent('submit');
const event = createEvent('submit');
form.dispatchEvent(event);
expect(contentEl.value).toBe(updatedMockContent);
});
form.dispatchEvent(event);
expect(contentEl.value).toBe(updatedMockContent);
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment