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>2021-03-29 15:09:14 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-03-29 15:09:14 +0300
commit1838e244070041ed8ebb6344c628b580d78b578f (patch)
treea6c863a58c74747c2241ff6df35593dfecfa83aa /app/assets
parent290b2ab01becf60d9eaf1094b620f1fb32fdccb3 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets')
-rw-r--r--app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue4
-rw-r--r--app/assets/javascripts/packages/list/components/packages_list_app.vue3
-rw-r--r--app/assets/javascripts/packages_and_registries/shared/constants.js1
-rw-r--r--app/assets/javascripts/packages_and_registries/shared/utils.js9
-rw-r--r--app/assets/javascripts/registry/explorer/pages/list.vue3
-rw-r--r--app/assets/javascripts/repository/components/blob_content_viewer.vue93
-rw-r--r--app/assets/javascripts/repository/components/table/row.vue22
-rw-r--r--app/assets/javascripts/repository/pages/blob.vue17
-rw-r--r--app/assets/javascripts/repository/queries/blob_info.query.graphql30
-rw-r--r--app/assets/javascripts/repository/router.js20
-rw-r--r--app/assets/javascripts/vue_shared/components/registry/registry_search.vue45
-rw-r--r--app/assets/javascripts/vue_shared/components/url_sync.vue20
-rw-r--r--app/assets/stylesheets/page_bundles/ci_status.scss14
13 files changed, 254 insertions, 27 deletions
diff --git a/app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue b/app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue
index bf92da66b27..c0e13d665c3 100644
--- a/app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue
+++ b/app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue
@@ -505,7 +505,7 @@ export default {
<gl-form-textarea
id="sample-payload"
- v-model.trim="samplePayload.json"
+ v-model="samplePayload.json"
:disabled="canEditPayload"
:state="isSampePayloadValid"
:placeholder="$options.i18n.integrationFormSteps.mapFields.placeholder"
@@ -669,7 +669,7 @@ export default {
<gl-form-textarea
id="test-payload"
- v-model.trim="testPayload.json"
+ v-model="testPayload.json"
:state="isTestPayloadValid"
:placeholder="$options.i18n.integrationFormSteps.testPayload.placeholder"
class="gl-my-3"
diff --git a/app/assets/javascripts/packages/list/components/packages_list_app.vue b/app/assets/javascripts/packages/list/components/packages_list_app.vue
index a609dfebedf..3b236764088 100644
--- a/app/assets/javascripts/packages/list/components/packages_list_app.vue
+++ b/app/assets/javascripts/packages/list/components/packages_list_app.vue
@@ -5,6 +5,7 @@ import createFlash from '~/flash';
import { historyReplaceState } from '~/lib/utils/common_utils';
import { s__ } from '~/locale';
import { SHOW_DELETE_SUCCESS_ALERT } from '~/packages/shared/constants';
+import { FILTERED_SEARCH_TERM } from '~/packages_and_registries/shared/constants';
import { DELETE_PACKAGE_SUCCESS_MESSAGE } from '../constants';
import PackageSearch from './package_search.vue';
import PackageTitle from './package_title.vue';
@@ -30,7 +31,7 @@ export default {
}),
emptySearch() {
return (
- this.filter.filter((f) => f.type !== 'filtered-search-term' || f.value?.data).length === 0
+ this.filter.filter((f) => f.type !== FILTERED_SEARCH_TERM || f.value?.data).length === 0
);
},
diff --git a/app/assets/javascripts/packages_and_registries/shared/constants.js b/app/assets/javascripts/packages_and_registries/shared/constants.js
new file mode 100644
index 00000000000..55b5816cc5a
--- /dev/null
+++ b/app/assets/javascripts/packages_and_registries/shared/constants.js
@@ -0,0 +1 @@
+export const FILTERED_SEARCH_TERM = 'filtered-search-term';
diff --git a/app/assets/javascripts/packages_and_registries/shared/utils.js b/app/assets/javascripts/packages_and_registries/shared/utils.js
new file mode 100644
index 00000000000..663c0b2762a
--- /dev/null
+++ b/app/assets/javascripts/packages_and_registries/shared/utils.js
@@ -0,0 +1,9 @@
+import { queryToObject } from '~/lib/utils/url_utility';
+import { FILTERED_SEARCH_TERM } from './constants';
+
+export const getQueryParams = (query) => queryToObject(query, { gatherArrays: true });
+
+export const keyValueToFilterToken = (type, data) => ({ type, value: { data } });
+
+export const searchArrayToFilterTokens = (search) =>
+ search.map((s) => keyValueToFilterToken(FILTERED_SEARCH_TERM, s));
diff --git a/app/assets/javascripts/registry/explorer/pages/list.vue b/app/assets/javascripts/registry/explorer/pages/list.vue
index 625d491db6a..46b3ebbc633 100644
--- a/app/assets/javascripts/registry/explorer/pages/list.vue
+++ b/app/assets/javascripts/registry/explorer/pages/list.vue
@@ -11,6 +11,7 @@ import {
import { get } from 'lodash';
import getContainerRepositoriesQuery from 'shared_queries/container_registry/get_container_repositories.query.graphql';
import createFlash from '~/flash';
+import { FILTERED_SEARCH_TERM } from '~/packages_and_registries/shared/constants';
import Tracking from '~/tracking';
import RegistrySearch from '~/vue_shared/components/registry/registry_search.vue';
import DeleteImage from '../components/delete_image.vue';
@@ -241,7 +242,7 @@ export default {
};
},
doFilter() {
- const search = this.filter.find((i) => i.type === 'filtered-search-term');
+ const search = this.filter.find((i) => i.type === FILTERED_SEARCH_TERM);
this.name = search?.value?.data;
},
},
diff --git a/app/assets/javascripts/repository/components/blob_content_viewer.vue b/app/assets/javascripts/repository/components/blob_content_viewer.vue
new file mode 100644
index 00000000000..a77c1a41787
--- /dev/null
+++ b/app/assets/javascripts/repository/components/blob_content_viewer.vue
@@ -0,0 +1,93 @@
+<script>
+import { GlLoadingIcon } from '@gitlab/ui';
+import { uniqueId } from 'lodash';
+import BlobContent from '~/blob/components/blob_content.vue';
+import BlobHeader from '~/blob/components/blob_header.vue';
+import createFlash from '~/flash';
+import { __ } from '~/locale';
+import blobInfoQuery from '../queries/blob_info.query.graphql';
+import projectPathQuery from '../queries/project_path.query.graphql';
+
+export default {
+ components: {
+ BlobHeader,
+ BlobContent,
+ GlLoadingIcon,
+ },
+ apollo: {
+ projectPath: {
+ query: projectPathQuery,
+ },
+ blobInfo: {
+ query: blobInfoQuery,
+ variables() {
+ return {
+ projectPath: this.projectPath,
+ filePath: this.path,
+ };
+ },
+ error() {
+ createFlash({ message: __('An error occurred while loading the file. Please try again.') });
+ },
+ },
+ },
+ provide() {
+ return {
+ blobHash: uniqueId(),
+ };
+ },
+ data() {
+ return {
+ projectPath: '',
+ blobInfo: {
+ name: '',
+ size: '',
+ rawBlob: '',
+ type: '',
+ fileType: '',
+ tooLarge: false,
+ path: '',
+ editBlobPath: '',
+ ideEditPath: '',
+ storedExternally: false,
+ rawPath: '',
+ externalStorageUrl: '',
+ replacePath: '',
+ deletePath: '',
+ canLock: false,
+ isLocked: false,
+ lockLink: '',
+ canModifyBlob: true,
+ forkPath: '',
+ simpleViewer: '',
+ richViewer: '',
+ },
+ };
+ },
+ computed: {
+ isLoading() {
+ return this.$apollo.queries.blobInfo.loading;
+ },
+ viewer() {
+ const { fileType, tooLarge, type } = this.blobInfo;
+
+ return { fileType, tooLarge, type };
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <gl-loading-icon v-if="isLoading" />
+ <div v-if="blobInfo && !isLoading">
+ <blob-header :blob="blobInfo" />
+ <blob-content
+ :blob="blobInfo"
+ :content="blobInfo.rawBlob"
+ :active-viewer="viewer"
+ :loading="false"
+ />
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/repository/components/table/row.vue b/app/assets/javascripts/repository/components/table/row.vue
index 70918dd55e4..8ea5fce92fa 100644
--- a/app/assets/javascripts/repository/components/table/row.vue
+++ b/app/assets/javascripts/repository/components/table/row.vue
@@ -12,6 +12,7 @@ import { escapeRegExp } from 'lodash';
import { escapeFileUrl } from '~/lib/utils/url_utility';
import FileIcon from '~/vue_shared/components/file_icon.vue';
import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import getRefMixin from '../../mixins/get_ref';
import commitQuery from '../../queries/commit.query.graphql';
@@ -41,7 +42,7 @@ export default {
},
},
},
- mixins: [getRefMixin],
+ mixins: [getRefMixin, glFeatureFlagMixin()],
props: {
id: {
type: String,
@@ -103,10 +104,21 @@ export default {
};
},
computed: {
+ refactorBlobViewerEnabled() {
+ return this.glFeatures.refactorBlobViewer;
+ },
routerLinkTo() {
- return this.isFolder
- ? { path: `/-/tree/${this.escapedRef}/${escapeFileUrl(this.path)}` }
- : null;
+ const blobRouteConfig = { path: `/-/blob/${this.escapedRef}/${escapeFileUrl(this.path)}` };
+ const treeRouteConfig = { path: `/-/tree/${this.escapedRef}/${escapeFileUrl(this.path)}` };
+
+ if (this.refactorBlobViewerEnabled && this.isBlob) {
+ return blobRouteConfig;
+ }
+
+ return this.isFolder ? treeRouteConfig : null;
+ },
+ isBlob() {
+ return this.type === 'blob';
},
isFolder() {
return this.type === 'tree';
@@ -115,7 +127,7 @@ export default {
return this.type === 'commit';
},
linkComponent() {
- return this.isFolder ? 'router-link' : 'a';
+ return this.isFolder || (this.refactorBlobViewerEnabled && this.isBlob) ? 'router-link' : 'a';
},
fullPath() {
return this.path.replace(new RegExp(`^${escapeRegExp(this.currentPath)}/`), '');
diff --git a/app/assets/javascripts/repository/pages/blob.vue b/app/assets/javascripts/repository/pages/blob.vue
new file mode 100644
index 00000000000..c492f966364
--- /dev/null
+++ b/app/assets/javascripts/repository/pages/blob.vue
@@ -0,0 +1,17 @@
+<script>
+// This file is in progress and behind a feature flag, please see the following issue for more:
+// https://gitlab.com/gitlab-org/gitlab/-/issues/323200
+
+// TODO (follow-up MR): import BlobContentViewer from '../components/blob_content_viewer.vue';
+
+export default {
+ components: {
+ // TODO (follow-up MR): BlobContentViewer,
+ },
+};
+</script>
+
+<template>
+ <div></div>
+ <!-- TODO (follow-up MR): <blob-content-viewer/> -->
+</template>
diff --git a/app/assets/javascripts/repository/queries/blob_info.query.graphql b/app/assets/javascripts/repository/queries/blob_info.query.graphql
new file mode 100644
index 00000000000..e0bbf12f3eb
--- /dev/null
+++ b/app/assets/javascripts/repository/queries/blob_info.query.graphql
@@ -0,0 +1,30 @@
+query getBlobInfo($projectPath: ID!, $filePath: String!) {
+ project(fullPath: $projectPath) {
+ id
+ repository {
+ blobs(path: $filePath) {
+ name
+ size
+ rawBlob
+ type
+ fileType
+ tooLarge
+ path
+ editBlobPath
+ ideEditPath
+ storedExternally
+ rawPath
+ externalStorageUrl
+ replacePath
+ deletePath
+ canLock
+ isLocked
+ lockLink
+ canModifyBlob
+ forkPath
+ simpleViewer
+ richViewer
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/repository/router.js b/app/assets/javascripts/repository/router.js
index ad6e32d7055..c7f7451fb55 100644
--- a/app/assets/javascripts/repository/router.js
+++ b/app/assets/javascripts/repository/router.js
@@ -2,6 +2,7 @@ import { escapeRegExp } from 'lodash';
import Vue from 'vue';
import VueRouter from 'vue-router';
import { joinPaths } from '../lib/utils/url_utility';
+import BlobPage from './pages/blob.vue';
import IndexPage from './pages/index.vue';
import TreePage from './pages/tree.vue';
@@ -15,6 +16,13 @@ export default function createRouter(base, baseRef) {
}),
};
+ const blobPathRoute = {
+ component: BlobPage,
+ props: (route) => ({
+ path: route.params.path,
+ }),
+ };
+
return new VueRouter({
mode: 'history',
base: joinPaths(gon.relative_url_root || '', base),
@@ -32,6 +40,18 @@ export default function createRouter(base, baseRef) {
...treePathRoute,
},
{
+ name: 'blobPathDecoded',
+ // Sometimes the ref needs decoding depending on how the backend sends it to us
+ path: `(/-)?/blob/${decodeURI(baseRef)}/:path*`,
+ ...blobPathRoute,
+ },
+ {
+ name: 'blobPath',
+ // Support without decoding as well just in case the ref doesn't need to be decoded
+ path: `(/-)?/blob/${escapeRegExp(baseRef)}/:path*`,
+ ...blobPathRoute,
+ },
+ {
path: '/',
name: 'projectRoot',
component: IndexPage,
diff --git a/app/assets/javascripts/vue_shared/components/registry/registry_search.vue b/app/assets/javascripts/vue_shared/components/registry/registry_search.vue
index 62453a25f62..0825c3a76ea 100644
--- a/app/assets/javascripts/vue_shared/components/registry/registry_search.vue
+++ b/app/assets/javascripts/vue_shared/components/registry/registry_search.vue
@@ -1,5 +1,6 @@
<script>
import { GlSorting, GlSortingItem, GlFilteredSearch } from '@gitlab/ui';
+import { FILTERED_SEARCH_TERM } from '~/packages_and_registries/shared/constants';
const ASCENDING_ORDER = 'asc';
const DESCENDING_ORDER = 'desc';
@@ -45,18 +46,60 @@ export default {
isSortAscending() {
return this.sorting.sort === ASCENDING_ORDER;
},
+ baselineQueryStringFilters() {
+ return this.tokens.reduce((acc, curr) => {
+ acc[curr.type] = '';
+ return acc;
+ }, {});
+ },
},
methods: {
+ generateQueryData({ sorting = {}, filter = [] } = {}) {
+ // Ensure that we clean up the query when we remove a token from the search
+ const result = { ...this.baselineQueryStringFilters, ...sorting, search: [] };
+
+ filter.forEach((f) => {
+ if (f.type === FILTERED_SEARCH_TERM) {
+ result.search.push(f.value.data);
+ } else {
+ result[f.type] = f.value.data;
+ }
+ });
+ return result;
+ },
onDirectionChange() {
const sort = this.isSortAscending ? DESCENDING_ORDER : ASCENDING_ORDER;
+ const newQueryString = this.generateQueryData({
+ sorting: { ...this.sorting, sort },
+ filter: this.filter,
+ });
this.$emit('sorting:changed', { sort });
+ this.$emit('query:changed', newQueryString);
},
onSortItemClick(item) {
+ const newQueryString = this.generateQueryData({
+ sorting: { ...this.sorting, orderBy: item },
+ filter: this.filter,
+ });
this.$emit('sorting:changed', { orderBy: item });
+ this.$emit('query:changed', newQueryString);
+ },
+ submitSearch() {
+ const newQueryString = this.generateQueryData({
+ sorting: this.sorting,
+ filter: this.filter,
+ });
+ this.$emit('filter:submit');
+ this.$emit('query:changed', newQueryString);
},
clearSearch() {
+ const newQueryString = this.generateQueryData({
+ sorting: this.sorting,
+ });
+
this.$emit('filter:changed', []);
this.$emit('filter:submit');
+ this.$emit('query:changed', newQueryString);
},
},
};
@@ -69,7 +112,7 @@ export default {
class="gl-mr-4 gl-flex-fill-1"
:placeholder="__('Filter results')"
:available-tokens="tokens"
- @submit="$emit('filter:submit')"
+ @submit="submitSearch"
@clear="clearSearch"
/>
<gl-sorting
diff --git a/app/assets/javascripts/vue_shared/components/url_sync.vue b/app/assets/javascripts/vue_shared/components/url_sync.vue
index 2844d9e9e94..925c6008836 100644
--- a/app/assets/javascripts/vue_shared/components/url_sync.vue
+++ b/app/assets/javascripts/vue_shared/components/url_sync.vue
@@ -2,11 +2,18 @@
import { historyPushState } from '~/lib/utils/common_utils';
import { mergeUrlParams } from '~/lib/utils/url_utility';
+/**
+ * Renderless component to update the query string,
+ * the update is done by updating the query property or
+ * by using updateQuery method in the scoped slot.
+ * note: do not use both prop and updateQuery method.
+ */
export default {
props: {
query: {
type: Object,
- required: true,
+ required: false,
+ default: null,
},
},
watch: {
@@ -14,12 +21,19 @@ export default {
immediate: true,
deep: true,
handler(newQuery) {
- historyPushState(mergeUrlParams(newQuery, window.location.href, { spreadArrays: true }));
+ if (newQuery) {
+ this.updateQuery(newQuery);
+ }
},
},
},
+ methods: {
+ updateQuery(newQuery) {
+ historyPushState(mergeUrlParams(newQuery, window.location.href, { spreadArrays: true }));
+ },
+ },
render() {
- return this.$slots.default;
+ return this.$scopedSlots.default?.({ updateQuery: this.updateQuery });
},
};
</script>
diff --git a/app/assets/stylesheets/page_bundles/ci_status.scss b/app/assets/stylesheets/page_bundles/ci_status.scss
index 232d363b7f1..6b976106cc9 100644
--- a/app/assets/stylesheets/page_bundles/ci_status.scss
+++ b/app/assets/stylesheets/page_bundles/ci_status.scss
@@ -80,17 +80,3 @@
}
}
}
-
-.d-block.d-sm-none-inline {
- .ci-status-link {
- position: relative;
- top: 2px;
- left: 5px;
- }
-}
-
-.ci-status-link {
- svg {
- overflow: visible;
- }
-}