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:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-05-23 18:08:42 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-05-23 18:08:42 +0300
commit3e53902ee13fc4e0bf3162c0c392dcfe1a0ede4b (patch)
tree5b42426053dabe6727c69ca568d547ede95275cb /app
parent097eb364752b8dbb08758e6b7b98a6e4030792c8 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/api/projects_api.js9
-rw-r--r--app/assets/javascripts/content_editor/services/hast_to_prosemirror_converter.js179
-rw-r--r--app/assets/javascripts/content_editor/services/remark_markdown_deserializer.js83
-rw-r--r--app/assets/stylesheets/framework/forms.scss7
-rw-r--r--app/assets/stylesheets/framework/source_editor.scss5
-rw-r--r--app/assets/stylesheets/pages/commits.scss2
-rw-r--r--app/assets/stylesheets/pages/issuable.scss8
-rw-r--r--app/assets/stylesheets/pages/note_form.scss2
-rw-r--r--app/models/bulk_imports/file_transfer/project_config.rb10
-rw-r--r--app/models/project_statistics.rb2
-rw-r--r--app/services/bulk_imports/file_export_service.rb4
-rw-r--r--app/services/bulk_imports/repository_bundle_export_service.rb12
-rw-r--r--app/views/projects/tags/_tag.html.haml2
-rw-r--r--app/views/projects/usage_quotas/index.html.haml6
14 files changed, 179 insertions, 152 deletions
diff --git a/app/assets/javascripts/api/projects_api.js b/app/assets/javascripts/api/projects_api.js
index 7666f558eb5..547060fae5a 100644
--- a/app/assets/javascripts/api/projects_api.js
+++ b/app/assets/javascripts/api/projects_api.js
@@ -6,6 +6,7 @@ export * from './alert_management_alerts_api';
const PROJECTS_PATH = '/api/:version/projects.json';
const PROJECT_IMPORT_MEMBERS_PATH = '/api/:version/projects/:id/import_project_members/:project_id';
+const PROJECT_REPOSITORY_SIZE_PATH = '/api/:version/projects/:id/repository_size';
export function getProjects(query, options, callback = () => {}) {
const url = buildApiUrl(PROJECTS_PATH);
@@ -35,3 +36,11 @@ export function importProjectMembers(sourceId, targetId) {
.replace(':project_id', targetId);
return axios.post(url);
}
+
+export function updateRepositorySize(projectPath) {
+ const url = buildApiUrl(PROJECT_REPOSITORY_SIZE_PATH).replace(
+ ':id',
+ encodeURIComponent(projectPath),
+ );
+ return axios.post(url);
+}
diff --git a/app/assets/javascripts/content_editor/services/hast_to_prosemirror_converter.js b/app/assets/javascripts/content_editor/services/hast_to_prosemirror_converter.js
index b6a3e0bc26a..067965f53eb 100644
--- a/app/assets/javascripts/content_editor/services/hast_to_prosemirror_converter.js
+++ b/app/assets/javascripts/content_editor/services/hast_to_prosemirror_converter.js
@@ -249,33 +249,39 @@ class HastToProseMirrorConverterState {
* @returns An object that contains ProseMirror node factories
*/
const createProseMirrorNodeFactories = (schema, proseMirrorFactorySpecs, source) => {
- const handlers = {
- root: (state, hastNode) => state.openNode(schema.topNodeType, hastNode, {}),
- text: (state, hastNode) => {
- const { factorySpec } = state.top;
-
- if (/^\s+$/.test(hastNode.value)) {
- return;
- }
-
- if (factorySpec.wrapTextInParagraph === true) {
- state.openNode(schema.nodeType('paragraph'));
- state.addText(schema, hastNode.value);
- state.closeNode();
- } else {
- state.addText(schema, hastNode.value);
- }
+ const factories = {
+ root: {
+ selector: 'root',
+ handle: (state, hastNode) => state.openNode(schema.topNodeType, hastNode, {}),
+ },
+ text: {
+ selector: 'text',
+ handle: (state, hastNode) => {
+ const { factorySpec } = state.top;
+
+ if (/^\s+$/.test(hastNode.value)) {
+ return;
+ }
+
+ if (factorySpec.wrapTextInParagraph === true) {
+ state.openNode(schema.nodeType('paragraph'));
+ state.addText(schema, hastNode.value);
+ state.closeNode();
+ } else {
+ state.addText(schema, hastNode.value);
+ }
+ },
},
};
+ for (const [proseMirrorName, factorySpec] of Object.entries(proseMirrorFactorySpecs)) {
+ const factory = {
+ selector: factorySpec.selector,
+ skipChildren: factorySpec.skipChildren,
+ };
- for (const [hastNodeTagName, factorySpec] of Object.entries(proseMirrorFactorySpecs)) {
- if (factorySpec.block) {
- handlers[hastNodeTagName] = (state, hastNode, parent, ancestors) => {
- const nodeType = schema.nodeType(
- isFunction(factorySpec.block)
- ? factorySpec.block(hastNode, parent, ancestors)
- : factorySpec.block,
- );
+ if (factorySpec.type === 'block') {
+ factory.handle = (state, hastNode, parent) => {
+ const nodeType = schema.nodeType(proseMirrorName);
state.closeUntil(parent);
state.openNode(
@@ -297,9 +303,9 @@ const createProseMirrorNodeFactories = (schema, proseMirrorFactorySpecs, source)
state.closeNode();
}
};
- } else if (factorySpec.inline) {
- const nodeType = schema.nodeType(factorySpec.inline);
- handlers[hastNodeTagName] = (state, hastNode, parent) => {
+ } else if (factorySpec.type === 'inline') {
+ const nodeType = schema.nodeType(proseMirrorName);
+ factory.handle = (state, hastNode, parent) => {
state.closeUntil(parent);
state.openNode(
nodeType,
@@ -310,9 +316,9 @@ const createProseMirrorNodeFactories = (schema, proseMirrorFactorySpecs, source)
// Inline nodes do not have children therefore they are immediately closed
state.closeNode();
};
- } else if (factorySpec.mark) {
- const markType = schema.marks[factorySpec.mark];
- handlers[hastNodeTagName] = (state, hastNode, parent) => {
+ } else if (factorySpec.type === 'mark') {
+ const markType = schema.marks[proseMirrorName];
+ factory.handle = (state, hastNode, parent) => {
state.openMark(markType, getAttrs(factorySpec, hastNode, parent, source));
if (factorySpec.inlineContent) {
@@ -320,13 +326,26 @@ const createProseMirrorNodeFactories = (schema, proseMirrorFactorySpecs, source)
}
};
} else {
- throw new RangeError(`Unrecognized node factory spec ${JSON.stringify(factorySpec)}`);
+ throw new RangeError(
+ `Unrecognized ProseMirror object type ${JSON.stringify(factorySpec.type)}`,
+ );
}
+
+ factories[proseMirrorName] = factory;
}
- return handlers;
+ return factories;
};
+const findFactory = (hastNode, factories) =>
+ Object.entries(factories).find(([, factorySpec]) => {
+ const { selector } = factorySpec;
+
+ return isFunction(selector)
+ ? selector(hastNode)
+ : [hastNode.tagName, hastNode.type].includes(selector);
+ })?.[1];
+
/**
* Converts a Hast AST to a ProseMirror document based on a series
* of specifications that describe how to map all the nodes of the former
@@ -339,8 +358,9 @@ const createProseMirrorNodeFactories = (schema, proseMirrorFactorySpecs, source)
* The object should have the following shape:
*
* {
- * [hastNode.tagName]: {
- * [block|node|mark]: [ProseMirror.Node.name],
+ * [ProseMirrorNodeOrMarkName]: {
+ * type: 'block' | 'inline' | 'mark',
+ * selector: String | hastNode -> Boolean,
* ...configurationOptions
* }
* }
@@ -348,57 +368,21 @@ const createProseMirrorNodeFactories = (schema, proseMirrorFactorySpecs, source)
* Where each property in the object represents a HAST node with a given tag name, for example:
*
* {
- * h1: {},
- * h2: {},
- * table: {},
- * strong: {},
- * // etc
- * }
- *
- * You can specify the type of ProseMirror object adding one the following
- * properties:
- *
- * 1. "block": A ProseMirror node that contains one or more children.
- * 2. "inline": A ProseMirror node that doesn’t contain any children although
- * it can have inline content like a code block or a reference.
- * 3. "mark": A ProseMirror mark.
- *
- * The value of that property should be the name of the ProseMirror node or mark, i.e:
- *
- * {
- * h1: {
- * block: 'heading',
+ * horizontalRule: {
+ * type: 'block',
+ * selector: 'hr',
* },
- * h2: {
- * block: 'heading',
+ * heading: {
+ * type: 'block',
+ * selector: (hastNode) => ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(hastNode),
* },
- * img: {
- * node: 'image',
+ * bold: {
+ * type: 'mark'
+ * selector: (hastNode) => ['b', 'strong'].includes(hastNode),
* },
- * strong: {
- * mark: 'bold',
- * }
- * }
+ * // etc
+ * }
*
- * You can compute a ProseMirror’s node or mark name based on the HAST node
- * by passing a function instead of a String. The converter invokes the function
- * and provides a HAST node object:
- *
- * {
- * list: {
- * block: (hastNode) => {
- * let type = 'bulletList';
-
- * if (hastNode.children.some(isTaskItem)) {
- * type = 'taskList';
- * } else if (hastNode.ordered) {
- * type = 'orderedList';
- * }
-
- * return type;
- * }
- * }
- * }
*
* Configuration options
* ----------------------
@@ -406,6 +390,26 @@ const createProseMirrorNodeFactories = (schema, proseMirrorFactorySpecs, source)
* You can customize the conversion process for every node or mark
* setting the following properties in the specification object:
*
+ * **type**
+ *
+ * The `type` property should have one of following three values:
+ *
+ * 1. "block": A ProseMirror node that contains one or more children.
+ * 2. "inline": A ProseMirror node that doesn’t contain any children although
+ * it can have inline content like an image or a mention object.
+ * 3. "mark": A ProseMirror mark.
+ *
+ * **selector**
+ *
+ * The `selector` property matches a HastNode to a ProseMirror node or
+ * Mark. If you assign a string value to this property, the converter
+ * will match the first hast node with a `tagName` or `type` property
+ * that equals the string value.
+ *
+ * If you assign a function, the converter will invoke the function with
+ * the hast node. The function should return `true` if the hastNode matches
+ * the custom criteria implemented in the function
+ *
* **getAttrs**
*
* Computes a ProseMirror node or mark attributes. The converter will invoke
@@ -447,12 +451,9 @@ export const createProseMirrorDocFromMdastTree = ({ schema, factorySpecs, tree,
const state = new HastToProseMirrorConverterState();
visitParents(tree, (hastNode, ancestors) => {
- const parent = ancestors[ancestors.length - 1];
- const skipChildren = factorySpecs[hastNode.tagName]?.skipChildren;
-
- const handler = proseMirrorNodeFactories[hastNode.tagName || hastNode.type];
+ const factory = findFactory(hastNode, proseMirrorNodeFactories);
- if (!handler) {
+ if (!factory) {
throw new Error(
`Hast node of type "${
hastNode.tagName || hastNode.type
@@ -460,9 +461,11 @@ export const createProseMirrorDocFromMdastTree = ({ schema, factorySpecs, tree,
);
}
- handler(state, hastNode, parent, ancestors);
+ const parent = ancestors[ancestors.length - 1];
+
+ factory.handle(state, hastNode, parent);
- return skipChildren === true ? 'skip' : true;
+ return factory.skipChildren === true ? 'skip' : true;
});
let doc;
diff --git a/app/assets/javascripts/content_editor/services/remark_markdown_deserializer.js b/app/assets/javascripts/content_editor/services/remark_markdown_deserializer.js
index 770de1df0d0..899bbcff82f 100644
--- a/app/assets/javascripts/content_editor/services/remark_markdown_deserializer.js
+++ b/app/assets/javascripts/content_editor/services/remark_markdown_deserializer.js
@@ -3,38 +3,24 @@ import { render } from '~/lib/gfm';
import { createProseMirrorDocFromMdastTree } from './hast_to_prosemirror_converter';
const factorySpecs = {
- blockquote: { block: 'blockquote' },
- p: { block: 'paragraph' },
- li: { block: 'listItem', wrapTextInParagraph: true },
- ul: { block: 'bulletList' },
- ol: { block: 'orderedList' },
- h1: {
- block: 'heading',
- getAttrs: () => ({ level: 1 }),
- },
- h2: {
- block: 'heading',
- getAttrs: () => ({ level: 2 }),
- },
- h3: {
- block: 'heading',
- getAttrs: () => ({ level: 3 }),
- },
- h4: {
- block: 'heading',
- getAttrs: () => ({ level: 4 }),
- },
- h5: {
- block: 'heading',
- getAttrs: () => ({ level: 5 }),
- },
- h6: {
- block: 'heading',
- getAttrs: () => ({ level: 6 }),
+ blockquote: { type: 'block', selector: 'blockquote' },
+ paragraph: { type: 'block', selector: 'p' },
+ listItem: { type: 'block', selector: 'li', wrapTextInParagraph: true },
+ orderedList: { type: 'block', selector: 'ol' },
+ bulletList: { type: 'block', selector: 'ul' },
+ heading: {
+ type: 'block',
+ selector: (hastNode) => ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(hastNode.tagName),
+ getAttrs: (hastNode) => {
+ const level = parseInt(/(\d)$/.exec(hastNode.tagName)?.[1], 10) || 1;
+
+ return { level };
+ },
},
- pre: {
- block: 'codeBlock',
+ codeBlock: {
+ type: 'block',
skipChildren: true,
+ selector: 'pre',
getContent: ({ hastNodeText }) => hastNodeText.replace(/\n$/, ''),
getAttrs: (hastNode) => {
const languageClass = hastNode.children[0]?.properties.className?.[0];
@@ -43,23 +29,38 @@ const factorySpecs = {
return { language };
},
},
- hr: { inline: 'horizontalRule' },
- img: {
- inline: 'image',
+ horizontalRule: {
+ type: 'block',
+ selector: 'hr',
+ },
+ image: {
+ type: 'inline',
+ selector: 'img',
getAttrs: (hastNode) => ({
src: hastNode.properties.src,
title: hastNode.properties.title,
alt: hastNode.properties.alt,
}),
},
- br: { inline: 'hardBreak' },
- code: { mark: 'code' },
- em: { mark: 'italic' },
- i: { mark: 'italic' },
- strong: { mark: 'bold' },
- b: { mark: 'bold' },
- a: {
- mark: 'link',
+ hardBreak: {
+ type: 'inline',
+ selector: 'br',
+ },
+ code: {
+ type: 'mark',
+ selector: 'code',
+ },
+ italic: {
+ type: 'mark',
+ selector: (hastNode) => ['em', 'i'].includes(hastNode.tagName),
+ },
+ bold: {
+ type: 'mark',
+ selector: (hastNode) => ['strong', 'b'].includes(hastNode.tagName),
+ },
+ link: {
+ type: 'mark',
+ selector: 'a',
getAttrs: (hastNode) => ({
href: hastNode.properties.href,
title: hastNode.properties.title,
diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss
index 7bba9bb6e68..fd20dfa3539 100644
--- a/app/assets/stylesheets/framework/forms.scss
+++ b/app/assets/stylesheets/framework/forms.scss
@@ -8,13 +8,6 @@ input {
background-color: $input-bg;
}
-input,
-textarea {
- &:focus {
- @include gl-focus;
- }
-}
-
input[type='text'].danger {
background: $input-danger-bg !important;
border-color: $red-400;
diff --git a/app/assets/stylesheets/framework/source_editor.scss b/app/assets/stylesheets/framework/source_editor.scss
index 8b694b9be05..046b8636f65 100644
--- a/app/assets/stylesheets/framework/source_editor.scss
+++ b/app/assets/stylesheets/framework/source_editor.scss
@@ -83,6 +83,11 @@
}
}
}
+
+ // Remove custom focus from element
+ .inputarea {
+ @include gl-shadow-none;
+ }
}
.active-line-text {
diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss
index afe57bb26e6..3ac0c9693d0 100644
--- a/app/assets/stylesheets/pages/commits.scss
+++ b/app/assets/stylesheets/pages/commits.scss
@@ -56,7 +56,7 @@
position: relative;
font-family: $monospace-font;
$left: 12px;
- overflow: hidden; // See https://gitlab.com/gitlab-org/gitlab-foss/issues/13987
+
.max-width-marker {
width: 72ch;
color: $commit-max-width-marker-color;
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 451b4022d41..8fea6134e30 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -750,8 +750,12 @@
.add-issuable-form-input-wrapper {
&.focus {
- border-color: $blue-300;
- box-shadow: 0 0 4px $dropdown-input-focus-shadow;
+ border-color: $gray-700;
+ @include gl-focus;
+
+ input {
+ @include gl-shadow-none;
+ }
}
.gl-show-field-errors &.form-control:not(textarea) {
diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss
index a07ca1792fe..fada49ca40d 100644
--- a/app/assets/stylesheets/pages/note_form.scss
+++ b/app/assets/stylesheets/pages/note_form.scss
@@ -77,7 +77,7 @@
// Disable inner focus
textarea:focus {
- box-shadow: none;
+ @include gl-shadow-none;
}
}
}
diff --git a/app/models/bulk_imports/file_transfer/project_config.rb b/app/models/bulk_imports/file_transfer/project_config.rb
index 67502b6f351..8d4c68f7b5a 100644
--- a/app/models/bulk_imports/file_transfer/project_config.rb
+++ b/app/models/bulk_imports/file_transfer/project_config.rb
@@ -9,7 +9,8 @@ module BulkImports
).freeze
LFS_OBJECTS_RELATION = 'lfs_objects'
- REPOSITORY_BUNDLE_RELATION = 'repository_bundle'
+ REPOSITORY_BUNDLE_RELATION = 'repository'
+ DESIGN_BUNDLE_RELATION = 'design'
def import_export_yaml
::Gitlab::ImportExport.config_file
@@ -20,7 +21,12 @@ module BulkImports
end
def file_relations
- [UPLOADS_RELATION, LFS_OBJECTS_RELATION, REPOSITORY_BUNDLE_RELATION]
+ [
+ UPLOADS_RELATION,
+ LFS_OBJECTS_RELATION,
+ REPOSITORY_BUNDLE_RELATION,
+ DESIGN_BUNDLE_RELATION
+ ]
end
end
end
diff --git a/app/models/project_statistics.rb b/app/models/project_statistics.rb
index 95fc135f38f..5f972c1f506 100644
--- a/app/models/project_statistics.rb
+++ b/app/models/project_statistics.rb
@@ -26,7 +26,7 @@ class ProjectStatistics < ApplicationRecord
pipeline_artifacts_size: %i[storage_size],
snippets_size: %i[storage_size]
}.freeze
- NAMESPACE_RELATABLE_COLUMNS = [:repository_size, :wiki_size, :lfs_objects_size, :uploads_size].freeze
+ NAMESPACE_RELATABLE_COLUMNS = [:repository_size, :wiki_size, :lfs_objects_size, :uploads_size, :container_registry_size].freeze
scope :for_project_ids, ->(project_ids) { where(project_id: project_ids) }
diff --git a/app/services/bulk_imports/file_export_service.rb b/app/services/bulk_imports/file_export_service.rb
index 68f5fcc45a1..b2d114368a1 100644
--- a/app/services/bulk_imports/file_export_service.rb
+++ b/app/services/bulk_imports/file_export_service.rb
@@ -31,7 +31,9 @@ module BulkImports
when FileTransfer::ProjectConfig::LFS_OBJECTS_RELATION
LfsObjectsExportService.new(portable, export_path)
when FileTransfer::ProjectConfig::REPOSITORY_BUNDLE_RELATION
- RepositoryBundleExportService.new(portable, export_path)
+ RepositoryBundleExportService.new(portable.repository, export_path, relation)
+ when FileTransfer::ProjectConfig::DESIGN_BUNDLE_RELATION
+ RepositoryBundleExportService.new(portable.design_repository, export_path, relation)
else
raise BulkImports::Error, 'Unsupported relation export type'
end
diff --git a/app/services/bulk_imports/repository_bundle_export_service.rb b/app/services/bulk_imports/repository_bundle_export_service.rb
index 9d8371dd086..31a2ed6d1af 100644
--- a/app/services/bulk_imports/repository_bundle_export_service.rb
+++ b/app/services/bulk_imports/repository_bundle_export_service.rb
@@ -2,12 +2,10 @@
module BulkImports
class RepositoryBundleExportService
- FILENAME = 'project.bundle'
-
- def initialize(portable, export_path)
- @portable = portable
+ def initialize(repository, export_path, export_filename)
+ @repository = repository
@export_path = export_path
- @repository = portable.repository
+ @export_filename = export_filename
end
def execute
@@ -16,10 +14,10 @@ module BulkImports
private
- attr_reader :portable, :export_path, :repository
+ attr_reader :repository, :export_path, :export_filename
def bundle_filepath
- File.join(export_path, FILENAME)
+ File.join(export_path, "#{export_filename}.bundle")
end
end
end
diff --git a/app/views/projects/tags/_tag.html.haml b/app/views/projects/tags/_tag.html.haml
index 0ee3b89b629..f9d49b36a68 100644
--- a/app/views/projects/tags/_tag.html.haml
+++ b/app/views/projects/tags/_tag.html.haml
@@ -21,7 +21,7 @@
.text-secondary
= sprite_icon("rocket", size: 12)
= _("Release")
- = link_to release.name, project_releases_path(@project, anchor: release.tag), class: 'gl-text-blue-600!'
+ = link_to release.name, ::Feature.enabled?(:fix_release_path_in_tag_index_page, @project) ? project_release_path(@project, release) : project_releases_path(@project, anchor: release.tag), class: 'gl-text-blue-600!'
- if tag.message.present?
%pre.wrap
diff --git a/app/views/projects/usage_quotas/index.html.haml b/app/views/projects/usage_quotas/index.html.haml
index 5b4edc92d1d..6dce9b27409 100644
--- a/app/views/projects/usage_quotas/index.html.haml
+++ b/app/views/projects/usage_quotas/index.html.haml
@@ -1,5 +1,11 @@
- page_title s_("UsageQuota|Usage")
+= render Pajamas::AlertComponent.new(title: _('Repository size recalculation started'),
+ variant: :info,
+ alert_class: 'js-recalculation-started-alert gl-mt-4 gl-mb-5 gl-display-none') do |c|
+ = c.body do
+ = _('Refresh the page in a few minutes to view usage.')
+
%h3.page-title
= s_('UsageQuota|Usage Quotas')