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
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-10-31 12:09:32 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-10-31 12:09:32 +0300
commit5025412fc4ab16cc7049a38d43fdc2e4095a1f87 (patch)
treeecec75618d069e02ba0ebcf36db6630150a9d073 /app/assets
parent853c0c530b624a2f94ce85acbbdffc70510bdba3 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets')
-rw-r--r--app/assets/javascripts/behaviors/markdown/render_gfm.js2
-rw-r--r--app/assets/javascripts/behaviors/markdown/render_sandboxed_mermaid.js129
-rw-r--r--app/assets/javascripts/related_issues/components/related_issues_block.vue14
-rw-r--r--app/assets/javascripts/related_issues/components/related_issues_root.vue10
-rw-r--r--app/assets/javascripts/webhooks/components/form_url_app.vue15
-rw-r--r--app/assets/javascripts/webhooks/components/form_url_mask_item.vue20
-rw-r--r--app/assets/javascripts/webhooks/constants.js2
-rw-r--r--app/assets/javascripts/webhooks/index.js7
8 files changed, 122 insertions, 77 deletions
diff --git a/app/assets/javascripts/behaviors/markdown/render_gfm.js b/app/assets/javascripts/behaviors/markdown/render_gfm.js
index a08cf48c327..ee5c0fe5ef3 100644
--- a/app/assets/javascripts/behaviors/markdown/render_gfm.js
+++ b/app/assets/javascripts/behaviors/markdown/render_gfm.js
@@ -15,7 +15,7 @@ $.fn.renderGFM = function renderGFM() {
syntaxHighlight(this.find('.js-syntax-highlight').get());
renderKroki(this.find('.js-render-kroki[hidden]').get());
renderMath(this.find('.js-render-math'));
- renderSandboxedMermaid(this.find('.js-render-mermaid').get());
+ renderSandboxedMermaid(this.find('.js-render-mermaid'));
renderJSONTable(
Array.from(this.find('[lang="json"][data-lang-params="table"]').get()).map((e) => e.parentNode),
);
diff --git a/app/assets/javascripts/behaviors/markdown/render_sandboxed_mermaid.js b/app/assets/javascripts/behaviors/markdown/render_sandboxed_mermaid.js
index 031b03e0d59..077e96b2fee 100644
--- a/app/assets/javascripts/behaviors/markdown/render_sandboxed_mermaid.js
+++ b/app/assets/javascripts/behaviors/markdown/render_sandboxed_mermaid.js
@@ -1,4 +1,5 @@
-import { countBy } from 'lodash';
+import $ from 'jquery';
+import { once, countBy } from 'lodash';
import { __ } from '~/locale';
import {
getBaseURL,
@@ -7,8 +8,7 @@ import {
joinPaths,
} from '~/lib/utils/url_utility';
import { darkModeEnabled } from '~/lib/utils/color_utils';
-import { setAttributes, isElementVisible } from '~/lib/utils/dom_utils';
-import { createAlert, VARIANT_WARNING } from '~/flash';
+import { setAttributes } from '~/lib/utils/dom_utils';
import { unrestrictedPages } from './constants';
// Renders diagrams and flowcharts from text using Mermaid in any element with the
@@ -27,30 +27,17 @@ import { unrestrictedPages } from './constants';
const SANDBOX_FRAME_PATH = '/-/sandbox/mermaid';
// This is an arbitrary number; Can be iterated upon when suitable.
-export const MAX_CHAR_LIMIT = 2000;
+const MAX_CHAR_LIMIT = 2000;
// Max # of mermaid blocks that can be rendered in a page.
-export const MAX_MERMAID_BLOCK_LIMIT = 50;
+const MAX_MERMAID_BLOCK_LIMIT = 50;
// Max # of `&` allowed in Chaining of links syntax
const MAX_CHAINING_OF_LINKS_LIMIT = 30;
-
export const BUFFER_IFRAME_HEIGHT = 10;
export const SANDBOX_ATTRIBUTES = 'allow-scripts allow-popups';
-
-const ALERT_CONTAINER_CLASS = 'mermaid-alert-container';
-export const LAZY_ALERT_SHOWN_CLASS = 'lazy-alert-shown';
-
// Keep a map of mermaid blocks we've already rendered.
const elsProcessingMap = new WeakMap();
let renderedMermaidBlocks = 0;
-/**
- * Determines whether a given Mermaid diagram is visible.
- *
- * @param {Element} el The Mermaid DOM node
- * @returns
- */
-const isVisibleMermaid = (el) => el.closest('details') === null && isElementVisible(el);
-
function shouldLazyLoadMermaidBlock(source) {
/**
* If source contains `&`, which means that it might
@@ -117,8 +104,8 @@ function renderMermaidEl(el, source) {
);
}
-function renderMermaids(els) {
- if (!els.length) return;
+function renderMermaids($els) {
+ if (!$els.length) return;
const pageName = document.querySelector('body').dataset.page;
@@ -127,7 +114,7 @@ function renderMermaids(els) {
let renderedChars = 0;
- els.forEach((el) => {
+ $els.each((i, el) => {
// Skipping all the elements which we've already queued in requestIdleCallback
if (elsProcessingMap.has(el)) {
return;
@@ -146,29 +133,33 @@ function renderMermaids(els) {
renderedMermaidBlocks >= MAX_MERMAID_BLOCK_LIMIT ||
shouldLazyLoadMermaidBlock(source))
) {
- const parent = el.parentNode;
-
- if (!parent.classList.contains(LAZY_ALERT_SHOWN_CLASS)) {
- const alertContainer = document.createElement('div');
- alertContainer.classList.add(ALERT_CONTAINER_CLASS);
- alertContainer.classList.add('gl-mb-5');
- parent.after(alertContainer);
- createAlert({
- message: __(
- 'Warning: Displaying this diagram might cause performance issues on this page.',
- ),
- variant: VARIANT_WARNING,
- parent: parent.parentNode,
- containerSelector: `.${ALERT_CONTAINER_CLASS}`,
- primaryButton: {
- text: __('Display'),
- clickHandler: () => {
- alertContainer.remove();
- renderMermaidEl(el, source);
- },
- },
- });
- parent.classList.add(LAZY_ALERT_SHOWN_CLASS);
+ const html = `
+ <div class="alert gl-alert gl-alert-warning alert-dismissible lazy-render-mermaid-container js-lazy-render-mermaid-container fade show" role="alert">
+ <div>
+ <div>
+ <div class="js-warning-text"></div>
+ <div class="gl-alert-actions">
+ <button type="button" class="js-lazy-render-mermaid btn gl-alert-action btn-confirm btn-md gl-button">Display</button>
+ </div>
+ </div>
+ <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+ <span aria-hidden="true">&times;</span>
+ </button>
+ </div>
+ </div>
+ `;
+
+ const $parent = $(el).parent();
+
+ if (!$parent.hasClass('lazy-alert-shown')) {
+ $parent.after(html);
+ $parent
+ .siblings()
+ .find('.js-warning-text')
+ .text(
+ __('Warning: Displaying this diagram might cause performance issues on this page.'),
+ );
+ $parent.addClass('lazy-alert-shown');
}
return;
@@ -185,33 +176,37 @@ function renderMermaids(els) {
});
}
-export default function renderMermaid(els) {
- if (!els.length) return;
+const hookLazyRenderMermaidEvent = once(() => {
+ $(document.body).on('click', '.js-lazy-render-mermaid', function eventHandler() {
+ const parent = $(this).closest('.js-lazy-render-mermaid-container');
+ const pre = parent.prev();
- const visibleMermaids = [];
- const hiddenMermaids = [];
+ const el = pre.find('.js-render-mermaid');
- for (const el of els) {
- if (isVisibleMermaid(el)) {
- visibleMermaids.push(el);
- } else {
- hiddenMermaids.push(el);
- }
- }
+ parent.remove();
+
+ // sandbox update
+ const element = el.get(0);
+ const { source } = fixElementSource(element);
+
+ renderMermaidEl(element, source);
+ });
+});
+
+export default function renderMermaid($els) {
+ if (!$els.length) return;
+
+ const visibleMermaids = $els.filter(function filter() {
+ return $(this).closest('details').length === 0 && $(this).is(':visible');
+ });
renderMermaids(visibleMermaids);
- hiddenMermaids.forEach((el) => {
- el.closest('details').addEventListener(
- 'toggle',
- ({ target: details }) => {
- if (details.open) {
- renderMermaids([...details.querySelectorAll('.js-render-mermaid')]);
- }
- },
- {
- once: true,
- },
- );
+ $els.closest('details').one('toggle', function toggle() {
+ if (this.open) {
+ renderMermaids($(this).find('.js-render-mermaid'));
+ }
});
+
+ hookLazyRenderMermaidEvent();
}
diff --git a/app/assets/javascripts/related_issues/components/related_issues_block.vue b/app/assets/javascripts/related_issues/components/related_issues_block.vue
index 1ab41ee2f0a..c3726ebc14a 100644
--- a/app/assets/javascripts/related_issues/components/related_issues_block.vue
+++ b/app/assets/javascripts/related_issues/components/related_issues_block.vue
@@ -95,6 +95,16 @@ export default {
required: false,
default: true,
},
+ hasError: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ itemAddFailureMessage: {
+ type: String,
+ required: false,
+ default: '',
+ },
},
data() {
return {
@@ -233,7 +243,7 @@ export default {
<div
v-if="isFormVisible"
class="js-add-related-issues-form-area card-body bordered-box bg-white"
- :class="{ 'gl-mb-5': shouldShowTokenBody }"
+ :class="{ 'gl-mb-5': shouldShowTokenBody, 'gl-show-field-errors': hasError }"
>
<add-issuable-form
:show-categorized-issues="showCategorizedIssues"
@@ -245,6 +255,8 @@ export default {
:auto-complete-epics="autoCompleteEpics"
:auto-complete-issues="autoCompleteIssues"
:path-id-separator="pathIdSeparator"
+ :has-error="hasError"
+ :item-add-failure-message="itemAddFailureMessage"
@pendingIssuableRemoveRequest="$emit('pendingIssuableRemoveRequest', $event)"
@addIssuableFormInput="$emit('addIssuableFormInput', $event)"
@addIssuableFormBlur="$emit('addIssuableFormBlur', $event)"
diff --git a/app/assets/javascripts/related_issues/components/related_issues_root.vue b/app/assets/javascripts/related_issues/components/related_issues_root.vue
index 38e1d6e9d4f..795eb3b0083 100644
--- a/app/assets/javascripts/related_issues/components/related_issues_root.vue
+++ b/app/assets/javascripts/related_issues/components/related_issues_root.vue
@@ -107,6 +107,8 @@ export default {
isSubmitting: false,
isFormVisible: false,
inputValue: '',
+ hasError: false,
+ errorMessage: null,
};
},
computed: {
@@ -170,11 +172,11 @@ export default {
this.isFormVisible = false;
})
.catch(({ response }) => {
- let errorMessage = addRelatedIssueErrorMap[this.issuableType];
+ this.hasError = true;
+ this.errorMessage = addRelatedIssueErrorMap[this.issuableType];
if (response && response.data && response.data.message) {
- errorMessage = response.data.message;
+ this.errorMessage = response.data.message;
}
- createAlert({ message: errorMessage });
})
.finally(() => {
this.isSubmitting = false;
@@ -266,6 +268,8 @@ export default {
:issuable-type="issuableType"
:path-id-separator="pathIdSeparator"
:show-categorized-issues="showCategorizedIssues"
+ :has-error="hasError"
+ :item-add-failure-message="errorMessage"
@saveReorder="saveIssueOrder"
@toggleAddRelatedIssuesForm="onToggleAddRelatedIssuesForm"
@addIssuableFormInput="onInput"
diff --git a/app/assets/javascripts/webhooks/components/form_url_app.vue b/app/assets/javascripts/webhooks/components/form_url_app.vue
index 5ec16d4ba15..45526ff9080 100644
--- a/app/assets/javascripts/webhooks/components/form_url_app.vue
+++ b/app/assets/javascripts/webhooks/components/form_url_app.vue
@@ -1,5 +1,5 @@
<script>
-import { isEmpty } from 'lodash';
+import { cloneDeep, isEmpty } from 'lodash';
import { GlFormGroup, GlFormInput, GlFormRadio, GlFormRadioGroup, GlLink } from '@gitlab/ui';
import { __, s__ } from '~/locale';
@@ -30,7 +30,7 @@ export default {
return {
maskEnabled: !isEmpty(this.initialUrlVariables),
url: this.initialUrl,
- items: isEmpty(this.initialUrlVariables) ? [{}] : this.initialUrlVariables,
+ items: this.getInitialItems(),
};
},
computed: {
@@ -54,6 +54,16 @@ export default {
},
},
methods: {
+ getInitialItems() {
+ return isEmpty(this.initialUrlVariables) ? [{}] : cloneDeep(this.initialUrlVariables);
+ },
+ isEditingItem(key) {
+ if (isEmpty(this.initialUrlVariables)) {
+ return false;
+ }
+
+ return this.initialUrlVariables.some((item) => item.key === key);
+ },
onItemInput({ index, key, value }) {
this.$set(this.items, index, { key, value });
},
@@ -112,6 +122,7 @@ export default {
:index="index"
:item-key="key"
:item-value="value"
+ :is-editing="isEditingItem(key)"
@input="onItemInput"
@remove="removeItem"
/>
diff --git a/app/assets/javascripts/webhooks/components/form_url_mask_item.vue b/app/assets/javascripts/webhooks/components/form_url_mask_item.vue
index 3b75f9b6c0d..aa5d9ce57f4 100644
--- a/app/assets/javascripts/webhooks/components/form_url_mask_item.vue
+++ b/app/assets/javascripts/webhooks/components/form_url_mask_item.vue
@@ -1,6 +1,7 @@
<script>
import { GlButton, GlFormGroup, GlFormInput } from '@gitlab/ui';
import { s__ } from '~/locale';
+import { MASK_ITEM_VALUE_HIDDEN } from '../constants';
export default {
components: {
@@ -24,6 +25,11 @@ export default {
required: false,
default: null,
},
+ isEditing: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
computed: {
keyInputId() {
@@ -32,6 +38,9 @@ export default {
valueInputId() {
return this.inputId('value');
},
+ displayValue() {
+ return this.isEditing ? MASK_ITEM_VALUE_HIDDEN : this.itemValue;
+ },
},
methods: {
inputId(type) {
@@ -68,7 +77,8 @@ export default {
<gl-form-input
:id="valueInputId"
:name="inputName('value')"
- :value="itemValue"
+ :value="displayValue"
+ :disabled="isEditing"
@input="onValueInput"
/>
</gl-form-group>
@@ -82,9 +92,15 @@ export default {
:id="keyInputId"
:name="inputName('key')"
:value="itemKey"
+ :disabled="isEditing"
@input="onKeyInput"
/>
</gl-form-group>
- <gl-button icon="remove" :aria-label="__('Remove')" @click="onRemoveClick" />
+ <gl-button
+ icon="remove"
+ :aria-label="__('Remove')"
+ :disabled="isEditing"
+ @click="onRemoveClick"
+ />
</div>
</template>
diff --git a/app/assets/javascripts/webhooks/constants.js b/app/assets/javascripts/webhooks/constants.js
index abef16545bc..6710a418117 100644
--- a/app/assets/javascripts/webhooks/constants.js
+++ b/app/assets/javascripts/webhooks/constants.js
@@ -15,3 +15,5 @@ export const descriptionText = {
),
[BRANCH_FILTER_REGEX]: s__('Webhooks|Regex such as %{REGEX_CODE} is supported.'),
};
+
+export const MASK_ITEM_VALUE_HIDDEN = '************';
diff --git a/app/assets/javascripts/webhooks/index.js b/app/assets/javascripts/webhooks/index.js
index 1b2b33e44c1..d90680a9bac 100644
--- a/app/assets/javascripts/webhooks/index.js
+++ b/app/assets/javascripts/webhooks/index.js
@@ -10,6 +10,11 @@ export default () => {
const { url: initialUrl, urlVariables } = el.dataset;
+ // Convert the array of 'key' strings to array of { key } objects
+ const initialUrlVariables = urlVariables
+ ? JSON.parse(urlVariables)?.map((key) => ({ key }))
+ : undefined;
+
return new Vue({
el,
name: 'WebhookFormRoot',
@@ -17,7 +22,7 @@ export default () => {
return createElement(FormUrlApp, {
props: {
initialUrl,
- initialUrlVariables: urlVariables ? JSON.parse(urlVariables) : undefined,
+ initialUrlVariables,
},
});
},