Skip to content

Commit ca9cb5e

Browse files
author
GitLab Bot
committed
Add latest changes from gitlab-org/gitlab@master
1 parent da10347 commit ca9cb5e

File tree

69 files changed

+1215
-1200
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+1215
-1200
lines changed

.rubocop.yml

+4
Original file line numberDiff line numberDiff line change
@@ -1329,3 +1329,7 @@ Scalability/RandomCronSchedule:
13291329
Enabled: true
13301330
Include:
13311331
- 'config/initializers/1_settings.rb'
1332+
1333+
Migration/PreventFeatureFlagsUsage:
1334+
Enabled: true
1335+
EnforcedSince: 20250505000000
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
Migration/PreventFeatureFlagsUsage:
3+
Details: grace period
4+
Exclude:
5+
- 'db/migrate/20250228183319_migrate_vscode_extension_marketplace_feature_flag_to_data.rb'
6+
- 'db/post_migrate/20250404151331_backfill_ci_job_live_trace_application_setting.rb'

.rubocop_todo/rspec/feature_category.yml

-1
Original file line numberDiff line numberDiff line change
@@ -987,7 +987,6 @@ RSpec/FeatureCategory:
987987
- 'ee/spec/validators/ldap_filter_validator_spec.rb'
988988
- 'ee/spec/validators/password/complexity_validator_spec.rb'
989989
- 'ee/spec/validators/user_existence_validator_spec.rb'
990-
- 'ee/spec/views/admin/application_settings/_deletion_protection_settings.html.haml_spec.rb'
991990
- 'ee/spec/views/admin/application_settings/_git_abuse_rate_limit.html.haml_spec.rb'
992991
- 'ee/spec/views/admin/application_settings/general.html.haml_spec.rb'
993992
- 'ee/spec/views/admin/dev_ops_report/show.html.haml_spec.rb'

GITLAB_KAS_VERSION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
e8c0552b8152cf9363ccd1d9e9002225904d5202
1+
d02aa3b4de57ed8a1a53156be2909b7199659e6c

app/assets/javascripts/boards/components/board_form.vue

+4-1
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ export default {
108108
return {
109109
board: { ...boardDefaults, ...this.currentBoard },
110110
isLoading: false,
111+
isDisabled: false,
111112
};
112113
},
113114
apollo: {
@@ -147,7 +148,7 @@ export default {
147148
return !this.canAdminBoard;
148149
},
149150
submitDisabled() {
150-
return this.isLoading || this.board.name.length === 0;
151+
return this.isLoading || this.board.name.length === 0 || this.isDisabled;
151152
},
152153
primaryProps() {
153154
return {
@@ -259,6 +260,7 @@ export default {
259260
setError({ error, message: this.$options.i18n.deleteErrorMessage });
260261
} finally {
261262
this.isLoading = false;
263+
this.isDisabled = true;
262264
}
263265
} else {
264266
try {
@@ -273,6 +275,7 @@ export default {
273275
setError({ error, message: this.$options.i18n.saveErrorMessage });
274276
} finally {
275277
this.isLoading = false;
278+
this.isDisabled = true;
276279
}
277280
}
278281
},

app/assets/javascripts/pages/projects/blob/show/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import { HISTORY_BUTTON_CLICK } from '~/tracking/constants';
2929
import { initFindFileShortcut } from '~/projects/behaviors';
3030
import initHeaderApp from '~/repository/init_header_app';
3131
import createRouter from '~/repository/router';
32+
import initFileTreeBrowser from '~/repository/file_tree_browser';
3233

3334
Vue.use(Vuex);
3435
Vue.use(VueApollo);
@@ -86,6 +87,7 @@ if (viewBlobEl) {
8687
...dataset
8788
} = viewBlobEl.dataset;
8889
const router = createRouter(projectPath, originalBranch);
90+
initFileTreeBrowser(router);
8991

9092
initHeaderApp({ router, isBlobView: true });
9193

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<script>
2+
import {
3+
GlTooltipDirective,
4+
GlBadge,
5+
GlButtonGroup,
6+
GlButton,
7+
GlSearchBoxByType,
8+
} from '@gitlab/ui';
9+
import { getModifierKey } from '~/constants';
10+
import { __, s__, sprintf } from '~/locale';
11+
12+
export default {
13+
i18n: {
14+
listViewToggleTitle: __('List view'),
15+
treeViewToggleTitle: __('Tree view'),
16+
},
17+
directives: {
18+
GlTooltip: GlTooltipDirective,
19+
},
20+
components: {
21+
GlBadge,
22+
GlButtonGroup,
23+
GlButton,
24+
GlSearchBoxByType,
25+
},
26+
props: {
27+
totalFilesCount: {
28+
type: Number,
29+
required: true,
30+
},
31+
},
32+
data() {
33+
return {
34+
search: '',
35+
renderTreeList: false,
36+
};
37+
},
38+
searchPlaceholder: sprintf(s__('Repository|Search (e.g. *.vue) (%{modifierKey}P)'), {
39+
modifierKey: getModifierKey(),
40+
}),
41+
};
42+
</script>
43+
44+
<template>
45+
<div class="tree-list-holder">
46+
<div class="gl-mb-3 gl-flex gl-items-center">
47+
<h5 class="gl-my-0 gl-inline-block">{{ __('Files') }}</h5>
48+
<gl-badge class="gl-ml-2">{{ totalFilesCount }}</gl-badge>
49+
<gl-button-group class="gl-ml-auto">
50+
<gl-button
51+
v-gl-tooltip.hover
52+
icon="list-bulleted"
53+
:selected="!renderTreeList"
54+
:title="$options.i18n.listViewToggleTitle"
55+
:aria-label="$options.i18n.listViewToggleTitle"
56+
@click="renderTreeList = false"
57+
/>
58+
<gl-button
59+
v-gl-tooltip.hover
60+
icon="file-tree"
61+
:selected="renderTreeList"
62+
:title="$options.i18n.treeViewToggleTitle"
63+
:aria-label="$options.i18n.treeViewToggleTitle"
64+
@click="renderTreeList = true"
65+
/>
66+
</gl-button-group>
67+
</div>
68+
<label for="repository-tree-search" class="sr-only">{{ $options.searchPlaceholder }}</label>
69+
<gl-search-box-by-type
70+
id="repository-tree-search"
71+
v-model="search"
72+
:placeholder="$options.searchPlaceholder"
73+
:clear-button-title="__('Clear search')"
74+
name="repository-tree-search"
75+
class="gl-mb-3"
76+
/>
77+
<div>
78+
<!-- TODO: implement recycle-scroller + list files (file-row components) -->
79+
<p class="text-center gl-my-6">
80+
{{ __('No files found') }}
81+
</p>
82+
</div>
83+
</div>
84+
</template>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<script>
2+
import FileBrowserHeight from '~/diffs/components/file_browser_height.vue';
3+
import TreeList from './components/tree_list.vue';
4+
5+
export const TREE_WIDTH = 320;
6+
7+
export default {
8+
name: 'FileTreeBrowser',
9+
components: {
10+
TreeList,
11+
FileBrowserHeight,
12+
},
13+
data() {
14+
return {
15+
treeWidth: TREE_WIDTH,
16+
isLoading: false,
17+
totalFilesCount: 0,
18+
};
19+
},
20+
};
21+
</script>
22+
23+
<template>
24+
<div>
25+
<file-browser-height :style="{ width: `${treeWidth}px` }" class="repository-tree-list">
26+
<tree-list v-if="!isLoading" class="gl-mr-5 gl-mt-5" :total-files-count="totalFilesCount" />
27+
</file-browser-height>
28+
</div>
29+
</template>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import Vue from 'vue';
2+
import VueApollo from 'vue-apollo';
3+
import createDefaultClient from '~/lib/graphql';
4+
import { pinia } from '~/pinia/instance';
5+
import FileBrowser from './file_tree_browser.vue';
6+
7+
Vue.use(VueApollo);
8+
9+
const apolloProvider = new VueApollo({
10+
defaultClient: createDefaultClient(),
11+
});
12+
13+
export default async function initBrowserComponent(router) {
14+
const el = document.getElementById('js-file-browser');
15+
if (!el) return false;
16+
17+
return new Vue({
18+
el,
19+
pinia,
20+
router,
21+
apolloProvider,
22+
render(h) {
23+
return h(FileBrowser);
24+
},
25+
});
26+
}

app/assets/javascripts/repository/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import RefSelector from '~/ref/components/ref_selector.vue';
1010
import HighlightWorker from '~/vue_shared/components/source_viewer/workers/highlight_worker?worker';
1111
import CodeDropdown from '~/vue_shared/components/code_dropdown/code_dropdown.vue';
1212
import CompactCodeDropdown from 'ee_else_ce/repository/components/code_dropdown/compact_code_dropdown.vue';
13+
import initFileTreeBrowser from '~/repository/file_tree_browser';
1314
import App from './components/app.vue';
1415
import Breadcrumbs from './components/header_area/breadcrumbs.vue';
1516
import ForkInfo from './components/fork_info.vue';
@@ -47,6 +48,7 @@ export default function setupVueRepositoryList() {
4748
targetBranch,
4849
} = dataset;
4950
const router = createRouter(projectPath, escapedRef);
51+
initFileTreeBrowser(router);
5052

5153
apolloProvider.clients.defaultClient.cache.writeQuery({
5254
query: commitsQuery,

app/assets/javascripts/vue_shared/components/crud_component.stories.js

+61-42
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { GlButton, GlTableLite } from '@gitlab/ui';
1+
import { GlButton, GlTableLite, GlKeysetPagination } from '@gitlab/ui';
22
import CrudComponent from './crud_component.vue';
33

44
export default {
@@ -44,6 +44,50 @@ const Template = (args, { argTypes }) => ({
4444
`,
4545
});
4646

47+
const TableTemplate = (args, { argTypes }) => ({
48+
components: { CrudComponent, GlButton, GlTableLite },
49+
props: Object.keys(argTypes),
50+
template: `
51+
<crud-component v-bind="$props" ref="crudComponent">
52+
<gl-table-lite
53+
:items="tableItems"
54+
:fields="tableFields" />
55+
56+
<template #form>
57+
<p>Add form</p>
58+
<div class="gl-flex gl-gap-3">
59+
<gl-button variant="confirm">Add item</gl-button>
60+
<gl-button @click="$refs.crudComponent.hideForm">Cancel</gl-button>
61+
</div>
62+
</template>
63+
</crud-component>
64+
`,
65+
});
66+
67+
const ContentListTemplate = (args, { argTypes }) => ({
68+
components: { CrudComponent, GlButton, GlKeysetPagination },
69+
props: Object.keys(argTypes),
70+
template: `
71+
<crud-component v-bind="$props" ref="crudComponent">
72+
<ul class="content-list">
73+
<li v-for="item in items">{{ item.label }}</li>
74+
</ul>
75+
76+
<template #form>
77+
<p>Add form</p>
78+
<div class="gl-flex gl-gap-3">
79+
<gl-button variant="confirm">Add item</gl-button>
80+
<gl-button @click="$refs.crudComponent.hideForm">Cancel</gl-button>
81+
</div>
82+
</template>
83+
84+
<template v-if="pagination" #pagination>
85+
<gl-keyset-pagination v-bind="paginationProps" />
86+
</template>
87+
</crud-component>
88+
`,
89+
});
90+
4791
const defaultArgs = {
4892
descriptionEnabled: false,
4993
customActions: false,
@@ -83,7 +127,7 @@ WithFooter.args = {
83127
isEmpty: false,
84128
};
85129

86-
export const WithPagnation = Template.bind({});
130+
export const WithPagnation = ContentListTemplate.bind({});
87131
WithPagnation.args = {
88132
...defaultArgs,
89133
title: 'CRUD Component title',
@@ -92,7 +136,22 @@ WithPagnation.args = {
92136
count: 99,
93137
toggleText: 'Add action',
94138
pagination: true,
139+
paginationProps: { hasPreviousPage: false, hasNextPage: true },
95140
isEmpty: false,
141+
items: [
142+
{
143+
label: 'First item',
144+
},
145+
{
146+
label: 'Second item',
147+
},
148+
{
149+
label: 'Third item',
150+
},
151+
{
152+
label: 'Fourth item',
153+
},
154+
],
96155
};
97156

98157
export const WithCustomActions = Template.bind({});
@@ -138,46 +197,6 @@ isCollapsible.args = {
138197
isEmpty: false,
139198
};
140199

141-
const TableTemplate = (args, { argTypes }) => ({
142-
components: { CrudComponent, GlButton, GlTableLite },
143-
props: Object.keys(argTypes),
144-
template: `
145-
<crud-component v-bind="$props" ref="crudComponent">
146-
<gl-table-lite
147-
:items="tableItems"
148-
:fields="tableFields" />
149-
150-
<template #form>
151-
<p>Add form</p>
152-
<div class="gl-flex gl-gap-3">
153-
<gl-button variant="confirm">Add item</gl-button>
154-
<gl-button @click="$refs.crudComponent.hideForm">Cancel</gl-button>
155-
</div>
156-
</template>
157-
</crud-component>
158-
`,
159-
});
160-
161-
const ContentListTemplate = (args, { argTypes }) => ({
162-
components: { CrudComponent, GlButton },
163-
props: Object.keys(argTypes),
164-
template: `
165-
<crud-component v-bind="$props" ref="crudComponent">
166-
<ul class="content-list">
167-
<li v-for="item in items">{{ item.label }}</li>
168-
</ul>
169-
170-
<template #form>
171-
<p>Add form</p>
172-
<div class="gl-flex gl-gap-3">
173-
<gl-button variant="confirm">Add item</gl-button>
174-
<gl-button @click="$refs.crudComponent.hideForm">Cancel</gl-button>
175-
</div>
176-
</template>
177-
</crud-component>
178-
`,
179-
});
180-
181200
export const TableExample = TableTemplate.bind({});
182201
TableExample.args = {
183202
title: 'Hooks',

app/controllers/projects/blob_controller.rb

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ class Projects::BlobController < Projects::ApplicationController
5353
push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks)
5454
push_frontend_feature_flag(:directory_code_dropdown_updates, current_user)
5555
push_frontend_feature_flag(:ci_pipeline_status_realtime, @project)
56+
push_frontend_feature_flag(:repository_file_tree_browser, @project)
5657
end
5758

5859
def new

app/controllers/projects/tree_controller.rb

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class Projects::TreeController < Projects::ApplicationController
2525
push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks)
2626
push_frontend_feature_flag(:directory_code_dropdown_updates, current_user)
2727
push_frontend_feature_flag(:ci_pipeline_status_realtime, @project)
28+
push_frontend_feature_flag(:repository_file_tree_browser, @project)
2829
end
2930

3031
feature_category :source_code_management

0 commit comments

Comments
 (0)