Commit 843467b8 authored by Phil Hughes's avatar Phil Hughes

Added file templates to the Web IDE

Closes #47947
parent c380d3ac
<script>
import { mapActions, mapGetters, mapState } from 'vuex';
import Dropdown from './dropdown.vue';
export default {
components: {
Dropdown,
},
computed: {
...mapGetters(['activeFile']),
...mapGetters('fileTemplates', ['templateTypes']),
...mapState('fileTemplates', ['selectedTemplateType', 'updateSuccess']),
showTemplatesDropdown() {
return Object.keys(this.selectedTemplateType).length > 0;
},
},
watch: {
activeFile: {
handler: 'setInitialType',
},
},
mounted() {
this.setInitialType();
},
methods: {
...mapActions('fileTemplates', ['setTemplateType', 'fetchTemplate']),
setInitialType() {
const type = this.templateTypes.find(t => t.name === this.activeFile.name);
if (type) {
this.setTemplateType(type);
}
},
selectTemplateType(type) {
this.setTemplateType(type);
},
selecteTemplate(template) {
this.fetchTemplate(template);
},
},
};
</script>
<template>
<div class="d-flex align-items-center ide-file-templates">
<strong class="mr-2">
{{ __('File templates') }}
</strong>
<dropdown
:data="templateTypes"
:label="selectedTemplateType.name || __('Choose a type...')"
class="mr-2"
@click="selectTemplateType"
/>
<dropdown
v-if="showTemplatesDropdown"
:label="__('Choose a type...')"
:async="true"
:searchable="true"
:title="__('File templates')"
class="mr-2"
@click="selecteTemplate"
/>
<transition name="fade">
<div v-show="updateSuccess">
<strong class="text-success mr-2">
{{ __('Template applied') }}
</strong>
<button
type="button"
class="btn btn-default"
>
{{ __('Undo') }}
</button>
</div>
</transition>
</div>
</template>
<style>
.ide-file-templates {
padding: 8px 16px;
background-color: #fafafa;
border-bottom: 1px solid #eaeaea;
}
.ide-file-templates .dropdown {
min-width: 180px;
}
</style>
<script>
import $ from 'jquery';
import { mapActions, mapState } from 'vuex';
import LoadingIcon from '~/vue_shared/components/loading_icon.vue';
import DropdownButton from '~/vue_shared/components/dropdown/dropdown_button.vue';
export default {
components: {
DropdownButton,
LoadingIcon,
},
props: {
data: {
type: Array,
required: false,
default: () => [],
},
label: {
type: String,
required: true,
},
title: {
type: String,
required: false,
default: null,
},
async: {
type: Boolean,
required: false,
default: false,
},
searchable: {
type: Boolean,
required: false,
default: false,
},
},
data() {
return {
search: '',
};
},
computed: {
...mapState('fileTemplates', ['templates', 'isLoading']),
outputData() {
return (this.async ? this.templates : this.data).filter(t => {
if (!this.searchable) return true;
return t.name.toLowerCase().indexOf(this.search.toLowerCase()) >= 0;
});
},
showLoading() {
return this.async ? this.isLoading : false;
},
},
mounted() {
$(this.$el).on('show.bs.dropdown', this.fetchTemplatesIfAsync);
},
beforeDestroy() {
$(this.$el).off('show.bs.dropdown', this.fetchTemplatesIfAsync);
},
methods: {
...mapActions('fileTemplates', ['fetchTemplateTypes']),
fetchTemplatesIfAsync() {
if (this.async) {
this.fetchTemplateTypes();
}
},
clickItem(item) {
this.$emit('click', item);
},
},
};
</script>
<template>
<div class="dropdown">
<dropdown-button
:toggle-text="label"
/>
<div class="dropdown-menu">
<div
v-if="title"
class="dropdown-title"
>
{{ title }}
</div>
<div
v-if="!showLoading && searchable"
class="dropdown-input"
>
<input
v-model="search"
:placeholder="__('Filter...')"
type="search"
class="dropdown-input-field"
/>
</div>
<div class="dropdown-content">
<loading-icon
v-if="showLoading"
size="2"
/>
<ul v-else>
<li
v-for="(item, index) in outputData"
:key="index"
>
<button
type="button"
@click="clickItem(item)"
>
{{ item.name }}
</button>
</li>
</ul>
</div>
</div>
</div>
</template>
...@@ -6,12 +6,14 @@ import DiffViewer from '~/vue_shared/components/diff_viewer/diff_viewer.vue'; ...@@ -6,12 +6,14 @@ import DiffViewer from '~/vue_shared/components/diff_viewer/diff_viewer.vue';
import { activityBarViews, viewerTypes } from '../constants'; import { activityBarViews, viewerTypes } from '../constants';
import Editor from '../lib/editor'; import Editor from '../lib/editor';
import ExternalLink from './external_link.vue'; import ExternalLink from './external_link.vue';
import FileTemplatesBar from './file_templates/bar.vue';
export default { export default {
components: { components: {
ContentViewer, ContentViewer,
DiffViewer, DiffViewer,
ExternalLink, ExternalLink,
FileTemplatesBar,
}, },
props: { props: {
file: { file: {
...@@ -34,6 +36,7 @@ export default { ...@@ -34,6 +36,7 @@ export default {
'isCommitModeActive', 'isCommitModeActive',
'isReviewModeActive', 'isReviewModeActive',
]), ]),
...mapGetters('fileTemplates', ['showFileTemplatesBar']),
shouldHideEditor() { shouldHideEditor() {
return this.file && this.file.binary && !this.file.content; return this.file && this.file.binary && !this.file.content;
}, },
...@@ -216,7 +219,7 @@ export default { ...@@ -216,7 +219,7 @@ export default {
id="ide" id="ide"
class="blob-viewer-container blob-editor-container" class="blob-viewer-container blob-editor-container"
> >
<div class="ide-mode-tabs clearfix" > <div class="ide-mode-tabs clearfix">
<ul <ul
v-if="!shouldHideEditor && isEditModeActive" v-if="!shouldHideEditor && isEditModeActive"
class="nav-links float-left" class="nav-links float-left"
...@@ -249,6 +252,9 @@ export default { ...@@ -249,6 +252,9 @@ export default {
:file="file" :file="file"
/> />
</div> </div>
<file-templates-bar
v-if="showFileTemplatesBar(file.name)"
/>
<div <div
v-show="!shouldHideEditor && file.viewMode ==='editor'" v-show="!shouldHideEditor && file.viewMode ==='editor'"
ref="editor" ref="editor"
......
...@@ -8,6 +8,7 @@ import commitModule from './modules/commit'; ...@@ -8,6 +8,7 @@ import commitModule from './modules/commit';
import pipelines from './modules/pipelines'; import pipelines from './modules/pipelines';
import mergeRequests from './modules/merge_requests'; import mergeRequests from './modules/merge_requests';
import branches from './modules/branches'; import branches from './modules/branches';
import fileTemplates from './modules/file_templates';
Vue.use(Vuex); Vue.use(Vuex);
...@@ -22,6 +23,7 @@ export const createStore = () => ...@@ -22,6 +23,7 @@ export const createStore = () =>
pipelines, pipelines,
mergeRequests, mergeRequests,
branches, branches,
fileTemplates,
}, },
}); });
......
---
title: Added file templates to the Web IDE
merge_request:
author:
type: added
...@@ -1167,6 +1167,9 @@ msgstr "" ...@@ -1167,6 +1167,9 @@ msgstr ""
msgid "Choose a branch/tag (e.g. %{master}) or enter a commit (e.g. %{sha}) to see what's changed or to create a merge request." msgid "Choose a branch/tag (e.g. %{master}) or enter a commit (e.g. %{sha}) to see what's changed or to create a merge request."
msgstr "" msgstr ""
msgid "Choose a type..."
msgstr ""
msgid "Choose any color." msgid "Choose any color."
msgstr "" msgstr ""
...@@ -2691,6 +2694,9 @@ msgstr "" ...@@ -2691,6 +2694,9 @@ msgstr ""
msgid "Fields on this page are now uneditable, you can configure" msgid "Fields on this page are now uneditable, you can configure"
msgstr "" msgstr ""
msgid "File templates"
msgstr ""
msgid "Files" msgid "Files"
msgstr "" msgstr ""
...@@ -2703,6 +2709,9 @@ msgstr "" ...@@ -2703,6 +2709,9 @@ msgstr ""
msgid "Filter by commit message" msgid "Filter by commit message"
msgstr "" msgstr ""
msgid "Filter..."
msgstr ""
msgid "Find by path" msgid "Find by path"
msgstr "" msgstr ""
...@@ -5595,6 +5604,9 @@ msgstr "" ...@@ -5595,6 +5604,9 @@ msgstr ""
msgid "Template" msgid "Template"
msgstr "" msgstr ""
msgid "Template applied"
msgstr ""
msgid "Terms of Service Agreement and Privacy Policy" msgid "Terms of Service Agreement and Privacy Policy"
msgstr "" msgstr ""
...@@ -6175,6 +6187,9 @@ msgstr "" ...@@ -6175,6 +6187,9 @@ msgstr ""
msgid "Unable to load the diff. %{button_try_again}" msgid "Unable to load the diff. %{button_try_again}"
msgstr "" msgstr ""
msgid "Undo"
msgstr ""
msgid "Unlock" msgid "Unlock"
msgstr "" msgstr ""
......
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