Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorNick Thomas <nick@gitlab.com>2018-10-03 02:00:38 +0300
committerNick Thomas <nick@gitlab.com>2018-10-05 13:34:43 +0300
commit25bd49e4f57fe15f9d61dc9376a5b7dc35b30f64 (patch)
treefaef4e9d73e9845413462013c868eace19a11abf /app
parentae014e189773f7299c12c1050334b3e8fe7b15d8 (diff)
Backport project template API to CE
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/api.js51
-rw-r--r--app/assets/javascripts/blob/file_template_mediator.js42
-rw-r--r--app/assets/javascripts/blob/template_selector.js3
-rw-r--r--app/assets/javascripts/blob/template_selectors/ci_yaml_selector.js4
-rw-r--r--app/assets/javascripts/blob/template_selectors/dockerfile_selector.js4
-rw-r--r--app/assets/javascripts/blob/template_selectors/gitignore_selector.js4
-rw-r--r--app/assets/javascripts/blob/template_selectors/license_selector.js4
-rw-r--r--app/assets/javascripts/blob_edit/blob_bundle.js3
-rw-r--r--app/assets/javascripts/blob_edit/edit_blob.js24
-rw-r--r--app/assets/javascripts/ide/stores/modules/file_templates/actions.js12
-rw-r--r--app/finders/license_template_finder.rb40
-rw-r--r--app/finders/template_finder.rb19
-rw-r--r--app/helpers/blob_helper.rb27
-rw-r--r--app/models/license_template.rb8
14 files changed, 122 insertions, 123 deletions
diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js
index ecc2440c7e6..3f7a1ef1bfc 100644
--- a/app/assets/javascripts/api.js
+++ b/app/assets/javascripts/api.js
@@ -15,12 +15,9 @@ const Api = {
mergeRequestChangesPath: '/api/:version/projects/:id/merge_requests/:mrid/changes',
mergeRequestVersionsPath: '/api/:version/projects/:id/merge_requests/:mrid/versions',
groupLabelsPath: '/groups/:namespace_path/-/labels',
- templatesPath: '/api/:version/templates/:key',
- licensePath: '/api/:version/templates/licenses/:key',
- gitignorePath: '/api/:version/templates/gitignores/:key',
- gitlabCiYmlPath: '/api/:version/templates/gitlab_ci_ymls/:key',
- dockerfilePath: '/api/:version/templates/dockerfiles/:key',
issuableTemplatePath: '/:namespace_path/:project_path/templates/:type/:key',
+ projectTemplatePath: '/api/:version/projects/:id/templates/:type/:key',
+ projectTemplatesPath: '/api/:version/projects/:id/templates/:type',
usersPath: '/api/:version/users.json',
userStatusPath: '/api/:version/user/status',
commitPath: '/api/:version/projects/:id/repository/commits',
@@ -196,29 +193,29 @@ const Api = {
return axios.get(url);
},
- // Return text for a specific license
- licenseText(key, data, callback) {
- const url = Api.buildUrl(Api.licensePath).replace(':key', key);
- return axios
- .get(url, {
- params: data,
- })
- .then(res => callback(res.data));
- },
+ projectTemplate(id, type, key, options, callback) {
+ const url = Api.buildUrl(this.projectTemplatePath)
+ .replace(':id', encodeURIComponent(id))
+ .replace(':type', type)
+ .replace(':key', encodeURIComponent(key));
- gitignoreText(key, callback) {
- const url = Api.buildUrl(Api.gitignorePath).replace(':key', key);
- return axios.get(url).then(({ data }) => callback(data));
- },
+ return axios.get(url, { params: options }).then(res => {
+ if (callback) callback(res.data);
- gitlabCiYml(key, callback) {
- const url = Api.buildUrl(Api.gitlabCiYmlPath).replace(':key', key);
- return axios.get(url).then(({ data }) => callback(data));
+ return res;
+ });
},
- dockerfileYml(key, callback) {
- const url = Api.buildUrl(Api.dockerfilePath).replace(':key', key);
- return axios.get(url).then(({ data }) => callback(data));
+ projectTemplates(id, type, params = {}, callback) {
+ const url = Api.buildUrl(this.projectTemplatesPath)
+ .replace(':id', encodeURIComponent(id))
+ .replace(':type', type);
+
+ return axios.get(url, { params }).then(res => {
+ if (callback) callback(res.data);
+
+ return res;
+ });
},
issueTemplate(namespacePath, projectPath, key, type, callback) {
@@ -276,12 +273,6 @@ const Api = {
});
},
- templates(key, params = {}) {
- const url = Api.buildUrl(this.templatesPath).replace(':key', key);
-
- return axios.get(url, { params });
- },
-
buildUrl(url) {
let urlRoot = '';
if (gon.relative_url_root != null) {
diff --git a/app/assets/javascripts/blob/file_template_mediator.js b/app/assets/javascripts/blob/file_template_mediator.js
index ff1cbcad145..addacf29f1e 100644
--- a/app/assets/javascripts/blob/file_template_mediator.js
+++ b/app/assets/javascripts/blob/file_template_mediator.js
@@ -1,4 +1,4 @@
-/* eslint-disable class-methods-use-this */
+import Api from '~/api';
import $ from 'jquery';
import Flash from '../flash';
@@ -9,9 +9,10 @@ import GitignoreSelector from './template_selectors/gitignore_selector';
import LicenseSelector from './template_selectors/license_selector';
export default class FileTemplateMediator {
- constructor({ editor, currentAction }) {
+ constructor({ editor, currentAction, projectId }) {
this.editor = editor;
this.currentAction = currentAction;
+ this.projectId = projectId;
this.initTemplateSelectors();
this.initTemplateTypeSelector();
@@ -33,15 +34,14 @@ export default class FileTemplateMediator {
initTemplateTypeSelector() {
this.typeSelector = new FileTemplateTypeSelector({
mediator: this,
- dropdownData: this.templateSelectors
- .map((templateSelector) => {
- const cfg = templateSelector.config;
-
- return {
- name: cfg.name,
- key: cfg.key,
- };
- }),
+ dropdownData: this.templateSelectors.map(templateSelector => {
+ const cfg = templateSelector.config;
+
+ return {
+ name: cfg.name,
+ key: cfg.key,
+ };
+ }),
});
}
@@ -89,7 +89,7 @@ export default class FileTemplateMediator {
}
listenForPreviewMode() {
- this.$navLinks.on('click', 'a', (e) => {
+ this.$navLinks.on('click', 'a', e => {
const urlPieces = e.target.href.split('#');
const hash = urlPieces[1];
if (hash === 'preview') {
@@ -105,7 +105,7 @@ export default class FileTemplateMediator {
e.preventDefault();
}
- this.templateSelectors.forEach((selector) => {
+ this.templateSelectors.forEach(selector => {
if (selector.config.key === item.key) {
selector.show();
} else {
@@ -126,8 +126,8 @@ export default class FileTemplateMediator {
selector.renderLoading();
// in case undo menu is already already there
this.destroyUndoMenu();
- this.fetchFileTemplate(selector.config.endpoint, query, data)
- .then((file) => {
+ this.fetchFileTemplate(selector.config.type, query, data)
+ .then(file => {
this.showUndoMenu();
this.setEditorContent(file);
this.setFilename(selector.config.name);
@@ -138,7 +138,7 @@ export default class FileTemplateMediator {
displayMatchedTemplateSelector() {
const currentInput = this.getFilename();
- this.templateSelectors.forEach((selector) => {
+ this.templateSelectors.forEach(selector => {
const match = selector.config.pattern.test(currentInput);
if (match) {
@@ -149,15 +149,11 @@ export default class FileTemplateMediator {
});
}
- fetchFileTemplate(apiCall, query, data) {
- return new Promise((resolve) => {
+ fetchFileTemplate(type, query, data = {}) {
+ return new Promise(resolve => {
const resolveFile = file => resolve(file);
- if (!data) {
- apiCall(query, resolveFile);
- } else {
- apiCall(query, data, resolveFile);
- }
+ Api.projectTemplate(this.projectId, type, query, data, resolveFile);
});
}
diff --git a/app/assets/javascripts/blob/template_selector.js b/app/assets/javascripts/blob/template_selector.js
index 9dfdb06007d..9db1fa70ffb 100644
--- a/app/assets/javascripts/blob/template_selector.js
+++ b/app/assets/javascripts/blob/template_selector.js
@@ -66,9 +66,6 @@ export default class TemplateSelector {
// be added by all subclasses.
}
- // To be implemented on the extending class
- // e.g. Api.gitlabCiYml(query.name, file => this.setEditorContent(file));
-
setEditorContent(file, { skipFocus } = {}) {
if (!file) return;
diff --git a/app/assets/javascripts/blob/template_selectors/ci_yaml_selector.js b/app/assets/javascripts/blob/template_selectors/ci_yaml_selector.js
index 9c41e429c8d..43f7aead8b9 100644
--- a/app/assets/javascripts/blob/template_selectors/ci_yaml_selector.js
+++ b/app/assets/javascripts/blob/template_selectors/ci_yaml_selector.js
@@ -1,5 +1,3 @@
-import Api from '../../api';
-
import FileTemplateSelector from '../file_template_selector';
export default class BlobCiYamlSelector extends FileTemplateSelector {
@@ -9,7 +7,7 @@ export default class BlobCiYamlSelector extends FileTemplateSelector {
key: 'gitlab-ci-yaml',
name: '.gitlab-ci.yml',
pattern: /(.gitlab-ci.yml)/,
- endpoint: Api.gitlabCiYml,
+ type: 'gitlab_ci_ymls',
dropdown: '.js-gitlab-ci-yml-selector',
wrapper: '.js-gitlab-ci-yml-selector-wrap',
};
diff --git a/app/assets/javascripts/blob/template_selectors/dockerfile_selector.js b/app/assets/javascripts/blob/template_selectors/dockerfile_selector.js
index 45fb614fe00..4718b642617 100644
--- a/app/assets/javascripts/blob/template_selectors/dockerfile_selector.js
+++ b/app/assets/javascripts/blob/template_selectors/dockerfile_selector.js
@@ -1,5 +1,3 @@
-import Api from '../../api';
-
import FileTemplateSelector from '../file_template_selector';
export default class DockerfileSelector extends FileTemplateSelector {
@@ -9,7 +7,7 @@ export default class DockerfileSelector extends FileTemplateSelector {
key: 'dockerfile',
name: 'Dockerfile',
pattern: /(Dockerfile)/,
- endpoint: Api.dockerfileYml,
+ type: 'dockerfiles',
dropdown: '.js-dockerfile-selector',
wrapper: '.js-dockerfile-selector-wrap',
};
diff --git a/app/assets/javascripts/blob/template_selectors/gitignore_selector.js b/app/assets/javascripts/blob/template_selectors/gitignore_selector.js
index a894953cc86..a8067ec5c84 100644
--- a/app/assets/javascripts/blob/template_selectors/gitignore_selector.js
+++ b/app/assets/javascripts/blob/template_selectors/gitignore_selector.js
@@ -1,5 +1,3 @@
-import Api from '../../api';
-
import FileTemplateSelector from '../file_template_selector';
export default class BlobGitignoreSelector extends FileTemplateSelector {
@@ -9,7 +7,7 @@ export default class BlobGitignoreSelector extends FileTemplateSelector {
key: 'gitignore',
name: '.gitignore',
pattern: /(.gitignore)/,
- endpoint: Api.gitignoreText,
+ type: 'gitignores',
dropdown: '.js-gitignore-selector',
wrapper: '.js-gitignore-selector-wrap',
};
diff --git a/app/assets/javascripts/blob/template_selectors/license_selector.js b/app/assets/javascripts/blob/template_selectors/license_selector.js
index b7c4da0f62e..ac1fe95eee5 100644
--- a/app/assets/javascripts/blob/template_selectors/license_selector.js
+++ b/app/assets/javascripts/blob/template_selectors/license_selector.js
@@ -1,5 +1,3 @@
-import Api from '../../api';
-
import FileTemplateSelector from '../file_template_selector';
export default class BlobLicenseSelector extends FileTemplateSelector {
@@ -9,7 +7,7 @@ export default class BlobLicenseSelector extends FileTemplateSelector {
key: 'license',
name: 'LICENSE',
pattern: /^(.+\/)?(licen[sc]e|copying)($|\.)/i,
- endpoint: Api.licenseText,
+ type: 'licenses',
dropdown: '.js-license-selector',
wrapper: '.js-license-selector-wrap',
};
diff --git a/app/assets/javascripts/blob_edit/blob_bundle.js b/app/assets/javascripts/blob_edit/blob_bundle.js
index a603d89b84a..4e4598870fa 100644
--- a/app/assets/javascripts/blob_edit/blob_bundle.js
+++ b/app/assets/javascripts/blob_edit/blob_bundle.js
@@ -15,8 +15,9 @@ export default () => {
const assetsPath = editBlobForm.data('assetsPrefix');
const blobLanguage = editBlobForm.data('blobLanguage');
const currentAction = $('.js-file-title').data('currentAction');
+ const projectId = editBlobForm.data('project-id');
- new EditBlob(`${urlRoot}${assetsPath}`, blobLanguage, currentAction);
+ new EditBlob(`${urlRoot}${assetsPath}`, blobLanguage, currentAction, projectId);
new NewCommitForm(editBlobForm);
}
diff --git a/app/assets/javascripts/blob_edit/edit_blob.js b/app/assets/javascripts/blob_edit/edit_blob.js
index 82a3d494b67..ec2b130ab7d 100644
--- a/app/assets/javascripts/blob_edit/edit_blob.js
+++ b/app/assets/javascripts/blob_edit/edit_blob.js
@@ -7,11 +7,11 @@ import { __ } from '~/locale';
import TemplateSelectorMediator from '../blob/file_template_mediator';
export default class EditBlob {
- constructor(assetsPath, aceMode, currentAction) {
+ constructor(assetsPath, aceMode, currentAction, projectId) {
this.configureAceEditor(aceMode, assetsPath);
this.initModePanesAndLinks();
this.initSoftWrap();
- this.initFileSelectors(currentAction);
+ this.initFileSelectors(currentAction, projectId);
}
configureAceEditor(aceMode, assetsPath) {
@@ -30,10 +30,11 @@ export default class EditBlob {
}
}
- initFileSelectors(currentAction) {
+ initFileSelectors(currentAction, projectId) {
this.fileTemplateMediator = new TemplateSelectorMediator({
currentAction,
editor: this.editor,
+ projectId,
});
}
@@ -60,14 +61,15 @@ export default class EditBlob {
if (paneId === '#preview') {
this.$toggleButton.hide();
- axios.post(currentLink.data('previewUrl'), {
- content: this.editor.getValue(),
- })
- .then(({ data }) => {
- currentPane.empty().append(data);
- currentPane.renderGFM();
- })
- .catch(() => createFlash(__('An error occurred previewing the blob')));
+ axios
+ .post(currentLink.data('previewUrl'), {
+ content: this.editor.getValue(),
+ })
+ .then(({ data }) => {
+ currentPane.empty().append(data);
+ currentPane.renderGFM();
+ })
+ .catch(() => createFlash(__('An error occurred previewing the blob')));
}
this.$toggleButton.show();
diff --git a/app/assets/javascripts/ide/stores/modules/file_templates/actions.js b/app/assets/javascripts/ide/stores/modules/file_templates/actions.js
index cc9f6c8638c..b7090e09daf 100644
--- a/app/assets/javascripts/ide/stores/modules/file_templates/actions.js
+++ b/app/assets/javascripts/ide/stores/modules/file_templates/actions.js
@@ -23,12 +23,12 @@ export const receiveTemplateTypesError = ({ commit, dispatch }) => {
export const receiveTemplateTypesSuccess = ({ commit }, templates) =>
commit(types.RECEIVE_TEMPLATE_TYPES_SUCCESS, templates);
-export const fetchTemplateTypes = ({ dispatch, state }, page = 1) => {
+export const fetchTemplateTypes = ({ dispatch, state, rootState }, page = 1) => {
if (!Object.keys(state.selectedTemplateType).length) return Promise.reject();
dispatch('requestTemplateTypes');
- return Api.templates(state.selectedTemplateType.key, { page })
+ return Api.projectTemplates(rootState.currentProjectId, state.selectedTemplateType.key, { page })
.then(({ data, headers }) => {
const nextPage = parseInt(normalizeHeaders(headers)['X-NEXT-PAGE'], 10);
@@ -74,12 +74,16 @@ export const receiveTemplateError = ({ dispatch }, template) => {
);
};
-export const fetchTemplate = ({ dispatch, state }, template) => {
+export const fetchTemplate = ({ dispatch, state, rootState }, template) => {
if (template.content) {
return dispatch('setFileTemplate', template);
}
- return Api.templates(`${state.selectedTemplateType.key}/${template.key || template.name}`)
+ return Api.projectTemplate(
+ rootState.currentProjectId,
+ state.selectedTemplateType.key,
+ template.key || template.name,
+ )
.then(({ data }) => {
dispatch('setFileTemplate', data);
})
diff --git a/app/finders/license_template_finder.rb b/app/finders/license_template_finder.rb
index 196922709f7..d735a4c1d69 100644
--- a/app/finders/license_template_finder.rb
+++ b/app/finders/license_template_finder.rb
@@ -5,33 +5,47 @@
# Used to find license templates, which may come from a variety of external
# sources
#
-# Arguments:
+# Params can be any of the following:
# popular: boolean. When set to true, only "popular" licenses are shown. When
# false, all licenses except popular ones are shown. When nil (the
# default), *all* licenses will be shown.
+# name: string. If set, return a single license matching that name (or nil)
class LicenseTemplateFinder
- attr_reader :params
+ include Gitlab::Utils::StrongMemoize
- def initialize(params = {})
+ attr_reader :project, :params
+
+ def initialize(project, params = {})
+ @project = project
@params = params
end
def execute
- Licensee::License.all(featured: popular_only?).map do |license|
- LicenseTemplate.new(
- id: license.key,
- name: license.name,
- nickname: license.nickname,
- category: (license.featured? ? :Popular : :Other),
- content: license.content,
- url: license.url,
- meta: license.meta
- )
+ if params[:name]
+ vendored_licenses.find { |template| template.key == params[:name] }
+ else
+ vendored_licenses
end
end
private
+ def vendored_licenses
+ strong_memoize(:vendored_licenses) do
+ Licensee::License.all(featured: popular_only?).map do |license|
+ LicenseTemplate.new(
+ key: license.key,
+ name: license.name,
+ nickname: license.nickname,
+ category: (license.featured? ? :Popular : :Other),
+ content: license.content,
+ url: license.url,
+ meta: license.meta
+ )
+ end
+ end
+ end
+
def popular_only?
params.fetch(:popular, nil)
end
diff --git a/app/finders/template_finder.rb b/app/finders/template_finder.rb
index c92ee9ca9ac..3e483716064 100644
--- a/app/finders/template_finder.rb
+++ b/app/finders/template_finder.rb
@@ -1,29 +1,32 @@
# frozen_string_literal: true
class TemplateFinder
- VENDORED_TEMPLATES = {
+ include Gitlab::Utils::StrongMemoize
+
+ VENDORED_TEMPLATES = HashWithIndifferentAccess.new(
dockerfiles: ::Gitlab::Template::DockerfileTemplate,
gitignores: ::Gitlab::Template::GitignoreTemplate,
gitlab_ci_ymls: ::Gitlab::Template::GitlabCiYmlTemplate
- }.freeze
+ ).freeze
class << self
- def build(type, params = {})
- if type == :licenses
- LicenseTemplateFinder.new(params) # rubocop: disable CodeReuse/Finder
+ def build(type, project, params = {})
+ if type.to_s == 'licenses'
+ LicenseTemplateFinder.new(project, params) # rubocop: disable CodeReuse/Finder
else
- new(type, params)
+ new(type, project, params)
end
end
end
- attr_reader :type, :params
+ attr_reader :type, :project, :params
attr_reader :vendored_templates
private :vendored_templates
- def initialize(type, params = {})
+ def initialize(type, project, params = {})
@type = type
+ @project = project
@params = params
@vendored_templates = VENDORED_TEMPLATES.fetch(type)
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index 9cbd5b5f785..883e5ddff57 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -159,10 +159,6 @@ module BlobHelper
end
end
- def licenses_for_select
- @licenses_for_select ||= template_dropdown_names(TemplateFinder.build(:licenses).execute)
- end
-
def ref_project
@ref_project ||= @target_project || @project
end
@@ -173,29 +169,34 @@ module BlobHelper
categories.each_with_object({}) do |category, hash|
hash[category] = grouped[category].map do |item|
- { name: item.name, id: item.id }
+ { name: item.name, id: item.key }
end
end
end
private :template_dropdown_names
- def gitignore_names
- @gitignore_names ||= template_dropdown_names(TemplateFinder.build(:gitignores).execute)
+ def licenses_for_select(project = @project)
+ @licenses_for_select ||= template_dropdown_names(TemplateFinder.build(:licenses, project).execute)
+ end
+
+ def gitignore_names(project = @project)
+ @gitignore_names ||= template_dropdown_names(TemplateFinder.build(:gitignores, project).execute)
end
- def gitlab_ci_ymls
- @gitlab_ci_ymls ||= template_dropdown_names(TemplateFinder.build(:gitlab_ci_ymls).execute)
+ def gitlab_ci_ymls(project = @project)
+ @gitlab_ci_ymls ||= template_dropdown_names(TemplateFinder.build(:gitlab_ci_ymls, project).execute)
end
- def dockerfile_names
- @dockerfile_names ||= template_dropdown_names(TemplateFinder.build(:dockerfiles).execute)
+ def dockerfile_names(project = @project)
+ @dockerfile_names ||= template_dropdown_names(TemplateFinder.build(:dockerfiles, project).execute)
end
- def blob_editor_paths
+ def blob_editor_paths(project = @project)
{
'relative-url-root' => Rails.application.config.relative_url_root,
'assets-prefix' => Gitlab::Application.config.assets.prefix,
- 'blob-language' => @blob && @blob.language.try(:ace_mode)
+ 'blob-language' => @blob && @blob.language.try(:ace_mode),
+ 'project-id' => project.id
}
end
diff --git a/app/models/license_template.rb b/app/models/license_template.rb
index 693a6a89fd2..73e403f98b4 100644
--- a/app/models/license_template.rb
+++ b/app/models/license_template.rb
@@ -12,12 +12,10 @@ class LicenseTemplate
(fullname|name\sof\s(author|copyright\sowner))
[\>\}\]]}xi.freeze
- attr_reader :id, :name, :category, :nickname, :url, :meta
+ attr_reader :key, :name, :category, :nickname, :url, :meta
- alias_method :key, :id
-
- def initialize(id:, name:, category:, content:, nickname: nil, url: nil, meta: {})
- @id = id
+ def initialize(key:, name:, category:, content:, nickname: nil, url: nil, meta: {})
+ @key = key
@name = name
@category = category
@content = content