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:
Diffstat (limited to 'app/assets/javascripts/editor')
-rw-r--r--app/assets/javascripts/editor/components/source_editor_toolbar.vue13
-rw-r--r--app/assets/javascripts/editor/components/source_editor_toolbar_button.vue17
-rw-r--r--app/assets/javascripts/editor/constants.js104
-rw-r--r--app/assets/javascripts/editor/extensions/source_editor_markdown_ext.js48
-rw-r--r--app/assets/javascripts/editor/extensions/source_editor_markdown_livepreview_ext.js3
-rw-r--r--app/assets/javascripts/editor/schema/ci.json213
6 files changed, 319 insertions, 79 deletions
diff --git a/app/assets/javascripts/editor/components/source_editor_toolbar.vue b/app/assets/javascripts/editor/components/source_editor_toolbar.vue
index 2c177634bbe..c72145f9d2f 100644
--- a/app/assets/javascripts/editor/components/source_editor_toolbar.vue
+++ b/app/assets/javascripts/editor/components/source_editor_toolbar.vue
@@ -57,13 +57,12 @@ export default {
>
<div v-for="group in $options.groups" :key="group">
<gl-button-group v-if="hasGroupItems(group)">
- <template v-for="item in getGroupItems(group)">
- <source-editor-toolbar-button
- :key="item.id"
- :button="item"
- @click="$emit('click', item)"
- />
- </template>
+ <source-editor-toolbar-button
+ v-for="item in getGroupItems(group)"
+ :key="item.id"
+ :button="item"
+ @click="$emit('click', item)"
+ />
</gl-button-group>
</div>
</section>
diff --git a/app/assets/javascripts/editor/components/source_editor_toolbar_button.vue b/app/assets/javascripts/editor/components/source_editor_toolbar_button.vue
index 6ce48ddf89a..38f586f0773 100644
--- a/app/assets/javascripts/editor/components/source_editor_toolbar_button.vue
+++ b/app/assets/javascripts/editor/components/source_editor_toolbar_button.vue
@@ -31,12 +31,19 @@ export default {
return Object.entries(this.button).length > 0;
},
},
+ mounted() {
+ if (this.button.data) {
+ Object.entries(this.button.data).forEach(([attr, value]) => {
+ this.$el.dataset[attr] = value;
+ });
+ }
+ },
methods: {
- clickHandler() {
+ clickHandler(event) {
if (this.button.onClick) {
- this.button.onClick();
+ this.button.onClick(event);
}
- this.$emit('click');
+ this.$emit('click', event);
},
},
};
@@ -52,7 +59,7 @@ export default {
:icon="icon"
:title="label"
:aria-label="label"
- data-qa-selector="editor_toolbar_button"
- @click="clickHandler"
+ :class="button.class"
+ @click="clickHandler($event)"
/>
</template>
diff --git a/app/assets/javascripts/editor/constants.js b/app/assets/javascripts/editor/constants.js
index 83cfdd25757..d0649ecccba 100644
--- a/app/assets/javascripts/editor/constants.js
+++ b/app/assets/javascripts/editor/constants.js
@@ -1,5 +1,6 @@
+import { MODIFIER_KEY } from '~/constants';
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
-import { s__, __ } from '~/locale';
+import { s__, __, sprintf } from '~/locale';
export const URI_PREFIX = 'gitlab';
export const CONTENT_UPDATE_DEBOUNCE = DEFAULT_DEBOUNCE_AND_THROTTLE_MS;
@@ -62,3 +63,104 @@ export const EXTENSION_MARKDOWN_PREVIEW_PANEL_WIDTH = 0.5; // 50% of the width
export const EXTENSION_MARKDOWN_PREVIEW_UPDATE_DELAY = 250; // ms
export const EXTENSION_MARKDOWN_PREVIEW_LABEL = __('Preview Markdown');
export const EXTENSION_MARKDOWN_HIDE_PREVIEW_LABEL = __('Hide Live Preview');
+export const EXTENSION_MARKDOWN_BUTTONS = [
+ {
+ id: 'bold',
+ label: sprintf(s__('MarkdownEditor|Add bold text (%{modifierKey}B)'), {
+ modifierKey: MODIFIER_KEY,
+ }),
+ data: {
+ mdTag: '**',
+ mdShortcuts: '["mod+b"]',
+ },
+ },
+ {
+ id: 'italic',
+ label: sprintf(s__('MarkdownEditor|Add italic text (%{modifierKey}I)'), {
+ modifierKey: MODIFIER_KEY,
+ }),
+ data: {
+ mdTag: '_',
+ mdShortcuts: '["mod+i"]',
+ },
+ },
+ {
+ id: 'strikethrough',
+ label: sprintf(s__('MarkdownEditor|Add strikethrough text (%{modifierKey}⇧X)'), {
+ modifierKey: MODIFIER_KEY,
+ }),
+ data: {
+ mdTag: '~~',
+ mdShortcuts: '["mod+shift+x]',
+ },
+ },
+ {
+ id: 'quote',
+ label: __('Insert a quote'),
+ data: {
+ mdTag: '> ',
+ mdPrepend: true,
+ },
+ },
+ {
+ id: 'code',
+ label: __('Insert code'),
+ data: {
+ mdTag: '`',
+ mdBlock: '```',
+ },
+ },
+ {
+ id: 'link',
+ label: sprintf(s__('MarkdownEditor|Add a link (%{modifier_key}K)'), {
+ modifierKey: MODIFIER_KEY,
+ }),
+ data: {
+ mdTag: '[{text}](url)',
+ mdSelect: 'url',
+ mdShortcuts: '["mod+k"]',
+ },
+ },
+ {
+ id: 'list-bulleted',
+ label: __('Add a bullet list'),
+ data: {
+ mdTag: '- ',
+ mdPrepend: true,
+ },
+ },
+ {
+ id: 'list-numbered',
+ label: __('Add a numbered list'),
+ data: {
+ mdTag: '1. ',
+ mdPrepend: true,
+ },
+ },
+ {
+ id: 'list-task',
+ label: __('Add a checklist'),
+ data: {
+ mdTag: '- [ ] ',
+ mdPrepend: true,
+ },
+ },
+ {
+ id: 'details-block',
+ label: __('Add a collapsible section'),
+ data: {
+ mdTag: '<details><summary>Click to expand</summary>\n{text}\n</details>',
+ mdPrepend: true,
+ mdSelect: __('Click to expand'),
+ },
+ },
+ {
+ id: 'table',
+ label: __('Add a table'),
+ data: {
+ /* eslint-disable-next-line @gitlab/require-i18n-strings */
+ mdTag: '| header | header |\n| ------ | ------ |\n| | |\n| | |',
+ mdPrepend: true,
+ },
+ },
+];
diff --git a/app/assets/javascripts/editor/extensions/source_editor_markdown_ext.js b/app/assets/javascripts/editor/extensions/source_editor_markdown_ext.js
index a16fe93026e..6105a577996 100644
--- a/app/assets/javascripts/editor/extensions/source_editor_markdown_ext.js
+++ b/app/assets/javascripts/editor/extensions/source_editor_markdown_ext.js
@@ -1,8 +1,37 @@
+import { insertMarkdownText } from '~/lib/utils/text_markdown';
+import { EDITOR_TOOLBAR_RIGHT_GROUP, EXTENSION_MARKDOWN_BUTTONS } from '../constants';
+
export class EditorMarkdownExtension {
static get extensionName() {
return 'EditorMarkdown';
}
+ onSetup(instance) {
+ this.toolbarButtons = [];
+ if (instance.toolbar) {
+ this.setupToolbar(instance);
+ }
+ }
+ onBeforeUnuse(instance) {
+ const ids = this.toolbarButtons.map((item) => item.id);
+ if (instance.toolbar) {
+ instance.toolbar.removeItems(ids);
+ }
+ }
+
+ setupToolbar(instance) {
+ this.toolbarButtons = EXTENSION_MARKDOWN_BUTTONS.map((btn) => {
+ return {
+ ...btn,
+ icon: btn.id,
+ group: EDITOR_TOOLBAR_RIGHT_GROUP,
+ category: 'tertiary',
+ onClick: (e) => instance.insertMarkdown(e),
+ };
+ });
+ instance.toolbar.addItems(this.toolbarButtons);
+ }
+
// eslint-disable-next-line class-methods-use-this
provides() {
return {
@@ -36,6 +65,25 @@ export class EditorMarkdownExtension {
pos.lineNumber += dy;
instance.setPosition(pos);
},
+ insertMarkdown: (instance, e) => {
+ const {
+ mdTag: tag,
+ mdBlock: blockTag,
+ mdPrepend,
+ mdSelect: select,
+ } = e.currentTarget.dataset;
+
+ insertMarkdownText({
+ tag,
+ blockTag,
+ wrap: !mdPrepend,
+ select,
+ selected: instance.getSelectedText(),
+ text: instance.getValue(),
+ editor: instance,
+ });
+ instance.focus();
+ },
/**
* Adjust existing selection to select text within the original selection.
* - If `selectedText` is not supplied, we fetch selected text with
diff --git a/app/assets/javascripts/editor/extensions/source_editor_markdown_livepreview_ext.js b/app/assets/javascripts/editor/extensions/source_editor_markdown_livepreview_ext.js
index dd4a7a689d7..58ddaa94d5e 100644
--- a/app/assets/javascripts/editor/extensions/source_editor_markdown_livepreview_ext.js
+++ b/app/assets/javascripts/editor/extensions/source_editor_markdown_livepreview_ext.js
@@ -120,6 +120,9 @@ export class EditorMarkdownPreviewExtension {
category: 'primary',
selectedLabel: EXTENSION_MARKDOWN_HIDE_PREVIEW_LABEL,
onClick: () => instance.togglePreview(),
+ data: {
+ qaSelector: 'editor_toolbar_button',
+ },
},
];
instance.toolbar.addItems(this.toolbarButtons);
diff --git a/app/assets/javascripts/editor/schema/ci.json b/app/assets/javascripts/editor/schema/ci.json
index 45f063a2048..d94aa73e43a 100644
--- a/app/assets/javascripts/editor/schema/ci.json
+++ b/app/assets/javascripts/editor/schema/ci.json
@@ -41,6 +41,9 @@
"before_script": {
"$ref": "#/definitions/before_script"
},
+ "hooks": {
+ "$ref": "#/definitions/hooks"
+ },
"cache": {
"$ref": "#/definitions/cache"
},
@@ -202,25 +205,11 @@
"when": {
"markdownDescription": "Configure when artifacts are uploaded depended on job status. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#artifactswhen).",
"default": "on_success",
- "oneOf": [
- {
- "enum": [
- "on_success"
- ],
- "description": "Upload artifacts only when the job succeeds (this is the default)."
- },
- {
- "enum": [
- "on_failure"
- ],
- "description": "Upload artifacts only when the job fails."
- },
- {
- "enum": [
- "always"
- ],
- "description": "Upload artifacts regardless of job status."
- }
+ "type": "string",
+ "enum": [
+ "on_success",
+ "on_failure",
+ "always"
]
},
"expire_in": {
@@ -347,10 +336,10 @@
"include_item": {
"oneOf": [
{
- "description": "Will infer the method based on the value. E.g. `https://...` strings will be of type `include:remote`, and `/templates/...` will be of type `include:local`.",
+ "description": "Will infer the method based on the value. E.g. `https://...` strings will be of type `include:remote`, and `/templates/...` or `templates/...` will be of type `include:local`.",
"type": "string",
"format": "uri-reference",
- "pattern": "^(https?://|/).+\\.ya?ml$"
+ "pattern": "^(https?://|/?.?-?(?!\\w+://)\\w).+\\.ya?ml$"
},
{
"type": "object",
@@ -585,56 +574,98 @@
]
}
},
+ "id_tokens": {
+ "type": "object",
+ "markdownDescription": "Defines JWTs to be injected as environment variables.",
+ "patternProperties": {
+ ".*": {
+ "type": "object",
+ "properties": {
+ "aud": {
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "minItems": 1,
+ "uniqueItems": true
+ }
+ ]
+ }
+ },
+ "required": [
+ "aud"
+ ],
+ "additionalProperties": false
+ }
+ }
+ },
"secrets": {
"type": "object",
"markdownDescription": "Defines secrets to be injected as environment variables. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#secrets).",
- "additionalProperties": {
- "type": "object",
- "description": "Environment variable name",
- "properties": {
- "vault": {
- "oneOf": [
- {
- "type": "string",
- "description": "The secret to be fetched from Vault (e.g. 'production/db/password@ops' translates to secret 'ops/data/production/db', field `password`)"
- },
- {
- "type": "object",
- "properties": {
- "engine": {
- "type": "object",
- "properties": {
- "name": {
- "type": "string"
+ "patternProperties": {
+ ".*": {
+ "type": "object",
+ "properties": {
+ "vault": {
+ "oneOf": [
+ {
+ "type": "string",
+ "markdownDescription": "The secret to be fetched from Vault (e.g. 'production/db/password@ops' translates to secret 'ops/data/production/db', field `password`). [Learn More](https://docs.gitlab.com/ee/ci/yaml/#secretsvault)"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "engine": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "path": {
+ "type": "string"
+ }
},
- "path": {
- "type": "string"
- }
+ "required": [
+ "name",
+ "path"
+ ]
},
- "required": [
- "name",
- "path"
- ]
- },
- "path": {
- "type": "string"
+ "path": {
+ "type": "string"
+ },
+ "field": {
+ "type": "string"
+ }
},
- "field": {
- "type": "string"
- }
- },
- "required": [
- "engine",
- "path",
- "field"
- ]
- }
- ]
- }
- },
- "required": [
- "vault"
- ]
+ "required": [
+ "engine",
+ "path",
+ "field"
+ ],
+ "additionalProperties": false
+ }
+ ]
+ },
+ "file": {
+ "type": "boolean",
+ "default": true,
+ "markdownDescription": "Configures the secret to be stored as either a file or variable type CI/CD variable. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#secretsfile)"
+ },
+ "token": {
+ "type": "string",
+ "description": "Specifies the JWT variable that should be used to authenticate with Hashicorp Vault."
+ }
+ },
+ "required": [
+ "vault"
+ ],
+ "additionalProperties": false
+ }
}
},
"before_script": {
@@ -739,7 +770,17 @@
"type": "object",
"properties": {
"value": {
- "type": "string"
+ "type": "string",
+ "markdownDescription": "Default value of the variable. If used with `options`, `value` must be included in the array. [Learn More](https://docs.gitlab.com/ee/ci/pipelines/index.html#prefill-variables-in-manual-pipelines)"
+ },
+ "options": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "minItems": 1,
+ "uniqueItems": true,
+ "markdownDescription": "A list of predefined values that users can select from in the **Run pipeline** page when running a pipeline manually. [Learn More](https://docs.gitlab.com/ee/ci/pipelines/index.html#configure-a-list-of-selectable-values-for-a-prefilled-variable)"
},
"description": {
"type": "string",
@@ -959,6 +1000,7 @@
"default": false
},
"when": {
+ "type": "string",
"markdownDescription": "Defines when to save the cache, based on the status of the job. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#cachewhen).",
"default": "on_success",
"enum": [
@@ -1200,6 +1242,9 @@
"after_script": {
"$ref": "#/definitions/after_script"
},
+ "hooks": {
+ "$ref": "#/definitions/hooks"
+ },
"rules": {
"$ref": "#/definitions/rules"
},
@@ -1209,6 +1254,9 @@
"cache": {
"$ref": "#/definitions/cache"
},
+ "id_tokens": {
+ "$ref": "#/definitions/id_tokens"
+ },
"secrets": {
"$ref": "#/definitions/secrets"
},
@@ -1861,6 +1909,39 @@
}
]
}
+ },
+ "hooks": {
+ "type": "object",
+ "markdownDescription": "Specifies lists of commands to execute on the runner at certain stages of job execution. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#hooks).",
+ "properties": {
+ "pre_get_sources_script": {
+ "markdownDescription": "Specifies a list of commands to execute on the runner before updating the Git repository and any submodules. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#hookspre_get_sources_script).",
+ "oneOf": [
+ {
+ "type": "string",
+ "minLength": 1
+ },
+ {
+ "type": "array",
+ "items": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ ]
+ },
+ "minItems": 1
+ }
+ ]
+ }
+ },
+ "additionalProperties": false
}
}
} \ No newline at end of file