Commit 718f54e7 authored by Himanshu Kapoor's avatar Himanshu Kapoor Committed by Illya Klymov

Replace property file.eol with a util function

Moved to ide_status_list.vue, and eol is computed based on file's
contents.
parent 0eb4b6f3
<script>
import { mapGetters } from 'vuex';
import TerminalSyncStatusSafe from './terminal_sync/terminal_sync_status_safe.vue';
import { getFileEOL } from '../utils';
export default {
components: {
......@@ -8,6 +9,9 @@ export default {
},
computed: {
...mapGetters(['activeFile']),
activeFileEOL() {
return getFileEOL(this.activeFile.content);
},
},
};
</script>
......@@ -16,7 +20,7 @@ export default {
<div class="ide-status-list d-flex">
<template v-if="activeFile">
<div class="ide-status-file">{{ activeFile.name }}</div>
<div class="ide-status-file">{{ activeFile.eol }}</div>
<div class="ide-status-file">{{ activeFileEOL }}</div>
<div v-if="!activeFile.binary" class="ide-status-file">
{{ activeFile.editorRow }}:{{ activeFile.editorColumn }}
</div>
......
......@@ -35,7 +35,6 @@ export default {
name: `${this.path ? `${this.path}/` : ''}${name}`,
type: 'blob',
content,
base64: !isText,
binary: !isText,
rawPath: !isText ? target.result : '',
});
......
......@@ -83,10 +83,6 @@ export default {
active: this.isPreviewViewMode,
};
},
fileType() {
const info = viewerInformationForPath(this.file.path);
return (info && info.id) || '';
},
showEditor() {
return !this.shouldHideEditor && this.isEditorViewMode;
},
......@@ -99,6 +95,12 @@ export default {
currentBranchCommit() {
return this.currentBranch?.commit.id;
},
previewMode() {
return viewerInformationForPath(this.file.path);
},
fileType() {
return this.previewMode?.id || '';
},
},
watch: {
file(newVal, oldVal) {
......@@ -181,7 +183,6 @@ export default {
'setFileLanguage',
'setEditorPosition',
'setFileViewMode',
'setFileEOL',
'updateViewer',
'removePendingTab',
'triggerFilesChange',
......@@ -260,7 +261,6 @@ export default {
const monacoModel = model.getModel();
const content = monacoModel.getValue();
this.changeFileContent({ path: file.path, content });
this.setFileEOL({ eol: this.model.eol });
});
// Handle Cursor Position
......@@ -280,11 +280,6 @@ export default {
this.setFileLanguage({
fileLanguage: this.model.language,
});
// Get File eol
this.setFileEOL({
eol: this.model.eol,
});
},
refreshEditorDimensions() {
if (this.showEditor) {
......@@ -331,16 +326,15 @@ export default {
role="button"
@click.prevent="setFileViewMode({ file, viewMode: $options.FILE_VIEW_MODE_EDITOR })"
>
<template v-if="viewer === $options.viewerTypes.edit">{{ __('Edit') }}</template>
<template v-else>{{ __('Review') }}</template>
{{ __('Edit') }}
</a>
</li>
<li v-if="file.previewMode" :class="previewTabCSS">
<li v-if="previewMode" :class="previewTabCSS">
<a
href="javascript:void(0);"
role="button"
@click.prevent="setFileViewMode({ file, viewMode: $options.FILE_VIEW_MODE_PREVIEW })"
>{{ file.previewMode.previewTitle }}</a
>{{ previewMode.previewTitle }}</a
>
</li>
</ul>
......
......@@ -53,10 +53,6 @@ export default class Model {
return this.model.getModeId();
}
get eol() {
return this.model.getEOL() === '\n' ? 'LF' : 'CRLF';
}
get path() {
return this.file.key;
}
......
......@@ -19,7 +19,6 @@ export const decorateFiles = ({
branchId,
tempFile = false,
content = '',
base64 = false,
binary = false,
rawPath = '',
}) => {
......@@ -88,10 +87,8 @@ export const decorateFiles = ({
tempFile,
changed: tempFile,
content,
base64,
binary: (previewMode && previewMode.binary) || binary,
rawPath,
previewMode,
parentPath,
});
......
......@@ -29,7 +29,6 @@ export const createTempEntry = (
name,
type,
content = '',
base64 = false,
binary = false,
rawPath = '',
openFile = true,
......@@ -60,7 +59,6 @@ export const createTempEntry = (
type,
tempFile: true,
content,
base64,
binary,
rawPath,
});
......@@ -92,7 +90,6 @@ export const addTempImage = ({ dispatch, getters }, { name, rawPath = '' }) =>
name: getters.getAvailableFileName(name),
type: 'blob',
content: rawPath.split('base64,')[1],
base64: true,
binary: true,
rawPath,
openFile: false,
......
......@@ -169,12 +169,6 @@ export const setFileLanguage = ({ getters, commit }, { fileLanguage }) => {
}
};
export const setFileEOL = ({ getters, commit }, { eol }) => {
if (getters.activeFile) {
commit(types.SET_FILE_EOL, { file: getters.activeFile, eol });
}
};
export const setEditorPosition = ({ getters, commit }, { editorRow, editorColumn }) => {
if (getters.activeFile) {
commit(types.SET_FILE_POSITION, {
......
......@@ -40,7 +40,6 @@ export const UPDATE_FILE_CONTENT = 'UPDATE_FILE_CONTENT';
export const SET_FILE_LANGUAGE = 'SET_FILE_LANGUAGE';
export const SET_FILE_POSITION = 'SET_FILE_POSITION';
export const SET_FILE_VIEWMODE = 'SET_FILE_VIEWMODE';
export const SET_FILE_EOL = 'SET_FILE_EOL';
export const DISCARD_FILE_CHANGES = 'DISCARD_FILE_CHANGES';
export const ADD_FILE_TO_CHANGED = 'ADD_FILE_TO_CHANGED';
export const REMOVE_FILE_FROM_CHANGED = 'REMOVE_FILE_FROM_CHANGED';
......
......@@ -99,11 +99,6 @@ export default {
fileLanguage,
});
},
[types.SET_FILE_EOL](state, { file, eol }) {
Object.assign(state.entries[file.path], {
eol,
});
},
[types.SET_FILE_POSITION](state, { file, editorRow, editorColumn }) {
Object.assign(state.entries[file.path], {
editorRow,
......
import { commitActionTypes, FILE_VIEW_MODE_EDITOR } from '../constants';
import { relativePathToAbsolute, isAbsolute, isRootRelative } from '~/lib/utils/url_utility';
import {
relativePathToAbsolute,
isAbsolute,
isRootRelative,
isBase64DataUrl,
} from '~/lib/utils/url_utility';
export const dataStructure = () => ({
id: '',
......@@ -31,13 +36,10 @@ export const dataStructure = () => ({
binary: false,
raw: '',
content: '',
base64: false,
editorRow: 1,
editorColumn: 1,
fileLanguage: '',
eol: '',
viewMode: FILE_VIEW_MODE_EDITOR,
previewMode: null,
size: 0,
parentPath: null,
lastOpenedAt: 0,
......@@ -60,10 +62,8 @@ export const decorateData = entity => {
active = false,
opened = false,
changed = false,
base64 = false,
binary = false,
rawPath = '',
previewMode,
file_lock,
parentPath = '',
} = entity;
......@@ -82,10 +82,8 @@ export const decorateData = entity => {
active,
changed,
content,
base64,
binary,
rawPath,
previewMode,
file_lock,
parentPath,
});
......@@ -136,7 +134,7 @@ export const createCommitPayload = ({
file_path: f.path,
previous_path: f.prevPath || undefined,
content: f.prevPath && !f.changed ? null : f.content || undefined,
encoding: f.base64 ? 'base64' : 'text',
encoding: isBase64DataUrl(f.rawPath) ? 'base64' : 'text',
last_commit_id: newBranch || f.deleted || f.prevPath ? undefined : f.lastCommitSha,
})),
start_sha: newBranch ? rootGetters.lastCommit.id : undefined,
......
......@@ -119,3 +119,7 @@ export function readFileAsDataURL(file) {
reader.readAsDataURL(file);
});
}
export function getFileEOL(content = '') {
return content.includes('\r\n') ? 'CRLF' : 'LF';
}
......@@ -243,6 +243,15 @@ export function isRootRelative(url) {
return /^\//.test(url);
}
/**
* Returns true if url is a base64 data URL
*
* @param {String} url
*/
export function isBase64DataUrl(url) {
return /^data:[.\w+-]+\/[.\w+-]+;base64,/.test(url);
}
/**
* Returns true if url is an absolute or root-relative URL
*
......
......@@ -5,10 +5,10 @@ import TerminalSyncStatusSafe from '~/ide/components/terminal_sync/terminal_sync
const TEST_FILE = {
name: 'lorem.md',
eol: 'LF',
editorRow: 3,
editorColumn: 23,
fileLanguage: 'markdown',
content: 'abc\nndef',
};
const localVue = createLocalVue();
......@@ -56,7 +56,8 @@ describe('ide/components/ide_status_list', () => {
});
it('shows file eol', () => {
expect(wrapper.text()).toContain(TEST_FILE.name);
expect(wrapper.text()).not.toContain('CRLF');
expect(wrapper.text()).toContain('LF');
});
it('shows file editor position', () => {
......
......@@ -85,7 +85,6 @@ describe('new dropdown upload', () => {
name: textFile.name,
type: 'blob',
content: 'plain text',
base64: false,
binary: false,
rawPath: '',
});
......@@ -103,7 +102,6 @@ describe('new dropdown upload', () => {
name: binaryFile.name,
type: 'blob',
content: binaryTarget.result.split('base64,')[1],
base64: true,
binary: true,
rawPath: binaryTarget.result,
});
......
......@@ -94,47 +94,24 @@ describe('RepoEditor', () => {
});
describe('when file is markdown', () => {
beforeEach(done => {
vm.file.previewMode = {
id: 'markdown',
previewTitle: 'Preview Markdown',
};
vm.$nextTick(done);
});
it('renders an Edit and a Preview Tab', done => {
Vue.nextTick(() => {
const tabs = vm.$el.querySelectorAll('.ide-mode-tabs .nav-links li');
expect(tabs.length).toBe(2);
expect(tabs[0].textContent.trim()).toBe('Edit');
expect(tabs[1].textContent.trim()).toBe('Preview Markdown');
done();
});
});
});
describe('when file is markdown and viewer mode is review', () => {
let mock;
beforeEach(done => {
beforeEach(() => {
mock = new MockAdapter(axios);
vm.file.projectId = 'namespace/project';
vm.file.previewMode = {
id: 'markdown',
previewTitle: 'Preview Markdown',
};
vm.file.content = 'testing 123';
vm.$store.state.viewer = 'diff';
mock.onPost(/(.*)\/preview_markdown/).reply(200, {
body: '<p>testing 123</p>',
});
vm.$nextTick(done);
Vue.set(vm, 'file', {
...vm.file,
projectId: 'namespace/project',
path: 'sample.md',
content: 'testing 123',
});
vm.$store.state.entries[vm.file.path] = vm.file;
return vm.$nextTick();
});
afterEach(() => {
......@@ -146,7 +123,7 @@ describe('RepoEditor', () => {
const tabs = vm.$el.querySelectorAll('.ide-mode-tabs .nav-links li');
expect(tabs.length).toBe(2);
expect(tabs[0].textContent.trim()).toBe('Review');
expect(tabs[0].textContent.trim()).toBe('Edit');
expect(tabs[1].textContent.trim()).toBe('Preview Markdown');
done();
......@@ -155,8 +132,6 @@ describe('RepoEditor', () => {
it('renders markdown for tempFile', done => {
vm.file.tempFile = true;
vm.file.path = `${vm.file.path}.md`;
vm.$store.state.entries[vm.file.path] = vm.file;
vm.$nextTick()
.then(() => {
......@@ -171,6 +146,20 @@ describe('RepoEditor', () => {
.then(done)
.catch(done.fail);
});
describe('when not in edit mode', () => {
beforeEach(async () => {
await vm.$nextTick();
vm.$store.state.currentActivityView = leftSidebarViews.review.name;
return vm.$nextTick();
});
it('shows no tabs', () => {
expect(vm.$el.querySelectorAll('.ide-mode-tabs .nav-links a')).toHaveLength(0);
});
});
});
describe('when open file is binary and not raw', () => {
......@@ -560,7 +549,6 @@ describe('RepoEditor', () => {
path: 'foo/foo.png',
type: 'blob',
content: 'Zm9v',
base64: true,
binary: true,
rawPath: 'data:image/png;base64,Zm9v',
});
......
......@@ -13,8 +13,8 @@ import { commitActionTypes, PERMISSION_CREATE_MR } from '~/ide/constants';
import testAction from '../../../../helpers/vuex_action_helper';
jest.mock('~/lib/utils/url_utility', () => ({
...jest.requireActual('~/lib/utils/url_utility'),
visitUrl: jest.fn(),
joinPaths: jest.requireActual('~/lib/utils/url_utility').joinPaths,
}));
const TEST_COMMIT_SHA = '123456789';
......
......@@ -46,7 +46,7 @@ describe('Multi-file store utils', () => {
path: 'added',
tempFile: true,
content: 'new file content',
base64: true,
rawPath: 'data:image/png;base64,abc',
lastCommitSha: '123456789',
},
{ ...file('deletedFile'), path: 'deletedFile', deleted: true },
......@@ -117,7 +117,7 @@ describe('Multi-file store utils', () => {
path: 'added',
tempFile: true,
content: 'new file content',
base64: true,
rawPath: 'data:image/png;base64,abc',
lastCommitSha: '123456789',
},
],
......
......@@ -371,6 +371,23 @@ describe('URL utility', () => {
});
});
describe('isBase64DataUrl', () => {
it.each`
url | valid
${undefined} | ${false}
${'http://gitlab.com'} | ${false}
${'data:image/png;base64,abcdef'} | ${true}
${'data:application/smil+xml;base64,abcdef'} | ${true}
${'data:application/vnd.syncml+xml;base64,abcdef'} | ${true}
${'data:application/vnd.3m.post-it-notes;base64,abcdef'} | ${true}
${'notaurl'} | ${false}
${'../relative_url'} | ${false}
${'<a></a>'} | ${false}
`('returns $valid for $url', ({ url, valid }) => {
expect(urlUtils.isBase64DataUrl(url)).toBe(valid);
});
});
describe('relativePathToAbsolute', () => {
it.each`
path | base | result
......
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