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>2023-11-21 00:14:21 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-11-21 00:14:21 +0300
commit235f755398a6a199b22e4924e7a81670b0dfdaef (patch)
tree84a23b2343ef5a4c0bd03d5ab03ba5370f2b5503 /app
parente12ad88e786d7a91d94d92b26bce9e984d9692f5 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/behaviors/markdown/copy_as_gfm.js4
-rw-r--r--app/assets/javascripts/groups/components/group_item.vue4
-rw-r--r--app/assets/javascripts/groups/components/item_stats.vue2
-rw-r--r--app/assets/javascripts/repository/components/blob_content_viewer.vue2
-rw-r--r--app/assets/javascripts/repository/components/blob_viewers/index.js8
-rw-r--r--app/assets/javascripts/repository/mixins/highlight_mixin.js23
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/constants.js1
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/source_viewer_new.vue19
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/workers/highlight_utils.js36
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/workers/highlight_worker.js4
-rw-r--r--app/assets/javascripts/vue_shared/components/user_access_role_badge.vue9
-rw-r--r--app/assets/javascripts/work_items/components/shared/work_item_link_child_contents.vue13
-rw-r--r--app/assets/javascripts/work_items/components/work_item_links/work_item_link_child.vue6
-rw-r--r--app/assets/javascripts/work_items/components/work_item_links/work_item_tree.vue56
-rw-r--r--app/services/metrics_service.rb6
15 files changed, 121 insertions, 72 deletions
diff --git a/app/assets/javascripts/behaviors/markdown/copy_as_gfm.js b/app/assets/javascripts/behaviors/markdown/copy_as_gfm.js
index 36317444af9..72aae254584 100644
--- a/app/assets/javascripts/behaviors/markdown/copy_as_gfm.js
+++ b/app/assets/javascripts/behaviors/markdown/copy_as_gfm.js
@@ -152,7 +152,9 @@ export class CopyAsGFM {
if (lineElements.length > 0) {
for (let i = 0; i < lineElements.length; i += 1) {
const lineElement = lineElements[i];
- codeElement.appendChild(lineElement);
+ const line = document.createElement('span');
+ line.append(...lineElement.childNodes);
+ codeElement.appendChild(line);
codeElement.appendChild(document.createTextNode('\n'));
}
} else {
diff --git a/app/assets/javascripts/groups/components/group_item.vue b/app/assets/javascripts/groups/components/group_item.vue
index af1af86d0c4..3a08e3e546f 100644
--- a/app/assets/javascripts/groups/components/group_item.vue
+++ b/app/assets/javascripts/groups/components/group_item.vue
@@ -243,7 +243,7 @@ export default {
</div>
</gl-popover>
</template>
- <user-access-role-badge v-if="group.permission" class="gl-mr-3">
+ <user-access-role-badge v-if="group.permission" size="sm" class="gl-mr-3">
{{ group.permission }}
</user-access-role-badge>
<gl-label
@@ -254,7 +254,7 @@ export default {
size="sm"
/>
</div>
- <div v-if="group.description" class="description">
+ <div v-if="group.description" class="description gl-font-sm gl-mt-1">
<span
v-safe-html:[$options.safeHtmlConfig]="group.description"
:itemprop="microdata.descriptionItemprop"
diff --git a/app/assets/javascripts/groups/components/item_stats.vue b/app/assets/javascripts/groups/components/item_stats.vue
index d87190edfd2..55c5ef2ae80 100644
--- a/app/assets/javascripts/groups/components/item_stats.vue
+++ b/app/assets/javascripts/groups/components/item_stats.vue
@@ -68,7 +68,7 @@ export default {
css-class="project-stars"
icon-name="star"
/>
- <div v-if="isProject" class="last-updated">
+ <div v-if="isProject" class="last-updated gl-font-sm">
<time-ago-tooltip :time="item.lastActivityAt" tooltip-placement="bottom" />
</div>
</div>
diff --git a/app/assets/javascripts/repository/components/blob_content_viewer.vue b/app/assets/javascripts/repository/components/blob_content_viewer.vue
index 97a1cbda5d0..264dbff525b 100644
--- a/app/assets/javascripts/repository/components/blob_content_viewer.vue
+++ b/app/assets/javascripts/repository/components/blob_content_viewer.vue
@@ -79,7 +79,7 @@ export default {
const urlHash = getLocationHash(); // If there is a code line hash in the URL we render with the simple viewer
const useSimpleViewer = usePlain || urlHash?.startsWith('L') || !this.hasRichViewer;
- this.initHighlightWorker(this.blobInfo);
+ this.initHighlightWorker(this.blobInfo, this.isUsingLfs);
this.switchViewer(useSimpleViewer ? SIMPLE_BLOB_VIEWER : RICH_BLOB_VIEWER); // By default, if present, use the rich viewer to render
},
error() {
diff --git a/app/assets/javascripts/repository/components/blob_viewers/index.js b/app/assets/javascripts/repository/components/blob_viewers/index.js
index d434700b29f..016f7f9fe43 100644
--- a/app/assets/javascripts/repository/components/blob_viewers/index.js
+++ b/app/assets/javascripts/repository/components/blob_viewers/index.js
@@ -1,4 +1,4 @@
-import { TEXT_FILE_TYPE, JSON_LANGUAGE } from '../../constants';
+import { TEXT_FILE_TYPE } from '../../constants';
export const viewers = {
csv: () => import('./csv_viewer.vue'),
@@ -17,12 +17,10 @@ export const viewers = {
geo_json: () => import('./geo_json/geo_json_viewer.vue'),
};
-export const loadViewer = (type, isUsingLfs, hljsWorkerEnabled, language) => {
+export const loadViewer = (type, isUsingLfs, hljsWorkerEnabled) => {
let viewer = viewers[type];
- if (hljsWorkerEnabled && language === JSON_LANGUAGE && type === TEXT_FILE_TYPE) {
- // The New Source Viewer currently only supports JSON files.
- // More language support will be added in: https://gitlab.com/gitlab-org/gitlab/-/issues/415753
+ if (hljsWorkerEnabled && type === TEXT_FILE_TYPE) {
viewer = () => import('~/vue_shared/components/source_viewer/source_viewer_new.vue');
}
diff --git a/app/assets/javascripts/repository/mixins/highlight_mixin.js b/app/assets/javascripts/repository/mixins/highlight_mixin.js
index 5b6f68681bb..fa4f0f48512 100644
--- a/app/assets/javascripts/repository/mixins/highlight_mixin.js
+++ b/app/assets/javascripts/repository/mixins/highlight_mixin.js
@@ -8,6 +8,8 @@ import { splitIntoChunks } from '~/vue_shared/components/source_viewer/workers/h
import LineHighlighter from '~/blob/line_highlighter';
import languageLoader from '~/content_editor/services/highlight_js_language_loader';
import Tracking from '~/tracking';
+import axios from '~/lib/utils/axios_utils';
+import { TEXT_FILE_TYPE } from '../constants';
/*
* This mixin is intended to be used as an interface between our highlight worker and Vue components
@@ -36,14 +38,29 @@ export default {
this.trackEvent(EVENT_LABEL_FALLBACK, language);
this?.onError();
},
- initHighlightWorker({ rawTextBlob, language, fileType }) {
- if (language !== 'json' || !this.glFeatures.highlightJsWorker) return;
+ async handleLFSBlob(externalStorageUrl, rawPath, language) {
+ await axios
+ .get(externalStorageUrl || rawPath)
+ .then(({ data }) => this.instructWorker(data, language))
+ .catch(() => this.$emit('error'));
+ },
+ initHighlightWorker(blob, isUsingLfs) {
+ const { rawTextBlob, language, fileType, externalStorageUrl, rawPath, simpleViewer } = blob;
+
+ if (!this.glFeatures.highlightJsWorker || simpleViewer?.fileType !== TEXT_FILE_TYPE) return;
if (this.isUnsupportedLanguage(language)) {
this.handleUnsupportedLanguage(language);
return;
}
+ this.highlightWorker.onmessage = this.handleWorkerMessage;
+
+ if (isUsingLfs) {
+ this.handleLFSBlob(externalStorageUrl, rawPath, language);
+ return;
+ }
+
/*
* We want to start rendering content as soon as possible, but highlighting large amounts of
* content can take long, so we render the content in phases:
@@ -64,8 +81,6 @@ export default {
this.chunks = splitIntoChunks(language, firstSeventyLines);
- this.highlightWorker.onmessage = this.handleWorkerMessage;
-
// Instruct the worker to highlight the first 70 lines ASAP, this improves perceived performance.
this.instructWorker(firstSeventyLines, language);
diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/constants.js b/app/assets/javascripts/vue_shared/components/source_viewer/constants.js
index 582093e5739..47b802d9d17 100644
--- a/app/assets/javascripts/vue_shared/components/source_viewer/constants.js
+++ b/app/assets/javascripts/vue_shared/components/source_viewer/constants.js
@@ -14,6 +14,7 @@ export const ROUGE_TO_HLJS_LANGUAGE_MAP = {
clean: 'clean',
clojure: 'clojure',
cmake: 'cmake',
+ codeowners: 'codeowners',
coffeescript: 'coffeescript',
coq: 'coq',
cpp: 'cpp',
diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer_new.vue b/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer_new.vue
index dcefa66c403..7ced12952dd 100644
--- a/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer_new.vue
+++ b/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer_new.vue
@@ -5,7 +5,7 @@ import SafeHtml from '~/vue_shared/directives/safe_html';
import Tracking from '~/tracking';
import addBlobLinksTracking from '~/blob/blob_links_tracking';
import LineHighlighter from '~/blob/line_highlighter';
-import { EVENT_ACTION, EVENT_LABEL_VIEWER } from './constants';
+import { EVENT_ACTION, EVENT_LABEL_VIEWER, CODEOWNERS_FILE_NAME } from './constants';
import Chunk from './components/chunk_new.vue';
import Blame from './components/blame_info.vue';
import { calculateBlameOffset, shouldRender, toggleBlameClasses } from './utils';
@@ -21,6 +21,7 @@ export default {
components: {
Chunk,
Blame,
+ CodeownersValidation: () => import('ee_component/blob/components/codeowners_validation.vue'),
},
directives: {
SafeHtml,
@@ -45,6 +46,10 @@ export default {
type: String,
required: true,
},
+ currentRef: {
+ type: String,
+ required: true,
+ },
},
data() {
return {
@@ -66,6 +71,9 @@ export default {
return result;
}, []);
},
+ isCodeownersFile() {
+ return this.blob.name === CODEOWNERS_FILE_NAME;
+ },
},
watch: {
showBlame: {
@@ -136,11 +144,18 @@ export default {
<blame v-if="showBlame && blameInfo.length" :blame-info="blameInfo" />
<div
- class="file-content code js-syntax-highlight blob-content gl-display-flex gl-flex-direction-column gl-overflow-auto gl-w-full"
+ class="file-content code js-syntax-highlight blob-content gl-display-flex gl-flex-direction-column gl-overflow-auto gl-w-full blob-viewer"
:class="$options.userColorScheme"
data-type="simple"
:data-path="blob.path"
>
+ <codeowners-validation
+ v-if="isCodeownersFile"
+ class="gl-text-black-normal"
+ :current-ref="currentRef"
+ :project-path="projectPath"
+ :file-path="blob.path"
+ />
<chunk
v-for="(chunk, index) in chunks"
:key="index"
diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/workers/highlight_utils.js b/app/assets/javascripts/vue_shared/components/source_viewer/workers/highlight_utils.js
index 8d8e945cd5f..057a1c2d113 100644
--- a/app/assets/javascripts/vue_shared/components/source_viewer/workers/highlight_utils.js
+++ b/app/assets/javascripts/vue_shared/components/source_viewer/workers/highlight_utils.js
@@ -1,13 +1,35 @@
import hljs from 'highlight.js/lib/core';
-import json from 'highlight.js/lib/languages/json';
+import languageLoader from '~/content_editor/services/highlight_js_language_loader';
import { registerPlugins } from '../plugins/index';
import { LINES_PER_CHUNK, NEWLINE, ROUGE_TO_HLJS_LANGUAGE_MAP } from '../constants';
-const initHighlightJs = (fileType, content, language) => {
- // The Highlight Worker is currently scoped to JSON files.
- // See the following issue for more: https://gitlab.com/gitlab-org/gitlab/-/issues/415753
- hljs.registerLanguage(language, json);
+const loadLanguage = async (language) => {
+ const languageDefinition = await languageLoader[language]();
+ hljs.registerLanguage(language, languageDefinition.default);
+};
+
+const loadSubLanguages = async (languageDefinition) => {
+ // Some files can contain sub-languages (i.e., Svelte); this ensures that sub-languages are also loaded
+ if (!languageDefinition?.contains) return;
+
+ // generate list of languages to load
+ const languages = new Set(
+ languageDefinition.contains
+ .filter((component) => Boolean(component.subLanguage))
+ .map((component) => component.subLanguage),
+ );
+
+ if (languageDefinition.subLanguage) {
+ languages.add(languageDefinition.subLanguage);
+ }
+
+ await Promise.all([...languages].map(loadLanguage));
+};
+
+const initHighlightJs = async (fileType, content, language) => {
registerPlugins(hljs, fileType, content, true);
+ await loadLanguage(language);
+ await loadSubLanguages(hljs.getLanguage(language));
};
const splitByLineBreaks = (content = '') => content.split(/\r?\n/);
@@ -35,12 +57,12 @@ const splitIntoChunks = (language, rawContent, highlightedContent) => {
return result;
};
-const highlight = (fileType, rawContent, lang) => {
+const highlight = async (fileType, rawContent, lang) => {
const language = ROUGE_TO_HLJS_LANGUAGE_MAP[lang.toLowerCase()];
let result;
if (language) {
- initHighlightJs(fileType, rawContent, language);
+ await initHighlightJs(fileType, rawContent, language);
const highlightedContent = hljs.highlight(rawContent, { language }).value;
result = splitIntoChunks(language, rawContent, highlightedContent);
}
diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/workers/highlight_worker.js b/app/assets/javascripts/vue_shared/components/source_viewer/workers/highlight_worker.js
index 535e857d7a9..49afaba3d2f 100644
--- a/app/assets/javascripts/vue_shared/components/source_viewer/workers/highlight_worker.js
+++ b/app/assets/javascripts/vue_shared/components/source_viewer/workers/highlight_worker.js
@@ -4,7 +4,7 @@ import { highlight } from './highlight_utils';
* A webworker for highlighting large amounts of content with Highlight.js
*/
// eslint-disable-next-line no-restricted-globals
-self.addEventListener('message', ({ data: { fileType, content, language } }) => {
+self.addEventListener('message', async ({ data: { fileType, content, language } }) => {
// eslint-disable-next-line no-restricted-globals
- self.postMessage(highlight(fileType, content, language));
+ self.postMessage(await highlight(fileType, content, language));
});
diff --git a/app/assets/javascripts/vue_shared/components/user_access_role_badge.vue b/app/assets/javascripts/vue_shared/components/user_access_role_badge.vue
index e5558c038b3..43e35f2b1f0 100644
--- a/app/assets/javascripts/vue_shared/components/user_access_role_badge.vue
+++ b/app/assets/javascripts/vue_shared/components/user_access_role_badge.vue
@@ -12,11 +12,18 @@ export default {
components: {
GlBadge,
},
+ props: {
+ size: {
+ type: String,
+ required: false,
+ default: 'md',
+ },
+ },
};
</script>
<template>
- <gl-badge class="gl-bg-transparent! gl-inset-border-1-gray-100!">
+ <gl-badge :size="size" class="gl-bg-transparent! gl-inset-border-1-gray-100!">
<slot></slot>
</gl-badge>
</template>
diff --git a/app/assets/javascripts/work_items/components/shared/work_item_link_child_contents.vue b/app/assets/javascripts/work_items/components/shared/work_item_link_child_contents.vue
index cbe7de4abcd..503328f7b03 100644
--- a/app/assets/javascripts/work_items/components/shared/work_item_link_child_contents.vue
+++ b/app/assets/javascripts/work_items/components/shared/work_item_link_child_contents.vue
@@ -58,11 +58,6 @@ export default {
default: true,
},
},
- data() {
- return {
- isFocused: false,
- };
- },
computed: {
labels() {
return this.metadataWidgets[WIDGET_TYPE_LABELS]?.labels?.nodes || [];
@@ -117,7 +112,7 @@ export default {
return false;
},
showRemove() {
- return this.canUpdate && this.isFocused;
+ return this.canUpdate;
},
displayLabels() {
return this.showLabels && this.labels.length;
@@ -135,10 +130,6 @@ export default {
<div
class="item-body work-item-link-child gl-relative gl-display-flex gl-flex-grow-1 gl-overflow-break-word gl-min-w-0 gl-pl-3 gl-pr-2 gl-py-2 gl-mx-n2 gl-rounded-base gl-gap-3"
data-testid="links-child"
- @mouseover="isFocused = true"
- @mouseleave="isFocused = false"
- @focusin="isFocused = true"
- @focusout="isFocused = false"
>
<div class="item-contents gl-display-flex gl-flex-grow-1 gl-flex-wrap gl-min-w-0">
<div
@@ -203,12 +194,14 @@ export default {
</div>
<div v-if="canUpdate">
<gl-button
+ v-gl-tooltip
:class="{ 'gl-visibility-visible': showRemove }"
class="gl-visibility-hidden"
category="tertiary"
size="small"
icon="close"
:aria-label="$options.i18n.remove"
+ :title="$options.i18n.remove"
data-testid="remove-work-item-link"
@click="$emit('removeChild', childItem)"
/>
diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_link_child.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_link_child.vue
index 49454c3d9f3..f43718c4cb8 100644
--- a/app/assets/javascripts/work_items/components/work_item_links/work_item_link_child.vue
+++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_link_child.vue
@@ -213,10 +213,10 @@ export default {
</script>
<template>
- <li class="tree-item">
+ <li class="tree-item gl-p-0! gl-border-bottom-0!">
<div
class="gl-display-flex gl-align-items-flex-start"
- :class="{ 'gl-ml-6': canHaveChildren && !hasChildren && hasIndirectChildren }"
+ :class="{ 'gl-ml-5 gl-pl-2': canHaveChildren && !hasChildren && hasIndirectChildren }"
>
<gl-button
v-if="hasChildren"
@@ -227,7 +227,7 @@ export default {
category="tertiary"
size="small"
:loading="isLoadingChildren"
- class="gl-px-0! gl-py-3! gl-mr-3"
+ class="gl-px-0! gl-py-3! gl-mr-2"
data-testid="expand-child"
@click="toggleItem"
/>
diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_tree.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_tree.vue
index 3d09a90169c..09d2e688174 100644
--- a/app/assets/javascripts/work_items/components/work_item_links/work_item_tree.vue
+++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_tree.vue
@@ -146,39 +146,39 @@ export default {
/>
</template>
<template #body>
- <div v-if="!isShownAddForm && children.length === 0" data-testid="tree-empty">
- <div class="gl-new-card-content">
+ <div class="gl-new-card-content">
+ <div v-if="!isShownAddForm && children.length === 0" data-testid="tree-empty">
<p class="gl-new-card-empty">
{{ $options.WORK_ITEMS_TREE_TEXT_MAP[workItemType].empty }}
</p>
</div>
+ <work-item-links-form
+ v-if="isShownAddForm"
+ ref="wiLinksForm"
+ data-testid="add-tree-form"
+ :full-path="fullPath"
+ :issuable-gid="workItemId"
+ :work-item-iid="workItemIid"
+ :form-type="formType"
+ :parent-work-item-type="parentWorkItemType"
+ :children-type="childType"
+ :children-ids="childrenIds"
+ :parent-confidential="confidential"
+ @cancel="hideAddForm"
+ @addChild="$emit('addChild')"
+ />
+ <work-item-children-wrapper
+ :children="children"
+ :can-update="canUpdate"
+ :full-path="fullPath"
+ :work-item-id="workItemId"
+ :work-item-iid="workItemIid"
+ :work-item-type="workItemType"
+ :show-labels="showLabels"
+ @error="error = $event"
+ @show-modal="showModal"
+ />
</div>
- <work-item-links-form
- v-if="isShownAddForm"
- ref="wiLinksForm"
- data-testid="add-tree-form"
- :full-path="fullPath"
- :issuable-gid="workItemId"
- :work-item-iid="workItemIid"
- :form-type="formType"
- :parent-work-item-type="parentWorkItemType"
- :children-type="childType"
- :children-ids="childrenIds"
- :parent-confidential="confidential"
- @cancel="hideAddForm"
- @addChild="$emit('addChild')"
- />
- <work-item-children-wrapper
- :children="children"
- :can-update="canUpdate"
- :full-path="fullPath"
- :work-item-id="workItemId"
- :work-item-iid="workItemIid"
- :work-item-type="workItemType"
- :show-labels="showLabels"
- @error="error = $event"
- @show-modal="showModal"
- />
</template>
</widget-wrapper>
</template>
diff --git a/app/services/metrics_service.rb b/app/services/metrics_service.rb
index f39cc1a8534..d27328f89cd 100644
--- a/app/services/metrics_service.rb
+++ b/app/services/metrics_service.rb
@@ -4,11 +4,7 @@ require 'prometheus/client/formats/text'
class MetricsService
def prometheus_metrics_text
- if Feature.enabled?(:prom_metrics_rust)
- ::Prometheus::Client::Formats::Text.marshal_multiprocess(multiprocess_metrics_path, use_rust: true)
- else
- ::Prometheus::Client::Formats::Text.marshal_multiprocess(multiprocess_metrics_path)
- end
+ ::Prometheus::Client::Formats::Text.marshal_multiprocess(multiprocess_metrics_path)
end
def metrics_text