diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-20 17:34:42 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-20 17:34:42 +0300 |
commit | 9f46488805e86b1bc341ea1620b866016c2ce5ed (patch) | |
tree | f9748c7e287041e37d6da49e0a29c9511dc34768 /app/assets/javascripts/ide | |
parent | dfc92d081ea0332d69c8aca2f0e745cb48ae5e6d (diff) |
Add latest changes from gitlab-org/gitlab@13-0-stable-ee
Diffstat (limited to 'app/assets/javascripts/ide')
40 files changed, 3024 insertions, 233 deletions
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/actions.vue b/app/assets/javascripts/ide/components/commit_sidebar/actions.vue index 6a8ea506d1b..6c563776533 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/actions.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/actions.vue @@ -1,5 +1,5 @@ <script> -import { escape as esc } from 'lodash'; +import { escape } from 'lodash'; import { mapState, mapGetters, createNamespacedHelpers } from 'vuex'; import { sprintf, s__ } from '~/locale'; import consts from '../../stores/modules/commit/constants'; @@ -22,7 +22,7 @@ export default { commitToCurrentBranchText() { return sprintf( s__('IDE|Commit to %{branchName} branch'), - { branchName: `<strong class="monospace">${esc(this.currentBranchId)}</strong>` }, + { branchName: `<strong class="monospace">${escape(this.currentBranchId)}</strong>` }, false, ); }, diff --git a/app/assets/javascripts/ide/components/commit_sidebar/editor_header.vue b/app/assets/javascripts/ide/components/commit_sidebar/editor_header.vue index e618fb3daae..24499fb9f6d 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/editor_header.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/editor_header.vue @@ -24,8 +24,8 @@ export default { discardModalTitle() { return sprintf(__('Discard changes to %{path}?'), { path: this.activeFile.path }); }, - isStaged() { - return !this.activeFile.changed && this.activeFile.staged; + canDiscard() { + return this.activeFile.changed || this.activeFile.staged; }, }, methods: { @@ -53,7 +53,7 @@ export default { <changed-file-icon :file="activeFile" :is-centered="false" /> <div class="ml-auto"> <button - v-if="!isStaged" + v-if="canDiscard" ref="discardButton" type="button" class="btn btn-remove btn-inverted append-right-8" diff --git a/app/assets/javascripts/ide/components/commit_sidebar/form.vue b/app/assets/javascripts/ide/components/commit_sidebar/form.vue index f6ca728defc..4cbd33e6ed6 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/form.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/form.vue @@ -1,11 +1,13 @@ <script> import { mapState, mapActions, mapGetters } from 'vuex'; import { n__, __ } from '~/locale'; +import { GlModal } from '@gitlab/ui'; import LoadingButton from '~/vue_shared/components/loading_button.vue'; import CommitMessageField from './message_field.vue'; import Actions from './actions.vue'; import SuccessMessage from './success_message.vue'; import { leftSidebarViews, MAX_WINDOW_HEIGHT_COMPACT } from '../../constants'; +import consts from '../../stores/modules/commit/constants'; export default { components: { @@ -13,6 +15,7 @@ export default { LoadingButton, CommitMessageField, SuccessMessage, + GlModal, }, data() { return { @@ -54,7 +57,20 @@ export default { }, methods: { ...mapActions(['updateActivityBarView']), - ...mapActions('commit', ['updateCommitMessage', 'discardDraft', 'commitChanges']), + ...mapActions('commit', [ + 'updateCommitMessage', + 'discardDraft', + 'commitChanges', + 'updateCommitAction', + ]), + commit() { + return this.commitChanges().catch(() => { + this.$refs.createBranchModal.show(); + }); + }, + forceCreateNewBranch() { + return this.updateCommitAction(consts.COMMIT_TO_NEW_BRANCH).then(() => this.commit()); + }, toggleIsCompact() { if (this.currentViewIsCommitView) { this.isCompact = !this.isCompact; @@ -119,13 +135,13 @@ export default { </button> <p class="text-center bold">{{ overviewText }}</p> </div> - <form v-if="!isCompact" ref="formEl" @submit.prevent.stop="commitChanges"> + <form v-if="!isCompact" ref="formEl" @submit.prevent.stop="commit"> <transition name="fade"> <success-message v-show="lastCommitMsg" /> </transition> <commit-message-field :text="commitMessage" :placeholder="preBuiltCommitMessage" @input="updateCommitMessage" - @submit="commitChanges" + @submit="commit" /> <div class="clearfix prepend-top-15"> <actions /> @@ -133,7 +149,7 @@ export default { :loading="submitCommitLoading" :label="commitButtonText" container-class="btn btn-success btn-sm float-left qa-commit-button" - @click="commitChanges" + @click="commit" /> <button v-if="!discardDraftButtonDisabled" @@ -152,6 +168,19 @@ export default { {{ __('Collapse') }} </button> </div> + <gl-modal + ref="createBranchModal" + modal-id="ide-create-branch-modal" + :ok-title="__('Create new branch')" + :title="__('Branch has changed')" + ok-variant="success" + @ok="forceCreateNewBranch" + > + {{ + __(`This branch has changed since you started editing. + Would you like to create a new branch?`) + }} + </gl-modal> </form> </transition> </div> diff --git a/app/assets/javascripts/ide/components/commit_sidebar/list.vue b/app/assets/javascripts/ide/components/commit_sidebar/list.vue index a15e22d4742..e6a1a1ba73c 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/list.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/list.vue @@ -1,9 +1,8 @@ <script> -import $ from 'jquery'; import { mapActions } from 'vuex'; import { __, sprintf } from '~/locale'; +import { GlModal } from '@gitlab/ui'; import Icon from '~/vue_shared/components/icon.vue'; -import DeprecatedModal2 from '~/vue_shared/components/deprecated_modal_2.vue'; import tooltip from '~/vue_shared/directives/tooltip'; import ListItem from './list_item.vue'; @@ -11,7 +10,7 @@ export default { components: { Icon, ListItem, - GlModal: DeprecatedModal2, + GlModal, }, directives: { tooltip, @@ -58,7 +57,7 @@ export default { methods: { ...mapActions(['stageAllChanges', 'unstageAllChanges', 'discardAllChanges']), openDiscardModal() { - $('#discard-all-changes').modal('show'); + this.$refs.discardAllModal.show(); }, unstageAndDiscardAllChanges() { this.unstageAllChanges(); @@ -114,11 +113,12 @@ export default { </p> <gl-modal v-if="!stagedList" - id="discard-all-changes" - :footer-primary-button-text="__('Discard all changes')" - :header-title-text="__('Discard all changes?')" - footer-primary-button-variant="danger" - @submit="unstageAndDiscardAllChanges" + ref="discardAllModal" + ok-variant="danger" + modal-id="discard-all-changes" + :ok-title="__('Discard all changes')" + :title="__('Discard all changes?')" + @ok="unstageAndDiscardAllChanges" > {{ $options.discardModalText }} </gl-modal> diff --git a/app/assets/javascripts/ide/components/ide.vue b/app/assets/javascripts/ide/components/ide.vue index 7ebcacc530f..36c8b18e205 100644 --- a/app/assets/javascripts/ide/components/ide.vue +++ b/app/assets/javascripts/ide/components/ide.vue @@ -3,6 +3,7 @@ import Vue from 'vue'; import { mapActions, mapGetters, mapState } from 'vuex'; import { GlDeprecatedButton, GlLoadingIcon } from '@gitlab/ui'; import { __ } from '~/locale'; +import { modalTypes } from '../constants'; import FindFile from '~/vue_shared/components/file_finder/index.vue'; import NewModal from './new_dropdown/modal.vue'; import IdeSidebar from './ide_side_bar.vue'; @@ -12,6 +13,7 @@ import RepoEditor from './repo_editor.vue'; import RightPane from './panes/right.vue'; import ErrorMessage from './error_message.vue'; import CommitEditorHeader from './commit_sidebar/editor_header.vue'; +import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; export default { components: { @@ -26,6 +28,7 @@ export default { GlDeprecatedButton, GlLoadingIcon, }, + mixins: [glFeatureFlagsMixin()], props: { rightPaneComponent: { type: Vue.Component, @@ -52,13 +55,20 @@ export default { 'allBlobs', 'emptyRepo', 'currentTree', + 'editorTheme', ]), + themeName() { + return window.gon?.user_color_scheme; + }, }, mounted() { window.onbeforeunload = e => this.onBeforeUnload(e); + + if (this.themeName) + document.querySelector('.navbar-gitlab').classList.add(`theme-${this.themeName}`); }, methods: { - ...mapActions(['toggleFileFinder', 'openNewEntryModal']), + ...mapActions(['toggleFileFinder']), onBeforeUnload(e = {}) { const returnValue = __('Are you sure you want to lose unsaved changes?'); @@ -72,12 +82,18 @@ export default { openFile(file) { this.$router.push(`/project${file.url}`); }, + createNewFile() { + this.$refs.newModal.open(modalTypes.blob); + }, }, }; </script> <template> - <article class="ide position-relative d-flex flex-column align-items-stretch"> + <article + class="ide position-relative d-flex flex-column align-items-stretch" + :class="{ [`theme-${themeName}`]: themeName }" + > <error-message v-if="errorMessage" :message="errorMessage" /> <div class="ide-view flex-grow d-flex"> <find-file @@ -125,7 +141,7 @@ export default { variant="success" :title="__('New file')" :aria-label="__('New file')" - @click="openNewEntryModal({ type: 'blob' })" + @click="createNewFile()" > {{ __('New file') }} </gl-deprecated-button> @@ -147,6 +163,6 @@ export default { <component :is="rightPaneComponent" v-if="currentProjectId" /> </div> <ide-status-bar /> - <new-modal /> + <new-modal ref="newModal" /> </article> </template> diff --git a/app/assets/javascripts/ide/components/ide_review.vue b/app/assets/javascripts/ide/components/ide_review.vue index 901b8892e80..62dbfea2088 100644 --- a/app/assets/javascripts/ide/components/ide_review.vue +++ b/app/assets/javascripts/ide/components/ide_review.vue @@ -43,7 +43,7 @@ export default { <template> <ide-tree-list :viewer-type="viewer" header-class="ide-review-header"> - <template slot="header"> + <template #header> <div class="ide-review-button-holder"> {{ __('Review') }} <editor-mode-dropdown diff --git a/app/assets/javascripts/ide/components/ide_side_bar.vue b/app/assets/javascripts/ide/components/ide_side_bar.vue index 40cd2178e09..7cb31df85ce 100644 --- a/app/assets/javascripts/ide/components/ide_side_bar.vue +++ b/app/assets/javascripts/ide/components/ide_side_bar.vue @@ -37,7 +37,7 @@ export default { </script> <template> - <resizable-panel :collapsible="false" :initial-width="340" side="left" class="flex-column"> + <resizable-panel :initial-width="340" side="left" class="flex-column"> <template v-if="loading"> <div class="multi-file-commit-panel-inner"> <div v-for="n in 3" :key="n" class="multi-file-loading-container"> diff --git a/app/assets/javascripts/ide/components/ide_tree.vue b/app/assets/javascripts/ide/components/ide_tree.vue index 598f3a1dac6..647f4d4be85 100644 --- a/app/assets/javascripts/ide/components/ide_tree.vue +++ b/app/assets/javascripts/ide/components/ide_tree.vue @@ -1,14 +1,17 @@ <script> import { mapState, mapGetters, mapActions } from 'vuex'; +import { modalTypes } from '../constants'; import IdeTreeList from './ide_tree_list.vue'; import Upload from './new_dropdown/upload.vue'; import NewEntryButton from './new_dropdown/button.vue'; +import NewModal from './new_dropdown/modal.vue'; export default { components: { Upload, IdeTreeList, NewEntryButton, + NewModal, }, computed: { ...mapState(['currentBranchId']), @@ -26,14 +29,20 @@ export default { } }, methods: { - ...mapActions(['updateViewer', 'openNewEntryModal', 'createTempEntry', 'resetOpenFiles']), + ...mapActions(['updateViewer', 'createTempEntry', 'resetOpenFiles']), + createNewFile() { + this.$refs.newModal.open(modalTypes.blob); + }, + createNewFolder() { + this.$refs.newModal.open(modalTypes.tree); + }, }, }; </script> <template> <ide-tree-list viewer-type="editor"> - <template slot="header"> + <template #header> {{ __('Edit') }} <div class="ide-tree-actions ml-auto d-flex"> <new-entry-button @@ -41,7 +50,7 @@ export default { :show-label="false" class="d-flex border-0 p-0 mr-3 qa-new-file" icon="doc-new" - @click="openNewEntryModal({ type: 'blob' })" + @click="createNewFile()" /> <upload :show-label="false" @@ -54,9 +63,10 @@ export default { :show-label="false" class="d-flex border-0 p-0" icon="folder-new" - @click="openNewEntryModal({ type: 'tree' })" + @click="createNewFolder()" /> </div> + <new-modal ref="newModal" /> </template> </ide-tree-list> </template> diff --git a/app/assets/javascripts/ide/components/jobs/detail.vue b/app/assets/javascripts/ide/components/jobs/detail.vue index 504391ffdc7..975d54c7a4e 100644 --- a/app/assets/javascripts/ide/components/jobs/detail.vue +++ b/app/assets/javascripts/ide/components/jobs/detail.vue @@ -79,7 +79,7 @@ export default { <icon name="chevron-left" /> {{ __('View jobs') }} </button> </header> - <div class="top-bar d-flex border-left-0"> + <div class="top-bar d-flex border-left-0 mr-3"> <job-description :job="detailJob" /> <div class="controllers ml-auto"> <a @@ -97,7 +97,7 @@ export default { <scroll-button :disabled="isScrolledToBottom" direction="down" @click="scrollDown" /> </div> </div> - <pre ref="buildTrace" class="build-trace mb-0 h-100" @scroll="scrollBuildLog"> + <pre ref="buildTrace" class="build-trace mb-0 h-100 mr-3" @scroll="scrollBuildLog"> <code v-show="!detailJob.isLoading" class="bash" diff --git a/app/assets/javascripts/ide/components/nav_form.vue b/app/assets/javascripts/ide/components/nav_form.vue index 195504a6861..70a92b8d3ab 100644 --- a/app/assets/javascripts/ide/components/nav_form.vue +++ b/app/assets/javascripts/ide/components/nav_form.vue @@ -25,13 +25,13 @@ export default { <div class="ide-nav-form p-0"> <tabs v-if="showMergeRequests" stop-propagation> <tab active> - <template slot="title"> + <template #title> {{ __('Branches') }} </template> <branches-search-list /> </tab> <tab> - <template slot="title"> + <template #title> {{ __('Merge Requests') }} </template> <merge-request-search-list /> diff --git a/app/assets/javascripts/ide/components/new_dropdown/index.vue b/app/assets/javascripts/ide/components/new_dropdown/index.vue index 9961c0df52e..2798ede5341 100644 --- a/app/assets/javascripts/ide/components/new_dropdown/index.vue +++ b/app/assets/javascripts/ide/components/new_dropdown/index.vue @@ -4,12 +4,14 @@ import icon from '~/vue_shared/components/icon.vue'; import upload from './upload.vue'; import ItemButton from './button.vue'; import { modalTypes } from '../../constants'; +import NewModal from './modal.vue'; export default { components: { icon, upload, ItemButton, + NewModal, }, props: { type: { @@ -37,9 +39,9 @@ export default { }, }, methods: { - ...mapActions(['createTempEntry', 'openNewEntryModal', 'deleteEntry']), + ...mapActions(['createTempEntry', 'deleteEntry']), createNewItem(type) { - this.openNewEntryModal({ type, path: this.path }); + this.$refs.newModal.open(type, this.path); this.$emit('toggle', false); }, openDropdown() { @@ -109,5 +111,6 @@ export default { </li> </ul> </div> + <new-modal ref="newModal" /> </div> </template> diff --git a/app/assets/javascripts/ide/components/new_dropdown/modal.vue b/app/assets/javascripts/ide/components/new_dropdown/modal.vue index bf3d736ddf3..4766a2fe6ae 100644 --- a/app/assets/javascripts/ide/components/new_dropdown/modal.vue +++ b/app/assets/javascripts/ide/components/new_dropdown/modal.vue @@ -1,61 +1,49 @@ <script> -import $ from 'jquery'; import { mapActions, mapState, mapGetters } from 'vuex'; import flash from '~/flash'; import { __, sprintf, s__ } from '~/locale'; -import DeprecatedModal2 from '~/vue_shared/components/deprecated_modal_2.vue'; +import { GlModal } from '@gitlab/ui'; import { modalTypes } from '../../constants'; +import { trimPathComponents } from '../../utils'; export default { components: { - GlModal: DeprecatedModal2, + GlModal, }, data() { return { - name: '', + entryName: '', + modalType: modalTypes.blob, + path: '', }; }, computed: { - ...mapState(['entries', 'entryModal']), + ...mapState(['entries']), ...mapGetters('fileTemplates', ['templateTypes']), - entryName: { - get() { - const entryPath = this.entryModal.entry.path; - - if (this.entryModal.type === modalTypes.rename) { - return this.name || entryPath; - } - - return this.name || (entryPath ? `${entryPath}/` : ''); - }, - set(val) { - this.name = val.trim(); - }, - }, modalTitle() { - if (this.entryModal.type === modalTypes.tree) { + const entry = this.entries[this.path]; + + if (this.modalType === modalTypes.tree) { return __('Create new directory'); - } else if (this.entryModal.type === modalTypes.rename) { - return this.entryModal.entry.type === modalTypes.tree - ? __('Rename folder') - : __('Rename file'); + } else if (this.modalType === modalTypes.rename) { + return entry.type === modalTypes.tree ? __('Rename folder') : __('Rename file'); } return __('Create new file'); }, buttonLabel() { - if (this.entryModal.type === modalTypes.tree) { + const entry = this.entries[this.path]; + + if (this.modalType === modalTypes.tree) { return __('Create directory'); - } else if (this.entryModal.type === modalTypes.rename) { - return this.entryModal.entry.type === modalTypes.tree - ? __('Rename folder') - : __('Rename file'); + } else if (this.modalType === modalTypes.rename) { + return entry.type === modalTypes.tree ? __('Rename folder') : __('Rename file'); } return __('Create file'); }, isCreatingNewFile() { - return this.entryModal.type === 'blob'; + return this.modalType === modalTypes.blob; }, placeholder() { return this.isCreatingNewFile ? 'dir/file_name' : 'dir/'; @@ -64,7 +52,9 @@ export default { methods: { ...mapActions(['createTempEntry', 'renameEntry']), submitForm() { - if (this.entryModal.type === modalTypes.rename) { + this.entryName = trimPathComponents(this.entryName); + + if (this.modalType === modalTypes.rename) { if (this.entries[this.entryName] && !this.entries[this.entryName].deleted) { flash( sprintf(s__('The name "%{name}" is already taken in this directory.'), { @@ -78,32 +68,32 @@ export default { ); } else { let parentPath = this.entryName.split('/'); - const entryName = parentPath.pop(); + const name = parentPath.pop(); parentPath = parentPath.join('/'); this.renameEntry({ - path: this.entryModal.entry.path, - name: entryName, + path: this.path, + name, parentPath, }); } } else { this.createTempEntry({ - name: this.name, - type: this.entryModal.type, + name: this.entryName, + type: this.modalType, }); } }, createFromTemplate(template) { this.createTempEntry({ name: template.name, - type: this.entryModal.type, + type: this.modalType, }); - $('#ide-new-entry').modal('toggle'); + this.$refs.modal.toggle(); }, focusInput() { - const name = this.entries[this.entryName] ? this.entries[this.entryName].name : null; + const name = this.entries[this.entryName]?.name; const inputValue = this.$refs.fieldName.value; this.$refs.fieldName.focus(); @@ -112,8 +102,28 @@ export default { this.$refs.fieldName.setSelectionRange(inputValue.indexOf(name), inputValue.length); } }, - closedModal() { - this.name = ''; + resetData() { + this.entryName = ''; + this.path = ''; + this.modalType = modalTypes.blob; + }, + open(type = modalTypes.blob, path = '') { + this.modalType = type; + this.path = path; + + if (this.modalType === modalTypes.rename) { + this.entryName = path; + } else { + this.entryName = path ? `${path}/` : ''; + } + + this.$refs.modal.show(); + + // wait for modal to show first + this.$nextTick(() => this.focusInput()); + }, + close() { + this.$refs.modal.hide(); }, }, }; @@ -121,22 +131,22 @@ export default { <template> <gl-modal - id="ide-new-entry" - class="qa-new-file-modal" - :header-title-text="modalTitle" - :footer-primary-button-text="buttonLabel" - footer-primary-button-variant="success" - modal-size="lg" - @submit="submitForm" - @open="focusInput" - @closed="closedModal" + ref="modal" + modal-id="ide-new-entry" + modal-class="qa-new-file-modal" + :title="modalTitle" + :ok-title="buttonLabel" + ok-variant="success" + size="lg" + @ok="submitForm" + @hide="resetData" > <div class="form-group row"> <label class="label-bold col-form-label col-sm-2"> {{ __('Name') }} </label> <div class="col-sm-10"> <input ref="fieldName" - v-model="entryName" + v-model.trim="entryName" type="text" class="form-control qa-full-file-path" :placeholder="placeholder" diff --git a/app/assets/javascripts/ide/components/panes/collapsible_sidebar.vue b/app/assets/javascripts/ide/components/panes/collapsible_sidebar.vue index 8adf0122fb4..91e80be7d18 100644 --- a/app/assets/javascripts/ide/components/panes/collapsible_sidebar.vue +++ b/app/assets/javascripts/ide/components/panes/collapsible_sidebar.vue @@ -103,7 +103,6 @@ export default { > <resizable-panel v-show="isOpen" - :collapsible="false" :initial-width="width" :min-size="width" :class="`ide-${side}-sidebar-${currentView}`" @@ -116,7 +115,7 @@ export default { v-for="tabView in aliveTabViews" v-show="isActiveView(tabView.name)" :key="tabView.name" - class="flex-fill js-tab-view" + class="flex-fill gl-overflow-hidden js-tab-view" > <component :is="tabView.component" /> </div> diff --git a/app/assets/javascripts/ide/components/pipelines/list.vue b/app/assets/javascripts/ide/components/pipelines/list.vue index d3e5add2e83..cf6d01b6351 100644 --- a/app/assets/javascripts/ide/components/pipelines/list.vue +++ b/app/assets/javascripts/ide/components/pipelines/list.vue @@ -1,6 +1,6 @@ <script> import { mapActions, mapGetters, mapState } from 'vuex'; -import { escape as esc } from 'lodash'; +import { escape } from 'lodash'; import { GlLoadingIcon } from '@gitlab/ui'; import { sprintf, __ } from '../../../locale'; import Icon from '../../../vue_shared/components/icon.vue'; @@ -10,6 +10,8 @@ import Tab from '../../../vue_shared/components/tabs/tab.vue'; import EmptyState from '../../../pipelines/components/empty_state.vue'; import JobsList from '../jobs/list.vue'; +import IDEServices from '~/ide/services'; + export default { components: { Icon, @@ -35,7 +37,7 @@ export default { return sprintf( __('You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}.'), { - linkStart: `<a href="${esc(this.currentProject.web_url)}/-/ci/lint">`, + linkStart: `<a href="${escape(this.currentProject.web_url)}/-/ci/lint">`, linkEnd: '</a>', }, false, @@ -47,6 +49,7 @@ export default { }, created() { this.fetchLatestPipeline(); + IDEServices.pingUsage(this.currentProject.path_with_namespace); }, methods: { ...mapActions('pipelines', ['fetchLatestPipeline']), @@ -85,14 +88,14 @@ export default { </div> <tabs v-else class="ide-pipeline-list"> <tab :active="!pipelineFailed"> - <template slot="title"> + <template #title> {{ __('Jobs') }} <span v-if="jobsCount" class="badge badge-pill"> {{ jobsCount }} </span> </template> <jobs-list :loading="isLoadingJobs" :stages="stages" /> </tab> <tab :active="pipelineFailed"> - <template slot="title"> + <template #title> {{ __('Failed Jobs') }} <span v-if="failedJobsCount" class="badge badge-pill"> {{ failedJobsCount }} </span> </template> diff --git a/app/assets/javascripts/ide/components/repo_commit_section.vue b/app/assets/javascripts/ide/components/repo_commit_section.vue index 2e7e55a61c5..530fba49df2 100644 --- a/app/assets/javascripts/ide/components/repo_commit_section.vue +++ b/app/assets/javascripts/ide/components/repo_commit_section.vue @@ -1,15 +1,12 @@ <script> import { mapState, mapActions, mapGetters } from 'vuex'; import tooltip from '~/vue_shared/directives/tooltip'; -import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue'; import CommitFilesList from './commit_sidebar/list.vue'; import EmptyState from './commit_sidebar/empty_state.vue'; -import consts from '../stores/modules/commit/constants'; import { leftSidebarViews, stageKeys } from '../constants'; export default { components: { - DeprecatedModal, CommitFilesList, EmptyState, }, @@ -17,13 +14,7 @@ export default { tooltip, }, computed: { - ...mapState([ - 'changedFiles', - 'stagedFiles', - 'rightPanelCollapsed', - 'lastCommitMsg', - 'unusedSeal', - ]), + ...mapState(['changedFiles', 'stagedFiles', 'lastCommitMsg', 'unusedSeal']), ...mapState('commit', ['commitMessage', 'submitCommitLoading']), ...mapGetters(['lastOpenedFile', 'hasChanges', 'someUncommittedChanges', 'activeFile']), ...mapGetters('commit', ['discardDraftButtonDisabled']), @@ -59,10 +50,6 @@ export default { }, methods: { ...mapActions(['openPendingTab', 'updateViewer', 'updateActivityBarView']), - ...mapActions('commit', ['commitChanges', 'updateCommitAction']), - forceCreateNewBranch() { - return this.updateCommitAction(consts.COMMIT_TO_NEW_BRANCH).then(() => this.commitChanges()); - }, }, stageKeys, }; @@ -70,20 +57,6 @@ export default { <template> <div class="multi-file-commit-panel-section"> - <deprecated-modal - id="ide-create-branch-modal" - :primary-button-label="__('Create new branch')" - :title="__('Branch has changed')" - kind="success" - @submit="forceCreateNewBranch" - > - <template slot="body"> - {{ - __(`This branch has changed since you started editing. - Would you like to create a new branch?`) - }} - </template> - </deprecated-modal> <template v-if="showStageUnstageArea"> <commit-files-list :key-prefix="$options.stageKeys.staged" diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue index 08850679152..c72a8b2b0d0 100644 --- a/app/assets/javascripts/ide/components/repo_editor.vue +++ b/app/assets/javascripts/ide/components/repo_editor.vue @@ -13,6 +13,7 @@ import { import Editor from '../lib/editor'; import FileTemplatesBar from './file_templates/bar.vue'; import { __ } from '~/locale'; +import { extractMarkdownImagesFromEntries } from '../stores/utils'; export default { components: { @@ -26,17 +27,23 @@ export default { required: true, }, }, + data() { + return { + content: '', + images: {}, + }; + }, computed: { ...mapState('rightPane', { rightPaneIsOpen: 'isOpen', }), ...mapState([ - 'rightPanelCollapsed', 'viewer', 'panelResizing', 'currentActivityView', 'renderWhitespaceInCode', 'editorTheme', + 'entries', ]), ...mapGetters([ 'currentMergeRequest', @@ -44,6 +51,7 @@ export default { 'isEditModeActive', 'isCommitModeActive', 'isReviewModeActive', + 'currentBranch', ]), ...mapGetters('fileTemplates', ['showFileTemplatesBar']), shouldHideEditor() { @@ -87,6 +95,9 @@ export default { theme: this.editorTheme, }; }, + currentBranchCommit() { + return this.currentBranch?.commit.id; + }, }, watch: { file(newVal, oldVal) { @@ -114,9 +125,6 @@ export default { }); } }, - rightPanelCollapsed() { - this.refreshEditorDimensions(); - }, viewer() { if (!this.file.pending) { this.createEditorInstance(); @@ -136,6 +144,18 @@ export default { this.$nextTick(() => this.refreshEditorDimensions()); } }, + showContentViewer(val) { + if (!val) return; + + if (this.fileType === 'markdown') { + const { content, images } = extractMarkdownImagesFromEntries(this.file, this.entries); + this.content = content; + this.images = images; + } else { + this.content = this.file.content || this.file.raw; + this.images = {}; + } + }, }, beforeDestroy() { this.editor.dispose(); @@ -310,11 +330,13 @@ export default { ></div> <content-viewer v-if="showContentViewer" - :content="file.content || file.raw" + :content="content" + :images="images" :path="file.rawPath || file.path" :file-path="file.path" :file-size="file.size" :project-path="file.projectId" + :commit-sha="currentBranchCommit" :type="fileType" /> <diff-viewer diff --git a/app/assets/javascripts/ide/components/resizable_panel.vue b/app/assets/javascripts/ide/components/resizable_panel.vue index 7277fcb7617..86a4622401c 100644 --- a/app/assets/javascripts/ide/components/resizable_panel.vue +++ b/app/assets/javascripts/ide/components/resizable_panel.vue @@ -1,5 +1,5 @@ <script> -import { mapActions, mapState } from 'vuex'; +import { mapActions } from 'vuex'; import PanelResizer from '~/vue_shared/components/panel_resizer.vue'; export default { @@ -7,10 +7,6 @@ export default { PanelResizer, }, props: { - collapsible: { - type: Boolean, - required: true, - }, initialWidth: { type: Number, required: true, @@ -31,11 +27,6 @@ export default { }; }, computed: { - ...mapState({ - collapsed(state) { - return state[`${this.side}PanelCollapsed`]; - }, - }), panelStyle() { if (!this.collapsed) { return { @@ -47,33 +38,17 @@ export default { }, }, methods: { - ...mapActions(['setPanelCollapsedStatus', 'setResizingStatus']), - toggleFullbarCollapsed() { - if (this.collapsed && this.collapsible) { - this.setPanelCollapsedStatus({ - side: this.side, - collapsed: !this.collapsed, - }); - } - }, + ...mapActions(['setResizingStatus']), }, maxSize: window.innerWidth / 2, }; </script> <template> - <div - :class="{ - 'is-collapsed': collapsed && collapsible, - }" - :style="panelStyle" - class="multi-file-commit-panel" - @click="toggleFullbarCollapsed" - > + <div :style="panelStyle" class="multi-file-commit-panel"> <slot></slot> <panel-resizer :size.sync="width" - :enabled="!collapsed" :start-size="initialWidth" :min-size="minSize" :max-size="$options.maxSize" diff --git a/app/assets/javascripts/ide/constants.js b/app/assets/javascripts/ide/constants.js index fa2672aaece..ae8550cba76 100644 --- a/app/assets/javascripts/ide/constants.js +++ b/app/assets/javascripts/ide/constants.js @@ -78,6 +78,7 @@ export const commitItemIconMap = { export const modalTypes = { rename: 'rename', tree: 'tree', + blob: 'blob', }; export const commitActionTypes = { diff --git a/app/assets/javascripts/ide/eventhub.js b/app/assets/javascripts/ide/eventhub.js index 0948c2e5352..e31806ad199 100644 --- a/app/assets/javascripts/ide/eventhub.js +++ b/app/assets/javascripts/ide/eventhub.js @@ -1,3 +1,3 @@ -import Vue from 'vue'; +import createEventHub from '~/helpers/event_hub_factory'; -export default new Vue(); +export default createEventHub(); diff --git a/app/assets/javascripts/ide/lib/diff/diff.js b/app/assets/javascripts/ide/lib/diff/diff.js index 9b7ed68b893..29e29d7fcd3 100644 --- a/app/assets/javascripts/ide/lib/diff/diff.js +++ b/app/assets/javascripts/ide/lib/diff/diff.js @@ -14,13 +14,12 @@ export const computeDiff = (originalContent, newContent) => { endLineNumber: lineNumber + change.count - 1, }); } else if ('added' in change || 'removed' in change) { - acc.push( - Object.assign({}, change, { - lineNumber, - modified: undefined, - endLineNumber: lineNumber + change.count - 1, - }), - ); + acc.push({ + ...change, + lineNumber, + modified: undefined, + endLineNumber: lineNumber + change.count - 1, + }); } if (!change.removed) { diff --git a/app/assets/javascripts/ide/lib/editor.js b/app/assets/javascripts/ide/lib/editor.js index 3aff4d30d81..25224abd77c 100644 --- a/app/assets/javascripts/ide/lib/editor.js +++ b/app/assets/javascripts/ide/lib/editor.js @@ -7,8 +7,10 @@ import Disposable from './common/disposable'; import ModelManager from './common/model_manager'; import editorOptions, { defaultEditorOptions } from './editor_options'; import { themes } from './themes'; +import languages from './languages'; import keymap from './keymap.json'; import { clearDomElement } from '~/editor/utils'; +import { registerLanguages } from '../utils'; function setupThemes() { themes.forEach(theme => { @@ -37,6 +39,7 @@ export default class Editor { }; setupThemes(); + registerLanguages(...languages); this.debouncedUpdate = debounce(() => { this.updateDimensions(); diff --git a/app/assets/javascripts/ide/lib/languages/index.js b/app/assets/javascripts/ide/lib/languages/index.js new file mode 100644 index 00000000000..0c85a1104fc --- /dev/null +++ b/app/assets/javascripts/ide/lib/languages/index.js @@ -0,0 +1,5 @@ +import vue from './vue'; + +const languages = [vue]; + +export default languages; diff --git a/app/assets/javascripts/ide/lib/languages/vue.js b/app/assets/javascripts/ide/lib/languages/vue.js new file mode 100644 index 00000000000..b9ff5c5d776 --- /dev/null +++ b/app/assets/javascripts/ide/lib/languages/vue.js @@ -0,0 +1,306 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See https://github.com/microsoft/monaco-languages/blob/master/LICENSE.md + *--------------------------------------------------------------------------------------------*/ + +// Based on handlebars template in https://github.com/microsoft/monaco-languages/blob/master/src/handlebars/handlebars.ts +// Look for "vuejs template attributes" in this file for Vue specific syntax. + +import { languages } from 'monaco-editor'; + +/* eslint-disable no-useless-escape */ +/* eslint-disable @gitlab/require-i18n-strings */ + +const EMPTY_ELEMENTS = [ + 'area', + 'base', + 'br', + 'col', + 'embed', + 'hr', + 'img', + 'input', + 'keygen', + 'link', + 'menuitem', + 'meta', + 'param', + 'source', + 'track', + 'wbr', +]; + +const conf = { + wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\$\^\&\*\(\)\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\s]+)/g, + + comments: { + blockComment: ['{{!--', '--}}'], + }, + + brackets: [['<!--', '-->'], ['<', '>'], ['{{', '}}'], ['{', '}'], ['(', ')']], + + autoClosingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '"', close: '"' }, + { open: "'", close: "'" }, + ], + + surroundingPairs: [ + { open: '<', close: '>' }, + { open: '"', close: '"' }, + { open: "'", close: "'" }, + ], + + onEnterRules: [ + { + beforeText: new RegExp( + `<(?!(?:${EMPTY_ELEMENTS.join('|')}))(\\w[\\w\\d]*)([^/>]*(?!/)>)[^<]*$`, + 'i', + ), + afterText: /^<\/(\w[\w\d]*)\s*>$/i, + action: { indentAction: languages.IndentAction.IndentOutdent }, + }, + { + beforeText: new RegExp( + `<(?!(?:${EMPTY_ELEMENTS.join('|')}))(\\w[\\w\\d]*)([^/>]*(?!/)>)[^<]*$`, + 'i', + ), + action: { indentAction: languages.IndentAction.Indent }, + }, + ], +}; + +const language = { + defaultToken: '', + tokenPostfix: '', + // ignoreCase: true, + + // The main tokenizer for our languages + tokenizer: { + root: [ + [/\{\{/, { token: '@rematch', switchTo: '@handlebarsInSimpleState.root' }], + [/<!DOCTYPE/, 'metatag.html', '@doctype'], + [/<!--/, 'comment.html', '@comment'], + [/(<)([\w]+)(\/>)/, ['delimiter.html', 'tag.html', 'delimiter.html']], + [/(<)(script)/, ['delimiter.html', { token: 'tag.html', next: '@script' }]], + [/(<)(style)/, ['delimiter.html', { token: 'tag.html', next: '@style' }]], + [/(<)([:\w]+)/, ['delimiter.html', { token: 'tag.html', next: '@otherTag' }]], + [/(<\/)([\w]+)/, ['delimiter.html', { token: 'tag.html', next: '@otherTag' }]], + [/</, 'delimiter.html'], + [/\{/, 'delimiter.html'], + [/[^<{]+/], // text + ], + + doctype: [ + [/\{\{/, { token: '@rematch', switchTo: '@handlebarsInSimpleState.comment' }], + [/[^>]+/, 'metatag.content.html'], + [/>/, 'metatag.html', '@pop'], + ], + + comment: [ + [/\{\{/, { token: '@rematch', switchTo: '@handlebarsInSimpleState.comment' }], + [/-->/, 'comment.html', '@pop'], + [/[^-]+/, 'comment.content.html'], + [/./, 'comment.content.html'], + ], + + otherTag: [ + [/\{\{/, { token: '@rematch', switchTo: '@handlebarsInSimpleState.otherTag' }], + [/\/?>/, 'delimiter.html', '@pop'], + + // -- BEGIN vuejs template attributes + [/(v-|@|:)[\w\-\.\:\[\]]+="([^"]*)"/, 'variable'], + [/(v-|@|:)[\w\-\.\:\[\]]+='([^']*)'/, 'variable'], + + [/"([^"]*)"/, 'attribute.value'], + [/'([^']*)'/, 'attribute.value'], + + [/[\w\-\.\:\[\]]+/, 'attribute.name'], + // -- END vuejs template attributes + + [/=/, 'delimiter'], + [/[ \t\r\n]+/], // whitespace + ], + + // -- BEGIN <script> tags handling + + // After <script + script: [ + [/\{\{/, { token: '@rematch', switchTo: '@handlebarsInSimpleState.script' }], + [/type/, 'attribute.name', '@scriptAfterType'], + [/"([^"]*)"/, 'attribute.value'], + [/'([^']*)'/, 'attribute.value'], + [/[\w\-]+/, 'attribute.name'], + [/=/, 'delimiter'], + [ + />/, + { + token: 'delimiter.html', + next: '@scriptEmbedded.text/javascript', + nextEmbedded: 'text/javascript', + }, + ], + [/[ \t\r\n]+/], // whitespace + [ + /(<\/)(script\s*)(>)/, + ['delimiter.html', 'tag.html', { token: 'delimiter.html', next: '@pop' }], + ], + ], + + // After <script ... type + scriptAfterType: [ + [/\{\{/, { token: '@rematch', switchTo: '@handlebarsInSimpleState.scriptAfterType' }], + [/=/, 'delimiter', '@scriptAfterTypeEquals'], + [ + />/, + { + token: 'delimiter.html', + next: '@scriptEmbedded.text/javascript', + nextEmbedded: 'text/javascript', + }, + ], // cover invalid e.g. <script type> + [/[ \t\r\n]+/], // whitespace + [/<\/script\s*>/, { token: '@rematch', next: '@pop' }], + ], + + // After <script ... type = + scriptAfterTypeEquals: [ + [/\{\{/, { token: '@rematch', switchTo: '@handlebarsInSimpleState.scriptAfterTypeEquals' }], + [/"([^"]*)"/, { token: 'attribute.value', switchTo: '@scriptWithCustomType.$1' }], + [/'([^']*)'/, { token: 'attribute.value', switchTo: '@scriptWithCustomType.$1' }], + [ + />/, + { + token: 'delimiter.html', + next: '@scriptEmbedded.text/javascript', + nextEmbedded: 'text/javascript', + }, + ], // cover invalid e.g. <script type=> + [/[ \t\r\n]+/], // whitespace + [/<\/script\s*>/, { token: '@rematch', next: '@pop' }], + ], + + // After <script ... type = $S2 + scriptWithCustomType: [ + [ + /\{\{/, + { token: '@rematch', switchTo: '@handlebarsInSimpleState.scriptWithCustomType.$S2' }, + ], + [/>/, { token: 'delimiter.html', next: '@scriptEmbedded.$S2', nextEmbedded: '$S2' }], + [/"([^"]*)"/, 'attribute.value'], + [/'([^']*)'/, 'attribute.value'], + [/[\w\-]+/, 'attribute.name'], + [/=/, 'delimiter'], + [/[ \t\r\n]+/], // whitespace + [/<\/script\s*>/, { token: '@rematch', next: '@pop' }], + ], + + scriptEmbedded: [ + [ + /\{\{/, + { + token: '@rematch', + switchTo: '@handlebarsInEmbeddedState.scriptEmbedded.$S2', + nextEmbedded: '@pop', + }, + ], + [/<\/script/, { token: '@rematch', next: '@pop', nextEmbedded: '@pop' }], + ], + + // -- END <script> tags handling + + // -- BEGIN <style> tags handling + + // After <style + style: [ + [/\{\{/, { token: '@rematch', switchTo: '@handlebarsInSimpleState.style' }], + [/type/, 'attribute.name', '@styleAfterType'], + [/"([^"]*)"/, 'attribute.value'], + [/'([^']*)'/, 'attribute.value'], + [/[\w\-]+/, 'attribute.name'], + [/=/, 'delimiter'], + [/>/, { token: 'delimiter.html', next: '@styleEmbedded.text/css', nextEmbedded: 'text/css' }], + [/[ \t\r\n]+/], // whitespace + [ + /(<\/)(style\s*)(>)/, + ['delimiter.html', 'tag.html', { token: 'delimiter.html', next: '@pop' }], + ], + ], + + // After <style ... type + styleAfterType: [ + [/\{\{/, { token: '@rematch', switchTo: '@handlebarsInSimpleState.styleAfterType' }], + [/=/, 'delimiter', '@styleAfterTypeEquals'], + [/>/, { token: 'delimiter.html', next: '@styleEmbedded.text/css', nextEmbedded: 'text/css' }], // cover invalid e.g. <style type> + [/[ \t\r\n]+/], // whitespace + [/<\/style\s*>/, { token: '@rematch', next: '@pop' }], + ], + + // After <style ... type = + styleAfterTypeEquals: [ + [/\{\{/, { token: '@rematch', switchTo: '@handlebarsInSimpleState.styleAfterTypeEquals' }], + [/"([^"]*)"/, { token: 'attribute.value', switchTo: '@styleWithCustomType.$1' }], + [/'([^']*)'/, { token: 'attribute.value', switchTo: '@styleWithCustomType.$1' }], + [/>/, { token: 'delimiter.html', next: '@styleEmbedded.text/css', nextEmbedded: 'text/css' }], // cover invalid e.g. <style type=> + [/[ \t\r\n]+/], // whitespace + [/<\/style\s*>/, { token: '@rematch', next: '@pop' }], + ], + + // After <style ... type = $S2 + styleWithCustomType: [ + [/\{\{/, { token: '@rematch', switchTo: '@handlebarsInSimpleState.styleWithCustomType.$S2' }], + [/>/, { token: 'delimiter.html', next: '@styleEmbedded.$S2', nextEmbedded: '$S2' }], + [/"([^"]*)"/, 'attribute.value'], + [/'([^']*)'/, 'attribute.value'], + [/[\w\-]+/, 'attribute.name'], + [/=/, 'delimiter'], + [/[ \t\r\n]+/], // whitespace + [/<\/style\s*>/, { token: '@rematch', next: '@pop' }], + ], + + styleEmbedded: [ + [ + /\{\{/, + { + token: '@rematch', + switchTo: '@handlebarsInEmbeddedState.styleEmbedded.$S2', + nextEmbedded: '@pop', + }, + ], + [/<\/style/, { token: '@rematch', next: '@pop', nextEmbedded: '@pop' }], + ], + + // -- END <style> tags handling + + handlebarsInSimpleState: [ + [/\{\{\{?/, 'delimiter.handlebars'], + [/\}\}\}?/, { token: 'delimiter.handlebars', switchTo: '@$S2.$S3' }], + { include: 'handlebarsRoot' }, + ], + + handlebarsInEmbeddedState: [ + [/\{\{\{?/, 'delimiter.handlebars'], + [/\}\}\}?/, { token: 'delimiter.handlebars', switchTo: '@$S2.$S3', nextEmbedded: '$S3' }], + { include: 'handlebarsRoot' }, + ], + + handlebarsRoot: [ + [/"[^"]*"/, 'string.handlebars'], + [/[#/][^\s}]+/, 'keyword.helper.handlebars'], + [/else\b/, 'keyword.helper.handlebars'], + [/[\s]+/], + [/[^}]/, 'variable.parameter.handlebars'], + ], + }, +}; + +export default { + id: 'vue', + extensions: ['.vue'], + aliases: ['Vue', 'vue'], + mimetypes: ['text/x-vue-template'], + conf, + language, +}; diff --git a/app/assets/javascripts/ide/lib/themes/index.js b/app/assets/javascripts/ide/lib/themes/index.js index 6ed9f6679a4..bb5be50576c 100644 --- a/app/assets/javascripts/ide/lib/themes/index.js +++ b/app/assets/javascripts/ide/lib/themes/index.js @@ -1,5 +1,9 @@ import white from './white'; import dark from './dark'; +import monokai from './monokai'; +import solarizedLight from './solarized_light'; +import solarizedDark from './solarized_dark'; +import none from './none'; export const themes = [ { @@ -10,6 +14,22 @@ export const themes = [ name: 'dark', data: dark, }, + { + name: 'solarized-light', + data: solarizedLight, + }, + { + name: 'solarized-dark', + data: solarizedDark, + }, + { + name: 'monokai', + data: monokai, + }, + { + name: 'none', + data: none, + }, ]; export const DEFAULT_THEME = 'white'; diff --git a/app/assets/javascripts/ide/lib/themes/monokai.js b/app/assets/javascripts/ide/lib/themes/monokai.js new file mode 100644 index 00000000000..d7636574754 --- /dev/null +++ b/app/assets/javascripts/ide/lib/themes/monokai.js @@ -0,0 +1,169 @@ +/* + +https://github.com/brijeshb42/monaco-themes/blob/master/themes/Tomorrow-Night.json + +The MIT License (MIT) + +Copyright (c) Brijesh Bittu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +export default { + base: 'vs-dark', + inherit: true, + rules: [ + { + foreground: '75715e', + token: 'comment', + }, + { + foreground: 'e6db74', + token: 'string', + }, + { + foreground: 'ae81ff', + token: 'constant.numeric', + }, + { + foreground: 'ae81ff', + token: 'constant.language', + }, + { + foreground: 'ae81ff', + token: 'constant.character', + }, + { + foreground: 'ae81ff', + token: 'constant.other', + }, + { + foreground: 'f92672', + token: 'keyword', + }, + { + foreground: 'f92672', + token: 'storage', + }, + { + foreground: '66d9ef', + fontStyle: 'italic', + token: 'storage.type', + }, + { + foreground: 'a6e22e', + fontStyle: 'underline', + token: 'entity.name.class', + }, + { + foreground: 'a6e22e', + // eslint-disable-next-line @gitlab/require-i18n-strings + fontStyle: 'italic underline', + token: 'entity.other.inherited-class', + }, + { + foreground: 'a6e22e', + token: 'entity.name.function', + }, + { + foreground: 'fd971f', + fontStyle: 'italic', + token: 'variable.parameter', + }, + { + foreground: 'f92672', + token: 'entity.name.tag', + }, + { + foreground: 'a6e22e', + token: 'entity.other.attribute-name', + }, + { + foreground: '66d9ef', + token: 'support.function', + }, + { + foreground: '66d9ef', + token: 'support.constant', + }, + { + foreground: '66d9ef', + fontStyle: 'italic', + token: 'support.type', + }, + { + foreground: '66d9ef', + fontStyle: 'italic', + token: 'support.class', + }, + { + foreground: 'f8f8f0', + background: 'f92672', + token: 'invalid', + }, + { + foreground: 'f8f8f0', + background: 'ae81ff', + token: 'invalid.deprecated', + }, + { + foreground: 'cfcfc2', + token: 'meta.structure.dictionary.json string.quoted.double.json', + }, + { + foreground: '75715e', + token: 'meta.diff', + }, + { + foreground: '75715e', + token: 'meta.diff.header', + }, + { + foreground: 'f92672', + token: 'markup.deleted', + }, + { + foreground: 'a6e22e', + token: 'markup.inserted', + }, + { + foreground: 'e6db74', + token: 'markup.changed', + }, + { + foreground: 'ae81ffa0', + token: 'constant.numeric.line-number.find-in-files - match', + }, + { + foreground: 'e6db74', + token: 'entity.name.filename.find-in-files', + }, + ], + colors: { + 'editor.foreground': '#F8F8F2', + 'editor.background': '#272822', + 'editor.selectionBackground': '#49483E', + 'editor.lineHighlightBackground': '#3E3D32', + 'editorCursor.foreground': '#F8F8F0', + 'editorWhitespace.foreground': '#3B3A32', + 'editorIndentGuide.activeBackground': '#9D550FB0', + 'editor.selectionHighlightBorder': '#222218', + }, +}; diff --git a/app/assets/javascripts/ide/lib/themes/none.js b/app/assets/javascripts/ide/lib/themes/none.js new file mode 100644 index 00000000000..8e722c4ff88 --- /dev/null +++ b/app/assets/javascripts/ide/lib/themes/none.js @@ -0,0 +1,17 @@ +export default { + base: 'vs', + inherit: false, + rules: [], + colors: { + 'editor.foreground': '#2e2e2e', + 'editor.selectionBackground': '#aad6f8', + 'editor.lineHighlightBackground': '#fffeeb', + 'editorCursor.foreground': '#666666', + 'editorWhitespace.foreground': '#bbbbbb', + + 'editorLineNumber.foreground': '#cccccc', + 'diffEditor.insertedTextBackground': '#a0f5b420', + 'diffEditor.removedTextBackground': '#f9d7dc20', + 'editorIndentGuide.activeBackground': '#cccccc', + }, +}; diff --git a/app/assets/javascripts/ide/lib/themes/solarized_dark.js b/app/assets/javascripts/ide/lib/themes/solarized_dark.js new file mode 100644 index 00000000000..3c9414b9dc9 --- /dev/null +++ b/app/assets/javascripts/ide/lib/themes/solarized_dark.js @@ -0,0 +1,1110 @@ +/* + +https://github.com/brijeshb42/monaco-themes/blob/master/themes/Solarized-dark.json + +The MIT License (MIT) + +Copyright (c) Brijesh Bittu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ +export default { + base: 'vs-dark', + inherit: true, + rules: [ + { + foreground: '586e75', + token: 'comment', + }, + { + foreground: '2aa198', + token: 'string', + }, + { + foreground: '586e75', + token: 'string', + }, + { + foreground: 'dc322f', + token: 'string.regexp', + }, + { + foreground: 'd33682', + token: 'constant.numeric', + }, + { + foreground: '268bd2', + token: 'variable.language', + }, + { + foreground: '268bd2', + token: 'variable.other', + }, + { + foreground: '859900', + token: 'keyword', + }, + { + foreground: '859900', + token: 'storage', + }, + { + foreground: '268bd2', + token: 'entity.name.class', + }, + { + foreground: '268bd2', + token: 'entity.name.type.class', + }, + { + foreground: '268bd2', + token: 'entity.name.function', + }, + { + foreground: '859900', + token: 'punctuation.definition.variable', + }, + { + foreground: 'dc322f', + token: 'punctuation.section.embedded.begin', + }, + { + foreground: 'dc322f', + token: 'punctuation.section.embedded.end', + }, + { + foreground: 'b58900', + token: 'constant.language', + }, + { + foreground: 'b58900', + token: 'meta.preprocessor', + }, + { + foreground: 'dc322f', + token: 'support.function.construct', + }, + { + foreground: 'dc322f', + token: 'keyword.other.new', + }, + { + foreground: 'cb4b16', + token: 'constant.character', + }, + { + foreground: 'cb4b16', + token: 'constant.other', + }, + { + foreground: '268bd2', + fontStyle: 'bold', + token: 'entity.name.tag', + }, + { + foreground: '586e75', + token: 'punctuation.definition.tag.html', + }, + { + foreground: '586e75', + token: 'punctuation.definition.tag.begin', + }, + { + foreground: '586e75', + token: 'punctuation.definition.tag.end', + }, + { + foreground: '93a1a1', + token: 'entity.other.attribute-name', + }, + { + foreground: '268bd2', + token: 'support.function', + }, + { + foreground: 'dc322f', + token: 'punctuation.separator.continuation', + }, + { + foreground: '859900', + token: 'support.type', + }, + { + foreground: '859900', + token: 'support.class', + }, + { + foreground: 'cb4b16', + token: 'support.type.exception', + }, + { + foreground: 'cb4b16', + token: 'keyword.other.special-method', + }, + { + foreground: '2aa198', + token: 'string.quoted.double', + }, + { + foreground: '2aa198', + token: 'string.quoted.single', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.string.begin', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.string.end', + }, + { + foreground: 'b58900', + token: 'entity.name.tag.css', + }, + { + foreground: 'b58900', + token: 'support.type.property-name.css', + }, + { + foreground: 'b58900', + token: 'meta.property-name.css', + }, + { + foreground: 'dc322f', + token: 'source.css', + }, + { + foreground: '586e75', + token: 'meta.selector.css', + }, + { + foreground: '6c71c4', + token: 'punctuation.section.property-list.css', + }, + { + foreground: '2aa198', + token: 'meta.property-value.css constant.numeric.css', + }, + { + foreground: '2aa198', + token: 'keyword.other.unit.css', + }, + { + foreground: '2aa198', + token: 'constant.other.color.rgb-value.css', + }, + { + foreground: '2aa198', + token: 'meta.property-value.css', + }, + { + foreground: 'dc322f', + token: 'keyword.other.important.css', + }, + { + foreground: '2aa198', + token: 'support.constant.color', + }, + { + foreground: '859900', + token: 'entity.name.tag.css', + }, + { + foreground: '586e75', + token: 'punctuation.separator.key-value.css', + }, + { + foreground: '586e75', + token: 'punctuation.terminator.rule.css', + }, + { + foreground: '268bd2', + token: 'entity.other.attribute-name.class.css', + }, + { + foreground: 'cb4b16', + token: 'entity.other.attribute-name.pseudo-element.css', + }, + { + foreground: 'cb4b16', + token: 'entity.other.attribute-name.pseudo-class.css', + }, + { + foreground: '268bd2', + token: 'entity.other.attribute-name.id.css', + }, + { + foreground: 'b58900', + token: 'meta.function.js', + }, + { + foreground: 'b58900', + token: 'entity.name.function.js', + }, + { + foreground: 'b58900', + token: 'support.function.dom.js', + }, + { + foreground: 'b58900', + token: 'text.html.basic source.js.embedded.html', + }, + { + foreground: '268bd2', + token: 'storage.type.function.js', + }, + { + foreground: '2aa198', + token: 'constant.numeric.js', + }, + { + foreground: '268bd2', + token: 'meta.brace.square.js', + }, + { + foreground: '268bd2', + token: 'storage.type.js', + }, + { + foreground: '93a1a1', + token: 'meta.brace.round', + }, + { + foreground: '93a1a1', + token: 'punctuation.definition.parameters.begin.js', + }, + { + foreground: '93a1a1', + token: 'punctuation.definition.parameters.end.js', + }, + { + foreground: '268bd2', + token: 'meta.brace.curly.js', + }, + { + foreground: '93a1a1', + fontStyle: 'italic', + token: 'entity.name.tag.doctype.html', + }, + { + foreground: '93a1a1', + fontStyle: 'italic', + token: 'meta.tag.sgml.html', + }, + { + foreground: '93a1a1', + fontStyle: 'italic', + token: 'string.quoted.double.doctype.identifiers-and-DTDs.html', + }, + { + foreground: '839496', + fontStyle: 'italic', + token: 'comment.block.html', + }, + { + fontStyle: 'italic', + token: 'entity.name.tag.script.html', + }, + { + foreground: '2aa198', + token: 'source.css.embedded.html string.quoted.double.html', + }, + { + foreground: 'cb4b16', + fontStyle: 'bold', + token: 'text.html.ruby', + }, + { + foreground: '657b83', + token: 'text.html.basic meta.tag.other.html', + }, + { + foreground: '657b83', + token: 'text.html.basic meta.tag.any.html', + }, + { + foreground: '657b83', + token: 'text.html.basic meta.tag.block.any', + }, + { + foreground: '657b83', + token: 'text.html.basic meta.tag.inline.any', + }, + { + foreground: '657b83', + token: 'text.html.basic meta.tag.structure.any.html', + }, + { + foreground: '657b83', + token: 'text.html.basic source.js.embedded.html', + }, + { + foreground: '657b83', + token: 'punctuation.separator.key-value.html', + }, + { + foreground: '657b83', + token: 'text.html.basic entity.other.attribute-name.html', + }, + { + foreground: '2aa198', + token: 'text.html.basic meta.tag.structure.any.html punctuation.definition.string.begin.html', + }, + { + foreground: '2aa198', + token: 'punctuation.definition.string.begin.html', + }, + { + foreground: '2aa198', + token: 'punctuation.definition.string.end.html', + }, + { + foreground: '268bd2', + fontStyle: 'bold', + token: 'entity.name.tag.block.any.html', + }, + { + fontStyle: 'italic', + token: 'source.css.embedded.html entity.name.tag.style.html', + }, + { + foreground: '839496', + fontStyle: 'italic', + token: 'source.css.embedded.html', + }, + { + foreground: '839496', + fontStyle: 'italic', + token: 'comment.block.html', + }, + { + foreground: '268bd2', + token: 'punctuation.definition.variable.ruby', + }, + { + foreground: '657b83', + token: 'meta.function.method.with-arguments.ruby', + }, + { + foreground: '2aa198', + token: 'variable.language.ruby', + }, + { + foreground: '268bd2', + token: 'entity.name.function.ruby', + }, + { + foreground: '859900', + fontStyle: 'bold', + token: 'keyword.control.ruby', + }, + { + foreground: '859900', + fontStyle: 'bold', + token: 'keyword.control.def.ruby', + }, + { + foreground: '859900', + token: 'keyword.control.class.ruby', + }, + { + foreground: '859900', + token: 'meta.class.ruby', + }, + { + foreground: 'b58900', + token: 'entity.name.type.class.ruby', + }, + { + foreground: '859900', + token: 'keyword.control.ruby', + }, + { + foreground: 'b58900', + token: 'support.class.ruby', + }, + { + foreground: '859900', + token: 'keyword.other.special-method.ruby', + }, + { + foreground: '2aa198', + token: 'constant.language.ruby', + }, + { + foreground: '2aa198', + token: 'constant.numeric.ruby', + }, + { + foreground: 'b58900', + token: 'variable.other.constant.ruby', + }, + { + foreground: '2aa198', + token: 'constant.other.symbol.ruby', + }, + { + foreground: 'dc322f', + token: 'punctuation.section.embedded.ruby', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.string.begin.ruby', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.string.end.ruby', + }, + { + foreground: 'cb4b16', + token: 'keyword.other.special-method.ruby', + }, + { + foreground: 'cb4b16', + token: 'keyword.control.import.include.php', + }, + { + foreground: '839496', + token: 'text.html.ruby meta.tag.inline.any.html', + }, + { + foreground: '2aa198', + token: 'text.html.ruby punctuation.definition.string.begin', + }, + { + foreground: '2aa198', + token: 'text.html.ruby punctuation.definition.string.end', + }, + { + foreground: '839496', + token: 'punctuation.definition.string.begin', + }, + { + foreground: '839496', + token: 'punctuation.definition.string.end', + }, + { + foreground: '839496', + token: 'support.class.php', + }, + { + foreground: 'dc322f', + token: 'keyword.operator.index-start.php', + }, + { + foreground: 'dc322f', + token: 'keyword.operator.index-end.php', + }, + { + foreground: '586e75', + token: 'meta.array.php', + }, + { + foreground: 'b58900', + token: 'meta.array.php support.function.construct.php', + }, + { + foreground: 'b58900', + token: 'meta.array.empty.php support.function.construct.php', + }, + { + foreground: 'b58900', + token: 'support.function.construct.php', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.array.begin', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.array.end', + }, + { + foreground: '2aa198', + token: 'constant.numeric.php', + }, + { + foreground: 'cb4b16', + token: 'keyword.other.new.php', + }, + { + foreground: '839496', + token: 'keyword.operator.class', + }, + { + foreground: '93a1a1', + token: 'variable.other.property.php', + }, + { + foreground: 'b58900', + token: 'storage.modifier.extends.php', + }, + { + foreground: 'b58900', + token: 'storage.type.class.php', + }, + { + foreground: 'b58900', + token: 'keyword.operator.class.php', + }, + { + foreground: '839496', + token: 'punctuation.terminator.expression.php', + }, + { + foreground: '586e75', + token: 'meta.other.inherited-class.php', + }, + { + foreground: '859900', + token: 'storage.type.php', + }, + { + foreground: '93a1a1', + token: 'entity.name.function.php', + }, + { + foreground: '859900', + token: 'support.function.construct.php', + }, + { + foreground: '839496', + token: 'entity.name.type.class.php', + }, + { + foreground: '839496', + token: 'meta.function-call.php', + }, + { + foreground: '839496', + token: 'meta.function-call.static.php', + }, + { + foreground: '839496', + token: 'meta.function-call.object.php', + }, + { + foreground: '93a1a1', + token: 'keyword.other.phpdoc', + }, + { + foreground: 'cb4b16', + token: 'source.php.embedded.block.html', + }, + { + foreground: 'cb4b16', + token: 'storage.type.function.php', + }, + { + foreground: '2aa198', + token: 'constant.numeric.c', + }, + { + foreground: 'cb4b16', + token: 'meta.preprocessor.c.include', + }, + { + foreground: 'cb4b16', + token: 'meta.preprocessor.macro.c', + }, + { + foreground: 'cb4b16', + token: 'keyword.control.import.define.c', + }, + { + foreground: 'cb4b16', + token: 'keyword.control.import.include.c', + }, + { + foreground: 'cb4b16', + token: 'entity.name.function.preprocessor.c', + }, + { + foreground: '2aa198', + token: 'meta.preprocessor.c.include string.quoted.other.lt-gt.include.c', + }, + { + foreground: '2aa198', + token: 'meta.preprocessor.c.include punctuation.definition.string.begin.c', + }, + { + foreground: '2aa198', + token: 'meta.preprocessor.c.include punctuation.definition.string.end.c', + }, + { + foreground: '586e75', + token: 'support.function.C99.c', + }, + { + foreground: '586e75', + token: 'support.function.any-method.c', + }, + { + foreground: '586e75', + token: 'entity.name.function.c', + }, + { + foreground: '2aa198', + token: 'punctuation.definition.string.begin.c', + }, + { + foreground: '2aa198', + token: 'punctuation.definition.string.end.c', + }, + { + foreground: 'b58900', + token: 'storage.type.c', + }, + { + foreground: 'e0eddd', + background: 'b58900', + fontStyle: 'italic', + token: 'meta.diff', + }, + { + foreground: 'e0eddd', + background: 'b58900', + fontStyle: 'italic', + token: 'meta.diff.header', + }, + { + foreground: 'dc322f', + background: 'eee8d5', + token: 'markup.deleted', + }, + { + foreground: 'cb4b16', + background: 'eee8d5', + token: 'markup.changed', + }, + { + foreground: '219186', + background: 'eee8d5', + token: 'markup.inserted', + }, + { + foreground: 'e0eddd', + background: 'b58900', + token: 'text.html.markdown meta.dummy.line-break', + }, + { + foreground: '2aa198', + token: 'text.html.markdown markup.raw.inline', + }, + { + foreground: '2aa198', + token: 'text.restructuredtext markup.raw', + }, + { + foreground: 'dc322f', + token: 'other.package.exclude', + }, + { + foreground: 'dc322f', + token: 'other.remove', + }, + { + foreground: '2aa198', + token: 'other.add', + }, + { + foreground: 'dc322f', + token: 'punctuation.section.group.tex', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.arguments.begin.latex', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.arguments.end.latex', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.arguments.latex', + }, + { + foreground: 'b58900', + token: 'meta.group.braces.tex', + }, + { + foreground: 'b58900', + token: 'string.other.math.tex', + }, + { + foreground: 'cb4b16', + token: 'variable.parameter.function.latex', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.constant.math.tex', + }, + { + foreground: '2aa198', + token: 'text.tex.latex constant.other.math.tex', + }, + { + foreground: '2aa198', + token: 'constant.other.general.math.tex', + }, + { + foreground: '2aa198', + token: 'constant.other.general.math.tex', + }, + { + foreground: '2aa198', + token: 'constant.character.math.tex', + }, + { + foreground: 'b58900', + token: 'string.other.math.tex', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.string.begin.tex', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.string.end.tex', + }, + { + foreground: '2aa198', + token: 'keyword.control.label.latex', + }, + { + foreground: '2aa198', + token: 'text.tex.latex constant.other.general.math.tex', + }, + { + foreground: 'dc322f', + token: 'variable.parameter.definition.label.latex', + }, + { + foreground: '859900', + token: 'support.function.be.latex', + }, + { + foreground: 'cb4b16', + token: 'support.function.section.latex', + }, + { + foreground: '2aa198', + token: 'support.function.general.tex', + }, + { + fontStyle: 'italic', + token: 'punctuation.definition.comment.tex', + }, + { + fontStyle: 'italic', + token: 'comment.line.percentage.tex', + }, + { + foreground: '2aa198', + token: 'keyword.control.ref.latex', + }, + { + foreground: '586e75', + token: 'string.quoted.double.block.python', + }, + { + foreground: '859900', + token: 'storage.type.class.python', + }, + { + foreground: '859900', + token: 'storage.type.function.python', + }, + { + foreground: '859900', + token: 'storage.modifier.global.python', + }, + { + foreground: 'cb4b16', + token: 'keyword.control.import.python', + }, + { + foreground: 'cb4b16', + token: 'keyword.control.import.from.python', + }, + { + foreground: 'b58900', + token: 'support.type.exception.python', + }, + { + foreground: '859900', + token: 'support.function.builtin.shell', + }, + { + foreground: 'cb4b16', + token: 'variable.other.normal.shell', + }, + { + foreground: '268bd2', + token: 'source.shell', + }, + { + foreground: '586e75', + token: 'meta.scope.for-in-loop.shell', + }, + { + foreground: '586e75', + token: 'variable.other.loop.shell', + }, + { + foreground: '859900', + token: 'punctuation.definition.string.end.shell', + }, + { + foreground: '859900', + token: 'punctuation.definition.string.begin.shell', + }, + { + foreground: '586e75', + token: 'meta.scope.case-block.shell', + }, + { + foreground: '586e75', + token: 'meta.scope.case-body.shell', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.logical-expression.shell', + }, + { + fontStyle: 'italic', + token: 'comment.line.number-sign.shell', + }, + { + foreground: 'cb4b16', + token: 'keyword.other.import.java', + }, + { + foreground: '586e75', + token: 'storage.modifier.import.java', + }, + { + foreground: 'b58900', + token: 'meta.class.java storage.modifier.java', + }, + { + foreground: '586e75', + token: 'source.java comment.block', + }, + { + foreground: '586e75', + token: + 'comment.block meta.documentation.tag.param.javadoc keyword.other.documentation.param.javadoc', + }, + { + foreground: 'b58900', + token: 'punctuation.definition.variable.perl', + }, + { + foreground: 'b58900', + token: 'variable.other.readwrite.global.perl', + }, + { + foreground: 'b58900', + token: 'variable.other.predefined.perl', + }, + { + foreground: 'b58900', + token: 'keyword.operator.comparison.perl', + }, + { + foreground: '859900', + token: 'support.function.perl', + }, + { + foreground: '586e75', + fontStyle: 'italic', + token: 'comment.line.number-sign.perl', + }, + { + foreground: '2aa198', + token: 'punctuation.definition.string.begin.perl', + }, + { + foreground: '2aa198', + token: 'punctuation.definition.string.end.perl', + }, + { + foreground: 'dc322f', + token: 'constant.character.escape.perl', + }, + { + foreground: '268bd2', + token: 'markup.heading.markdown', + }, + { + foreground: '268bd2', + token: 'markup.heading.1.markdown', + }, + { + foreground: '268bd2', + token: 'markup.heading.2.markdown', + }, + { + foreground: '268bd2', + token: 'markup.heading.3.markdown', + }, + { + foreground: '268bd2', + token: 'markup.heading.4.markdown', + }, + { + foreground: '268bd2', + token: 'markup.heading.5.markdown', + }, + { + foreground: '268bd2', + token: 'markup.heading.6.markdown', + }, + { + foreground: '839496', + fontStyle: 'bold', + token: 'markup.bold.markdown', + }, + { + foreground: '839496', + fontStyle: 'italic', + token: 'markup.italic.markdown', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.bold.markdown', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.italic.markdown', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.raw.markdown', + }, + { + foreground: 'b58900', + token: 'markup.list.unnumbered.markdown', + }, + { + foreground: '859900', + token: 'markup.list.numbered.markdown', + }, + { + foreground: '2aa198', + token: 'markup.raw.block.markdown', + }, + { + foreground: '2aa198', + token: 'markup.raw.inline.markdown', + }, + { + foreground: '6c71c4', + token: 'markup.quote.markdown', + }, + { + foreground: '6c71c4', + token: 'punctuation.definition.blockquote.markdown', + }, + { + foreground: 'd33682', + token: 'meta.separator.markdown', + }, + { + foreground: '586e75', + fontStyle: 'italic', + token: 'meta.image.inline.markdown', + }, + { + foreground: '586e75', + fontStyle: 'italic', + token: 'markup.underline.link.markdown', + }, + { + foreground: '93a1a1', + token: 'string.other.link.title.markdown', + }, + { + foreground: '93a1a1', + token: 'string.other.link.description.markdown', + }, + { + foreground: '586e75', + token: 'punctuation.definition.link.markdown', + }, + { + foreground: '586e75', + token: 'punctuation.definition.metadata.markdown', + }, + { + foreground: '586e75', + token: 'punctuation.definition.string.begin.markdown', + }, + { + foreground: '586e75', + token: 'punctuation.definition.string.end.markdown', + }, + { + foreground: '586e75', + token: 'punctuation.definition.constant.markdown', + }, + { + foreground: 'eee8d5', + background: 'eee8d5', + token: 'sublimelinter.notes', + }, + { + foreground: '93a1a1', + background: '93a1a1', + token: 'sublimelinter.outline.illegal', + }, + { + background: 'dc322f', + token: 'sublimelinter.underline.illegal', + }, + { + foreground: '839496', + background: '839496', + token: 'sublimelinter.outline.warning', + }, + { + background: 'b58900', + token: 'sublimelinter.underline.warning', + }, + { + foreground: '657b83', + background: '657b83', + token: 'sublimelinter.outline.violation', + }, + { + background: 'cb4b16', + token: 'sublimelinter.underline.violation', + }, + ], + colors: { + 'editor.foreground': '#839496', + 'editor.background': '#002B36', + 'editor.selectionBackground': '#073642', + 'editor.lineHighlightBackground': '#073642', + 'editorCursor.foreground': '#819090', + 'editorWhitespace.foreground': '#073642', + }, +}; diff --git a/app/assets/javascripts/ide/lib/themes/solarized_light.js b/app/assets/javascripts/ide/lib/themes/solarized_light.js new file mode 100644 index 00000000000..b7bfcf33b0f --- /dev/null +++ b/app/assets/javascripts/ide/lib/themes/solarized_light.js @@ -0,0 +1,1101 @@ +/* + +https://github.com/brijeshb42/monaco-themes/blob/master/themes/Solarized-dark.json + +The MIT License (MIT) + +Copyright (c) Brijesh Bittu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ +export default { + base: 'vs', + inherit: true, + rules: [ + { + foreground: '93a1a1', + token: 'comment', + }, + { + foreground: '2aa198', + token: 'string', + }, + { + foreground: '586e75', + token: 'string', + }, + { + foreground: 'dc322f', + token: 'string.regexp', + }, + { + foreground: 'd33682', + token: 'constant.numeric', + }, + { + foreground: '268bd2', + token: 'variable.language', + }, + { + foreground: '268bd2', + token: 'variable.other', + }, + { + foreground: '859900', + token: 'keyword', + }, + { + foreground: '073642', + fontStyle: 'bold', + token: 'storage', + }, + { + foreground: '268bd2', + token: 'entity.name.class', + }, + { + foreground: '268bd2', + token: 'entity.name.type.class', + }, + { + foreground: '268bd2', + token: 'entity.name.function', + }, + { + foreground: '859900', + token: 'punctuation.definition.variable', + }, + { + foreground: 'dc322f', + token: 'punctuation.section.embedded.begin', + }, + { + foreground: 'dc322f', + token: 'punctuation.section.embedded.end', + }, + { + foreground: 'b58900', + token: 'constant.language', + }, + { + foreground: 'b58900', + token: 'meta.preprocessor', + }, + { + foreground: 'dc322f', + token: 'support.function.construct', + }, + { + foreground: 'dc322f', + token: 'keyword.other.new', + }, + { + foreground: 'cb4b16', + token: 'constant.character', + }, + { + foreground: 'cb4b16', + token: 'constant.other', + }, + { + foreground: '268bd2', + fontStyle: 'bold', + token: 'entity.name.tag', + }, + { + foreground: '93a1a1', + token: 'punctuation.definition.tag.html', + }, + { + foreground: '93a1a1', + token: 'punctuation.definition.tag.begin', + }, + { + foreground: '93a1a1', + token: 'punctuation.definition.tag.end', + }, + { + foreground: '93a1a1', + token: 'entity.other.attribute-name', + }, + { + foreground: '268bd2', + token: 'support.function', + }, + { + foreground: 'dc322f', + token: 'punctuation.separator.continuation', + }, + { + foreground: '859900', + token: 'support.type', + }, + { + foreground: '859900', + token: 'support.class', + }, + { + foreground: 'cb4b16', + token: 'support.type.exception', + }, + { + foreground: 'cb4b16', + token: 'keyword.other.special-method', + }, + { + foreground: '2aa198', + token: 'string.quoted.double', + }, + { + foreground: '2aa198', + token: 'string.quoted.single', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.string.begin', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.string.end', + }, + { + foreground: 'b58900', + token: 'entity.name.tag.css', + }, + { + foreground: 'b58900', + token: 'support.type.property-name.css', + }, + { + foreground: 'b58900', + token: 'meta.property-name.css', + }, + { + foreground: 'dc322f', + token: 'source.css', + }, + { + foreground: '586e75', + token: 'meta.selector.css', + }, + { + foreground: '6c71c4', + token: 'punctuation.section.property-list.css', + }, + { + foreground: '2aa198', + token: 'meta.property-value.css constant.numeric.css', + }, + { + foreground: '2aa198', + token: 'keyword.other.unit.css', + }, + { + foreground: '2aa198', + token: 'constant.other.color.rgb-value.css', + }, + { + foreground: '2aa198', + token: 'meta.property-value.css', + }, + { + foreground: 'dc322f', + token: 'keyword.other.important.css', + }, + { + foreground: '2aa198', + token: 'support.constant.color', + }, + { + foreground: '859900', + token: 'entity.name.tag.css', + }, + { + foreground: '586e75', + token: 'punctuation.separator.key-value.css', + }, + { + foreground: '586e75', + token: 'punctuation.terminator.rule.css', + }, + { + foreground: '268bd2', + token: 'entity.other.attribute-name.class.css', + }, + { + foreground: 'cb4b16', + token: 'entity.other.attribute-name.pseudo-element.css', + }, + { + foreground: 'cb4b16', + token: 'entity.other.attribute-name.pseudo-class.css', + }, + { + foreground: '268bd2', + token: 'entity.other.attribute-name.id.css', + }, + { + foreground: 'b58900', + token: 'meta.function.js', + }, + { + foreground: 'b58900', + token: 'entity.name.function.js', + }, + { + foreground: 'b58900', + token: 'support.function.dom.js', + }, + { + foreground: 'b58900', + token: 'text.html.basic source.js.embedded.html', + }, + { + foreground: '268bd2', + token: 'storage.type.function.js', + }, + { + foreground: '2aa198', + token: 'constant.numeric.js', + }, + { + foreground: '268bd2', + token: 'meta.brace.square.js', + }, + { + foreground: '268bd2', + token: 'storage.type.js', + }, + { + foreground: '93a1a1', + token: 'meta.brace.round', + }, + { + foreground: '93a1a1', + token: 'punctuation.definition.parameters.begin.js', + }, + { + foreground: '93a1a1', + token: 'punctuation.definition.parameters.end.js', + }, + { + foreground: '268bd2', + token: 'meta.brace.curly.js', + }, + { + foreground: '93a1a1', + fontStyle: 'italic', + token: 'entity.name.tag.doctype.html', + }, + { + foreground: '93a1a1', + fontStyle: 'italic', + token: 'meta.tag.sgml.html', + }, + { + foreground: '93a1a1', + fontStyle: 'italic', + token: 'string.quoted.double.doctype.identifiers-and-DTDs.html', + }, + { + foreground: '839496', + fontStyle: 'italic', + token: 'comment.block.html', + }, + { + fontStyle: 'italic', + token: 'entity.name.tag.script.html', + }, + { + foreground: '2aa198', + token: 'source.css.embedded.html string.quoted.double.html', + }, + { + foreground: 'cb4b16', + fontStyle: 'bold', + token: 'text.html.ruby', + }, + { + foreground: '657b83', + token: 'text.html.basic meta.tag.other.html', + }, + { + foreground: '657b83', + token: 'text.html.basic meta.tag.any.html', + }, + { + foreground: '657b83', + token: 'text.html.basic meta.tag.block.any', + }, + { + foreground: '657b83', + token: 'text.html.basic meta.tag.inline.any', + }, + { + foreground: '657b83', + token: 'text.html.basic meta.tag.structure.any.html', + }, + { + foreground: '657b83', + token: 'text.html.basic source.js.embedded.html', + }, + { + foreground: '657b83', + token: 'punctuation.separator.key-value.html', + }, + { + foreground: '657b83', + token: 'text.html.basic entity.other.attribute-name.html', + }, + { + foreground: '2aa198', + token: 'text.html.basic meta.tag.structure.any.html punctuation.definition.string.begin.html', + }, + { + foreground: '2aa198', + token: 'punctuation.definition.string.begin.html', + }, + { + foreground: '2aa198', + token: 'punctuation.definition.string.end.html', + }, + { + foreground: '268bd2', + fontStyle: 'bold', + token: 'entity.name.tag.block.any.html', + }, + { + fontStyle: 'italic', + token: 'source.css.embedded.html entity.name.tag.style.html', + }, + { + foreground: '839496', + fontStyle: 'italic', + token: 'source.css.embedded.html', + }, + { + foreground: '839496', + fontStyle: 'italic', + token: 'comment.block.html', + }, + { + foreground: '268bd2', + token: 'punctuation.definition.variable.ruby', + }, + { + foreground: '657b83', + token: 'meta.function.method.with-arguments.ruby', + }, + { + foreground: '2aa198', + token: 'variable.language.ruby', + }, + { + foreground: '268bd2', + token: 'entity.name.function.ruby', + }, + { + foreground: '859900', + fontStyle: 'bold', + token: 'keyword.control.ruby', + }, + { + foreground: '859900', + fontStyle: 'bold', + token: 'keyword.control.def.ruby', + }, + { + foreground: '859900', + token: 'keyword.control.class.ruby', + }, + { + foreground: '859900', + token: 'meta.class.ruby', + }, + { + foreground: 'b58900', + token: 'entity.name.type.class.ruby', + }, + { + foreground: '859900', + token: 'keyword.control.ruby', + }, + { + foreground: 'b58900', + token: 'support.class.ruby', + }, + { + foreground: '859900', + token: 'keyword.other.special-method.ruby', + }, + { + foreground: '2aa198', + token: 'constant.language.ruby', + }, + { + foreground: '2aa198', + token: 'constant.numeric.ruby', + }, + { + foreground: 'b58900', + token: 'variable.other.constant.ruby', + }, + { + foreground: '2aa198', + token: 'constant.other.symbol.ruby', + }, + { + foreground: 'dc322f', + token: 'punctuation.section.embedded.ruby', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.string.begin.ruby', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.string.end.ruby', + }, + { + foreground: 'cb4b16', + token: 'keyword.other.special-method.ruby', + }, + { + foreground: 'cb4b16', + token: 'keyword.control.import.include.php', + }, + { + foreground: '839496', + token: 'text.html.ruby meta.tag.inline.any.html', + }, + { + foreground: '2aa198', + token: 'text.html.ruby punctuation.definition.string.begin', + }, + { + foreground: '2aa198', + token: 'text.html.ruby punctuation.definition.string.end', + }, + { + foreground: '839496', + token: 'punctuation.definition.string.begin', + }, + { + foreground: '839496', + token: 'punctuation.definition.string.end', + }, + { + foreground: 'dc322f', + token: 'keyword.operator.index-start.php', + }, + { + foreground: 'dc322f', + token: 'keyword.operator.index-end.php', + }, + { + foreground: '586e75', + token: 'meta.array.php', + }, + { + foreground: 'b58900', + token: 'meta.array.php support.function.construct.php', + }, + { + foreground: 'b58900', + token: 'meta.array.empty.php support.function.construct.php', + }, + { + foreground: 'b58900', + token: 'support.function.construct.php', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.array.begin', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.array.end', + }, + { + foreground: '2aa198', + token: 'constant.numeric.php', + }, + { + foreground: 'cb4b16', + token: 'keyword.other.new.php', + }, + { + foreground: '586e75', + token: 'support.class.php', + }, + { + foreground: '586e75', + token: 'keyword.operator.class', + }, + { + foreground: '93a1a1', + token: 'variable.other.property.php', + }, + { + foreground: 'b58900', + token: 'storage.modifier.extends.php', + }, + { + foreground: 'b58900', + token: 'storage.type.class.php', + }, + { + foreground: 'b58900', + token: 'keyword.operator.class.php', + }, + { + foreground: '586e75', + token: 'meta.other.inherited-class.php', + }, + { + foreground: '859900', + token: 'storage.type.php', + }, + { + foreground: '93a1a1', + token: 'entity.name.function.php', + }, + { + foreground: '859900', + token: 'support.function.construct.php', + }, + { + foreground: '839496', + token: 'entity.name.type.class.php', + }, + { + foreground: '839496', + token: 'meta.function-call.php', + }, + { + foreground: '839496', + token: 'meta.function-call.static.php', + }, + { + foreground: '839496', + token: 'meta.function-call.object.php', + }, + { + foreground: '93a1a1', + token: 'keyword.other.phpdoc', + }, + { + foreground: 'cb4b16', + token: 'source.php.embedded.block.html', + }, + { + foreground: 'cb4b16', + token: 'storage.type.function.php', + }, + { + foreground: '2aa198', + token: 'constant.numeric.c', + }, + { + foreground: 'cb4b16', + token: 'meta.preprocessor.c.include', + }, + { + foreground: 'cb4b16', + token: 'meta.preprocessor.macro.c', + }, + { + foreground: 'cb4b16', + token: 'keyword.control.import.define.c', + }, + { + foreground: 'cb4b16', + token: 'keyword.control.import.include.c', + }, + { + foreground: 'cb4b16', + token: 'entity.name.function.preprocessor.c', + }, + { + foreground: '2aa198', + token: 'meta.preprocessor.c.include string.quoted.other.lt-gt.include.c', + }, + { + foreground: '2aa198', + token: 'meta.preprocessor.c.include punctuation.definition.string.begin.c', + }, + { + foreground: '2aa198', + token: 'meta.preprocessor.c.include punctuation.definition.string.end.c', + }, + { + foreground: '586e75', + token: 'support.function.C99.c', + }, + { + foreground: '586e75', + token: 'support.function.any-method.c', + }, + { + foreground: '586e75', + token: 'entity.name.function.c', + }, + { + foreground: '2aa198', + token: 'punctuation.definition.string.begin.c', + }, + { + foreground: '2aa198', + token: 'punctuation.definition.string.end.c', + }, + { + foreground: 'b58900', + token: 'storage.type.c', + }, + { + foreground: 'e0eddd', + background: 'b58900', + fontStyle: 'italic', + token: 'meta.diff', + }, + { + foreground: 'e0eddd', + background: 'b58900', + fontStyle: 'italic', + token: 'meta.diff.header', + }, + { + foreground: 'dc322f', + background: 'eee8d5', + token: 'markup.deleted', + }, + { + foreground: 'cb4b16', + background: 'eee8d5', + token: 'markup.changed', + }, + { + foreground: '219186', + background: 'eee8d5', + token: 'markup.inserted', + }, + { + foreground: 'e0eddd', + background: 'a57706', + token: 'text.html.markdown meta.dummy.line-break', + }, + { + foreground: '2aa198', + token: 'text.html.markdown markup.raw.inline', + }, + { + foreground: '2aa198', + token: 'text.restructuredtext markup.raw', + }, + { + foreground: 'dc322f', + token: 'other.package.exclude', + }, + { + foreground: 'dc322f', + token: 'other.remove', + }, + { + foreground: '2aa198', + token: 'other.add', + }, + { + foreground: 'dc322f', + token: 'punctuation.section.group.tex', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.arguments.begin.latex', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.arguments.end.latex', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.arguments.latex', + }, + { + foreground: 'b58900', + token: 'meta.group.braces.tex', + }, + { + foreground: 'b58900', + token: 'string.other.math.tex', + }, + { + foreground: 'cb4b16', + token: 'variable.parameter.function.latex', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.constant.math.tex', + }, + { + foreground: '2aa198', + token: 'text.tex.latex constant.other.math.tex', + }, + { + foreground: '2aa198', + token: 'constant.other.general.math.tex', + }, + { + foreground: '2aa198', + token: 'constant.other.general.math.tex', + }, + { + foreground: '2aa198', + token: 'constant.character.math.tex', + }, + { + foreground: 'b58900', + token: 'string.other.math.tex', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.string.begin.tex', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.string.end.tex', + }, + { + foreground: '2aa198', + token: 'keyword.control.label.latex', + }, + { + foreground: '2aa198', + token: 'text.tex.latex constant.other.general.math.tex', + }, + { + foreground: 'dc322f', + token: 'variable.parameter.definition.label.latex', + }, + { + foreground: '859900', + token: 'support.function.be.latex', + }, + { + foreground: 'cb4b16', + token: 'support.function.section.latex', + }, + { + foreground: '2aa198', + token: 'support.function.general.tex', + }, + { + fontStyle: 'italic', + token: 'punctuation.definition.comment.tex', + }, + { + fontStyle: 'italic', + token: 'comment.line.percentage.tex', + }, + { + foreground: '2aa198', + token: 'keyword.control.ref.latex', + }, + { + foreground: '586e75', + token: 'string.quoted.double.block.python', + }, + { + foreground: '859900', + token: 'storage.type.class.python', + }, + { + foreground: '859900', + token: 'storage.type.function.python', + }, + { + foreground: '859900', + token: 'storage.modifier.global.python', + }, + { + foreground: 'cb4b16', + token: 'keyword.control.import.python', + }, + { + foreground: 'cb4b16', + token: 'keyword.control.import.from.python', + }, + { + foreground: 'b58900', + token: 'support.type.exception.python', + }, + { + foreground: '859900', + token: 'support.function.builtin.shell', + }, + { + foreground: 'cb4b16', + token: 'variable.other.normal.shell', + }, + { + foreground: '268bd2', + token: 'source.shell', + }, + { + foreground: '586e75', + token: 'meta.scope.for-in-loop.shell', + }, + { + foreground: '586e75', + token: 'variable.other.loop.shell', + }, + { + foreground: '859900', + token: 'punctuation.definition.string.end.shell', + }, + { + foreground: '859900', + token: 'punctuation.definition.string.begin.shell', + }, + { + foreground: '586e75', + token: 'meta.scope.case-block.shell', + }, + { + foreground: '586e75', + token: 'meta.scope.case-body.shell', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.logical-expression.shell', + }, + { + fontStyle: 'italic', + token: 'comment.line.number-sign.shell', + }, + { + foreground: 'cb4b16', + token: 'keyword.other.import.java', + }, + { + foreground: '586e75', + token: 'storage.modifier.import.java', + }, + { + foreground: 'b58900', + token: 'meta.class.java storage.modifier.java', + }, + { + foreground: '586e75', + token: 'source.java comment.block', + }, + { + foreground: '586e75', + token: + 'comment.block meta.documentation.tag.param.javadoc keyword.other.documentation.param.javadoc', + }, + { + foreground: 'b58900', + token: 'punctuation.definition.variable.perl', + }, + { + foreground: 'b58900', + token: 'variable.other.readwrite.global.perl', + }, + { + foreground: 'b58900', + token: 'variable.other.predefined.perl', + }, + { + foreground: 'b58900', + token: 'keyword.operator.comparison.perl', + }, + { + foreground: '859900', + token: 'support.function.perl', + }, + { + foreground: '586e75', + fontStyle: 'italic', + token: 'comment.line.number-sign.perl', + }, + { + foreground: '2aa198', + token: 'punctuation.definition.string.begin.perl', + }, + { + foreground: '2aa198', + token: 'punctuation.definition.string.end.perl', + }, + { + foreground: 'dc322f', + token: 'constant.character.escape.perl', + }, + { + foreground: '268bd2', + token: 'markup.heading.markdown', + }, + { + foreground: '268bd2', + token: 'markup.heading.1.markdown', + }, + { + foreground: '268bd2', + token: 'markup.heading.2.markdown', + }, + { + foreground: '268bd2', + token: 'markup.heading.3.markdown', + }, + { + foreground: '268bd2', + token: 'markup.heading.4.markdown', + }, + { + foreground: '268bd2', + token: 'markup.heading.5.markdown', + }, + { + foreground: '268bd2', + token: 'markup.heading.6.markdown', + }, + { + foreground: '586e75', + fontStyle: 'bold', + token: 'markup.bold.markdown', + }, + { + foreground: '586e75', + fontStyle: 'italic', + token: 'markup.italic.markdown', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.bold.markdown', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.italic.markdown', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.raw.markdown', + }, + { + foreground: 'b58900', + token: 'markup.list.unnumbered.markdown', + }, + { + foreground: '859900', + token: 'markup.list.numbered.markdown', + }, + { + foreground: '2aa198', + token: 'markup.raw.block.markdown', + }, + { + foreground: '2aa198', + token: 'markup.raw.inline.markdown', + }, + { + foreground: '6c71c4', + token: 'markup.quote.markdown', + }, + { + foreground: '6c71c4', + token: 'punctuation.definition.blockquote.markdown', + }, + { + foreground: 'd33682', + token: 'meta.separator.markdown', + }, + { + foreground: '839496', + token: 'markup.underline.link.markdown', + }, + { + foreground: '839496', + token: 'markup.underline.link.markdown', + }, + { + foreground: 'dc322f', + token: 'meta.link.inet.markdown', + }, + { + foreground: 'dc322f', + token: 'meta.link.email.lt-gt.markdown', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.string.begin.markdown', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.string.end.markdown', + }, + { + foreground: 'dc322f', + token: 'punctuation.definition.link.markdown', + }, + { + foreground: '6a8187', + token: 'text.plain', + }, + { + foreground: 'eee8d5', + background: 'eee8d5', + token: 'sublimelinter.notes', + }, + { + foreground: '93a1a1', + background: '93a1a1', + token: 'sublimelinter.outline.illegal', + }, + { + background: 'dc322f', + token: 'sublimelinter.underline.illegal', + }, + { + foreground: '839496', + background: '839496', + token: 'sublimelinter.outline.warning', + }, + { + background: 'b58900', + token: 'sublimelinter.underline.warning', + }, + { + foreground: '657b83', + background: '657b83', + token: 'sublimelinter.outline.violation', + }, + { + background: 'cb4b16', + token: 'sublimelinter.underline.violation', + }, + ], + colors: { + 'editor.foreground': '#586E75', + 'editor.background': '#FDF6E3', + 'editor.selectionBackground': '#EEE8D5', + 'editor.lineHighlightBackground': '#EEE8D5', + 'editorCursor.foreground': '#000000', + 'editorWhitespace.foreground': '#EAE3C9', + }, +}; diff --git a/app/assets/javascripts/ide/services/index.js b/app/assets/javascripts/ide/services/index.js index 3adf0cf073f..1767d961259 100644 --- a/app/assets/javascripts/ide/services/index.js +++ b/app/assets/javascripts/ide/services/index.js @@ -88,12 +88,16 @@ export default { commit(projectId, payload) { return Api.commitMultiple(projectId, payload); }, - getFiles(projectUrl, ref) { - const url = `${projectUrl}/-/files/${ref}`; + getFiles(projectPath, ref) { + const url = `${gon.relative_url_root}/${projectPath}/-/files/${ref}`; return axios.get(url, { params: { format: 'json' } }); }, lastCommitPipelines({ getters }) { const commitSha = getters.lastCommit.id; return Api.commitPipelines(getters.currentProject.path_with_namespace, commitSha); }, + pingUsage(projectPath) { + const url = `${gon.relative_url_root}/${projectPath}/usage_ping/web_ide_pipelines_count`; + return axios.post(url); + }, }; diff --git a/app/assets/javascripts/ide/stores/actions.js b/app/assets/javascripts/ide/stores/actions.js index 04cf0ad53d5..e32b5ac7bdc 100644 --- a/app/assets/javascripts/ide/stores/actions.js +++ b/app/assets/javascripts/ide/stores/actions.js @@ -1,6 +1,5 @@ -import $ from 'jquery'; import Vue from 'vue'; -import { escape as esc } from 'lodash'; +import { escape } from 'lodash'; import { __, sprintf } from '~/locale'; import { visitUrl } from '~/lib/utils/url_utility'; import flash from '~/flash'; @@ -25,14 +24,6 @@ export const closeAllFiles = ({ state, dispatch }) => { state.openFiles.forEach(file => dispatch('closeFile', file)); }; -export const setPanelCollapsedStatus = ({ commit }, { side, collapsed }) => { - if (side === 'left') { - commit(types.SET_LEFT_PANEL_COLLAPSED, collapsed); - } else { - commit(types.SET_RIGHT_PANEL_COLLAPSED, collapsed); - } -}; - export const setResizingStatus = ({ commit }, resizing) => { commit(types.SET_RESIZING_STATUS, resizing); }; @@ -176,13 +167,6 @@ export const setLinks = ({ commit }, links) => commit(types.SET_LINKS, links); export const setErrorMessage = ({ commit }, errorMessage) => commit(types.SET_ERROR_MESSAGE, errorMessage); -export const openNewEntryModal = ({ commit }, { type, path = '' }) => { - commit(types.OPEN_NEW_ENTRY_MODAL, { type, path }); - - // open the modal manually so we don't mess around with dropdown/rows - $('#ide-new-entry').modal('show'); -}; - export const deleteEntry = ({ commit, dispatch, state }, path) => { const entry = state.entries[path]; const { prevPath, prevName, prevParentPath } = entry; @@ -296,7 +280,7 @@ export const getBranchData = ({ commit, state }, { projectId, branchId, force = sprintf( __('Branch not loaded - %{branchId}'), { - branchId: `<strong>${esc(projectId)}/${esc(branchId)}</strong>`, + branchId: `<strong>${escape(projectId)}/${escape(branchId)}</strong>`, }, false, ), diff --git a/app/assets/javascripts/ide/stores/actions/project.js b/app/assets/javascripts/ide/stores/actions/project.js index ae3829dc35e..6c8fb9f90aa 100644 --- a/app/assets/javascripts/ide/stores/actions/project.js +++ b/app/assets/javascripts/ide/stores/actions/project.js @@ -1,4 +1,4 @@ -import { escape as esc } from 'lodash'; +import { escape } from 'lodash'; import flash from '~/flash'; import { __, sprintf } from '~/locale'; import service from '../../services'; @@ -73,7 +73,7 @@ export const showBranchNotFoundError = ({ dispatch }, branchId) => { text: sprintf( __("Branch %{branchName} was not found in this project's repository."), { - branchName: `<strong>${esc(branchId)}</strong>`, + branchName: `<strong>${escape(branchId)}</strong>`, }, false, ), @@ -162,7 +162,7 @@ export const openBranch = ({ dispatch }, { projectId, branchId, basePath }) => { sprintf( __('An error occurred while getting files for - %{branchId}'), { - branchId: `<strong>${esc(projectId)}/${esc(branchId)}</strong>`, + branchId: `<strong>${escape(projectId)}/${escape(branchId)}</strong>`, }, false, ), diff --git a/app/assets/javascripts/ide/stores/actions/tree.js b/app/assets/javascripts/ide/stores/actions/tree.js index 7d48f0adc4c..1ca608f1287 100644 --- a/app/assets/javascripts/ide/stores/actions/tree.js +++ b/app/assets/javascripts/ide/stores/actions/tree.js @@ -59,7 +59,7 @@ export const getFiles = ({ state, commit, dispatch }, payload = {}) => commit(types.CREATE_TREE, { treePath: `${projectId}/${branchId}` }); service - .getFiles(selectedProject.web_url, ref) + .getFiles(selectedProject.path_with_namespace, ref) .then(({ data }) => { const { entries, treeList } = decorateFiles({ data, diff --git a/app/assets/javascripts/ide/stores/modules/commit/actions.js b/app/assets/javascripts/ide/stores/modules/commit/actions.js index 505daa8834d..592c7e15918 100644 --- a/app/assets/javascripts/ide/stores/modules/commit/actions.js +++ b/app/assets/javascripts/ide/stores/modules/commit/actions.js @@ -1,6 +1,6 @@ -import $ from 'jquery'; import { sprintf, __ } from '~/locale'; import flash from '~/flash'; +import httpStatusCodes from '~/lib/utils/http_status'; import * as rootTypes from '../../mutation_types'; import { createCommitPayload, createNewMergeRequestUrl } from '../../utils'; import router from '../../../ide_router'; @@ -215,25 +215,23 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo ); }) .catch(err => { - if (err.response.status === 400) { - $('#ide-create-branch-modal').modal('show'); - } else { - dispatch( - 'setErrorMessage', - { - text: __('An error occurred while committing your changes.'), - action: () => - dispatch('commitChanges').then(() => - dispatch('setErrorMessage', null, { root: true }), - ), - actionText: __('Please try again'), - }, - { root: true }, - ); - window.dispatchEvent(new Event('resize')); - } - commit(types.UPDATE_LOADING, false); + + // don't catch bad request errors, let the view handle them + if (err.response.status === httpStatusCodes.BAD_REQUEST) throw err; + + dispatch( + 'setErrorMessage', + { + text: __('An error occurred while committing your changes.'), + action: () => + dispatch('commitChanges').then(() => dispatch('setErrorMessage', null, { root: true })), + actionText: __('Please try again'), + }, + { root: true }, + ); + + window.dispatchEvent(new Event('resize')); }); }; diff --git a/app/assets/javascripts/ide/stores/mutation_types.js b/app/assets/javascripts/ide/stores/mutation_types.js index 78831bdf022..5c78bfefa04 100644 --- a/app/assets/javascripts/ide/stores/mutation_types.js +++ b/app/assets/javascripts/ide/stores/mutation_types.js @@ -2,8 +2,6 @@ export const SET_INITIAL_DATA = 'SET_INITIAL_DATA'; export const TOGGLE_LOADING = 'TOGGLE_LOADING'; export const SET_LAST_COMMIT_DATA = 'SET_LAST_COMMIT_DATA'; export const SET_LAST_COMMIT_MSG = 'SET_LAST_COMMIT_MSG'; -export const SET_LEFT_PANEL_COLLAPSED = 'SET_LEFT_PANEL_COLLAPSED'; -export const SET_RIGHT_PANEL_COLLAPSED = 'SET_RIGHT_PANEL_COLLAPSED'; export const SET_RESIZING_STATUS = 'SET_RESIZING_STATUS'; export const SET_EMPTY_STATE_SVGS = 'SET_EMPTY_STATE_SVGS'; export const SET_LINKS = 'SET_LINKS'; @@ -73,7 +71,6 @@ export const RESET_OPEN_FILES = 'RESET_OPEN_FILES'; export const SET_ERROR_MESSAGE = 'SET_ERROR_MESSAGE'; -export const OPEN_NEW_ENTRY_MODAL = 'OPEN_NEW_ENTRY_MODAL'; export const DELETE_ENTRY = 'DELETE_ENTRY'; export const RENAME_ENTRY = 'RENAME_ENTRY'; export const REVERT_RENAME_ENTRY = 'REVERT_RENAME_ENTRY'; diff --git a/app/assets/javascripts/ide/stores/mutations.js b/app/assets/javascripts/ide/stores/mutations.js index 5d567d9b169..12ac10df206 100644 --- a/app/assets/javascripts/ide/stores/mutations.js +++ b/app/assets/javascripts/ide/stores/mutations.js @@ -29,16 +29,6 @@ export default { }); } }, - [types.SET_LEFT_PANEL_COLLAPSED](state, collapsed) { - Object.assign(state, { - leftPanelCollapsed: collapsed, - }); - }, - [types.SET_RIGHT_PANEL_COLLAPSED](state, collapsed) { - Object.assign(state, { - rightPanelCollapsed: collapsed, - }); - }, [types.SET_RESIZING_STATUS](state, resizing) { Object.assign(state, { panelResizing: resizing, @@ -192,15 +182,6 @@ export default { [types.SET_ERROR_MESSAGE](state, errorMessage) { Object.assign(state, { errorMessage }); }, - [types.OPEN_NEW_ENTRY_MODAL](state, { type, path }) { - Object.assign(state, { - entryModal: { - type, - path, - entry: { ...state.entries[path] }, - }, - }); - }, [types.DELETE_ENTRY](state, path) { const entry = state.entries[path]; const { tempFile = false } = entry; diff --git a/app/assets/javascripts/ide/stores/mutations/project.js b/app/assets/javascripts/ide/stores/mutations/project.js index 9230f3839c1..034fdad4305 100644 --- a/app/assets/javascripts/ide/stores/mutations/project.js +++ b/app/assets/javascripts/ide/stores/mutations/project.js @@ -16,9 +16,7 @@ export default { }); Object.assign(state, { - projects: Object.assign({}, state.projects, { - [projectPath]: project, - }), + projects: { ...state.projects, [projectPath]: project }, }); }, [types.TOGGLE_EMPTY_STATE](state, { projectPath, value }) { diff --git a/app/assets/javascripts/ide/stores/mutations/tree.js b/app/assets/javascripts/ide/stores/mutations/tree.js index 359943b4ab7..c8f14a680c2 100644 --- a/app/assets/javascripts/ide/stores/mutations/tree.js +++ b/app/assets/javascripts/ide/stores/mutations/tree.js @@ -14,12 +14,13 @@ export default { }, [types.CREATE_TREE](state, { treePath }) { Object.assign(state, { - trees: Object.assign({}, state.trees, { + trees: { + ...state.trees, [treePath]: { tree: [], loading: true, }, - }), + }, }); }, [types.SET_DIRECTORY_DATA](state, { data, treePath }) { diff --git a/app/assets/javascripts/ide/stores/state.js b/app/assets/javascripts/ide/stores/state.js index 0fd6a448283..0c95c22e8f8 100644 --- a/app/assets/javascripts/ide/stores/state.js +++ b/app/assets/javascripts/ide/stores/state.js @@ -15,8 +15,6 @@ export default () => ({ parentTreeUrl: '', trees: {}, projects: {}, - leftPanelCollapsed: false, - rightPanelCollapsed: false, panelResizing: false, entries: {}, viewer: viewerTypes.edit, diff --git a/app/assets/javascripts/ide/stores/utils.js b/app/assets/javascripts/ide/stores/utils.js index 4e5b01596d8..56671142bd4 100644 --- a/app/assets/javascripts/ide/stores/utils.js +++ b/app/assets/javascripts/ide/stores/utils.js @@ -1,4 +1,5 @@ import { commitActionTypes, FILE_VIEW_MODE_EDITOR } from '../constants'; +import { relativePathToAbsolute, isAbsolute, isRootRelative } from '~/lib/utils/url_utility'; export const dataStructure = () => ({ id: '', @@ -274,3 +275,45 @@ export const pathsAreEqual = (a, b) => { // if the contents of a file dont end with a newline, this function adds a newline export const addFinalNewlineIfNeeded = content => content.charAt(content.length - 1) !== '\n' ? `${content}\n` : content; + +export function extractMarkdownImagesFromEntries(mdFile, entries) { + /** + * Regex to identify an image tag in markdown, like: + * + * ![img alt goes here](/img.png) + * ![img alt](../img 1/img.png "my image title") + * ![img alt](https://gitlab.com/assets/logo.svg "title here") + * + */ + const reMdImage = /!\[([^\]]*)\]\((.*?)(?:(?="|\))"([^"]*)")?\)/gi; + const prefix = 'gl_md_img_'; + const images = {}; + + let content = mdFile.content || mdFile.raw; + let i = 0; + + content = content.replace(reMdImage, (_, alt, path, title) => { + const imagePath = (isRootRelative(path) ? path : relativePathToAbsolute(path, mdFile.path)) + .substr(1) + .trim(); + + const imageContent = entries[imagePath]?.content || entries[imagePath]?.raw; + + if (!isAbsolute(path) && imageContent) { + const ext = path.includes('.') + ? path + .split('.') + .pop() + .trim() + : 'jpeg'; + const src = `data:image/${ext};base64,${imageContent}`; + i += 1; + const key = `{{${prefix}${i}}}`; + images[key] = { alt, src, title }; + return key; + } + return title ? `![${alt}](${path}"${title}")` : `![${alt}](${path})`; + }); + + return { content, images }; +} diff --git a/app/assets/javascripts/ide/utils.js b/app/assets/javascripts/ide/utils.js index 64ac539a4ff..1ea2b199237 100644 --- a/app/assets/javascripts/ide/utils.js +++ b/app/assets/javascripts/ide/utils.js @@ -68,3 +68,19 @@ export const createPathWithExt = p => { return `${p.substring(1, p.lastIndexOf('.') + 1 || p.length)}${ext || '.js'}`; }; + +export const trimPathComponents = path => + path + .split('/') + .map(s => s.trim()) + .join('/'); + +export function registerLanguages(def, ...defs) { + if (defs.length) defs.forEach(lang => registerLanguages(lang)); + + const languageId = def.id; + + languages.register(def); + languages.setMonarchTokensProvider(languageId, def.language); + languages.setLanguageConfiguration(languageId, def.conf); +} |