parent
c380d3aceb
commit
843467b8c4
6 changed files with 239 additions and 1 deletions
90
app/assets/javascripts/ide/components/file_templates/bar.vue
Normal file
90
app/assets/javascripts/ide/components/file_templates/bar.vue
Normal file
|
@ -0,0 +1,90 @@
|
|||
<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>
|
|
@ -0,0 +1,120 @@
|
|||
<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';
|
|||
import { activityBarViews, viewerTypes } from '../constants';
|
||||
import Editor from '../lib/editor';
|
||||
import ExternalLink from './external_link.vue';
|
||||
import FileTemplatesBar from './file_templates/bar.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ContentViewer,
|
||||
DiffViewer,
|
||||
ExternalLink,
|
||||
FileTemplatesBar,
|
||||
},
|
||||
props: {
|
||||
file: {
|
||||
|
@ -34,6 +36,7 @@ export default {
|
|||
'isCommitModeActive',
|
||||
'isReviewModeActive',
|
||||
]),
|
||||
...mapGetters('fileTemplates', ['showFileTemplatesBar']),
|
||||
shouldHideEditor() {
|
||||
return this.file && this.file.binary && !this.file.content;
|
||||
},
|
||||
|
@ -216,7 +219,7 @@ export default {
|
|||
id="ide"
|
||||
class="blob-viewer-container blob-editor-container"
|
||||
>
|
||||
<div class="ide-mode-tabs clearfix" >
|
||||
<div class="ide-mode-tabs clearfix">
|
||||
<ul
|
||||
v-if="!shouldHideEditor && isEditModeActive"
|
||||
class="nav-links float-left"
|
||||
|
@ -249,6 +252,9 @@ export default {
|
|||
:file="file"
|
||||
/>
|
||||
</div>
|
||||
<file-templates-bar
|
||||
v-if="showFileTemplatesBar(file.name)"
|
||||
/>
|
||||
<div
|
||||
v-show="!shouldHideEditor && file.viewMode ==='editor'"
|
||||
ref="editor"
|
||||
|
|
|
@ -8,6 +8,7 @@ import commitModule from './modules/commit';
|
|||
import pipelines from './modules/pipelines';
|
||||
import mergeRequests from './modules/merge_requests';
|
||||
import branches from './modules/branches';
|
||||
import fileTemplates from './modules/file_templates';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
|
@ -22,6 +23,7 @@ export const createStore = () =>
|
|||
pipelines,
|
||||
mergeRequests,
|
||||
branches,
|
||||
fileTemplates,
|
||||
},
|
||||
});
|
||||
|
||||
|
|
5
changelogs/unreleased/ide-file-templates.yml
Normal file
5
changelogs/unreleased/ide-file-templates.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Added file templates to the Web IDE
|
||||
merge_request:
|
||||
author:
|
||||
type: added
|
|
@ -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."
|
||||
msgstr ""
|
||||
|
||||
msgid "Choose a type..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Choose any color."
|
||||
msgstr ""
|
||||
|
||||
|
@ -2691,6 +2694,9 @@ msgstr ""
|
|||
msgid "Fields on this page are now uneditable, you can configure"
|
||||
msgstr ""
|
||||
|
||||
msgid "File templates"
|
||||
msgstr ""
|
||||
|
||||
msgid "Files"
|
||||
msgstr ""
|
||||
|
||||
|
@ -2703,6 +2709,9 @@ msgstr ""
|
|||
msgid "Filter by commit message"
|
||||
msgstr ""
|
||||
|
||||
msgid "Filter..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Find by path"
|
||||
msgstr ""
|
||||
|
||||
|
@ -5595,6 +5604,9 @@ msgstr ""
|
|||
msgid "Template"
|
||||
msgstr ""
|
||||
|
||||
msgid "Template applied"
|
||||
msgstr ""
|
||||
|
||||
msgid "Terms of Service Agreement and Privacy Policy"
|
||||
msgstr ""
|
||||
|
||||
|
@ -6175,6 +6187,9 @@ msgstr ""
|
|||
msgid "Unable to load the diff. %{button_try_again}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Undo"
|
||||
msgstr ""
|
||||
|
||||
msgid "Unlock"
|
||||
msgstr ""
|
||||
|
||||
|
|
Loading…
Reference in a new issue