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>2023-08-11 03:10:11 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-08-11 03:10:11 +0300
commit7303dddd09bf28d28e36666f0cc2775e9fa27872 (patch)
treec97552993de10857894e26c7f0c6b412496a063b /app/assets
parent997968e3fa7d1f623f7bd9e2581c58dc7afc5aa5 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets')
-rw-r--r--app/assets/javascripts/groups/components/app.vue9
-rw-r--r--app/assets/javascripts/groups/components/group_item.vue10
-rw-r--r--app/assets/javascripts/groups/groups_list.js18
-rw-r--r--app/assets/javascripts/groups/index.js61
-rw-r--r--app/assets/javascripts/pages/explore/groups/index.js2
-rw-r--r--app/assets/javascripts/profile/edit/components/profile_edit_app.vue83
-rw-r--r--app/assets/javascripts/profile/edit/constants.js7
-rw-r--r--app/assets/javascripts/profile/edit/index.js16
8 files changed, 116 insertions, 90 deletions
diff --git a/app/assets/javascripts/groups/components/app.vue b/app/assets/javascripts/groups/components/app.vue
index c6fe16b13b5..3440bd87e6b 100644
--- a/app/assets/javascripts/groups/components/app.vue
+++ b/app/assets/javascripts/groups/components/app.vue
@@ -28,11 +28,6 @@ export default {
required: false,
default: '',
},
- containerId: {
- type: String,
- required: false,
- default: '',
- },
store: {
type: Object,
required: true,
@@ -94,10 +89,6 @@ export default {
},
mounted() {
this.fetchAllGroups();
-
- if (this.containerId) {
- this.containerEl = document.getElementById(this.containerId);
- }
},
beforeDestroy() {
eventHub.$off(`${this.action}fetchPage`, this.fetchPage);
diff --git a/app/assets/javascripts/groups/components/group_item.vue b/app/assets/javascripts/groups/components/group_item.vue
index befb96034f5..af1af86d0c4 100644
--- a/app/assets/javascripts/groups/components/group_item.vue
+++ b/app/assets/javascripts/groups/components/group_item.vue
@@ -21,7 +21,7 @@ import {
VISIBILITY_TYPE_ICON,
GROUP_VISIBILITY_TYPE,
} from '~/visibility_level/constants';
-import { ITEM_TYPE } from '../constants';
+import { ITEM_TYPE, ACTIVE_TAB_SHARED } from '../constants';
import eventHub from '../event_hub';
@@ -50,7 +50,11 @@ export default {
ItemActions,
ItemStats,
},
- inject: ['currentGroupVisibility'],
+ inject: {
+ currentGroupVisibility: {
+ default: '',
+ },
+ },
props: {
parentGroup: {
type: Object,
@@ -114,7 +118,7 @@ export default {
},
shouldShowVisibilityWarning() {
return (
- this.action === 'shared' &&
+ this.action === ACTIVE_TAB_SHARED &&
VISIBILITY_LEVELS_STRING_TO_INTEGER[this.group.visibility] >
VISIBILITY_LEVELS_STRING_TO_INTEGER[this.currentGroupVisibility]
);
diff --git a/app/assets/javascripts/groups/groups_list.js b/app/assets/javascripts/groups/groups_list.js
deleted file mode 100644
index 866dd7a61ff..00000000000
--- a/app/assets/javascripts/groups/groups_list.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import FilterableList from '~/filterable_list';
-
-/**
- * Makes search request for groups when user types a value in the search input.
- * Updates the html content of the page with the received one.
- */
-export default class GroupsList {
- constructor() {
- const form = document.querySelector('form#group-filter-form');
- const filter = document.querySelector('.js-groups-list-filter');
- const holder = document.querySelector('.js-groups-list-holder');
-
- if (form && filter && holder) {
- const list = new FilterableList(form, filter, holder);
- list.initSearch();
- }
- }
-}
diff --git a/app/assets/javascripts/groups/index.js b/app/assets/javascripts/groups/index.js
index df2a23dc0f7..e71ff6d9107 100644
--- a/app/assets/javascripts/groups/index.js
+++ b/app/assets/javascripts/groups/index.js
@@ -7,92 +7,49 @@ import Translate from '../vue_shared/translate';
import GroupsApp from './components/app.vue';
import GroupFolderComponent from './components/group_folder.vue';
-import { GROUPS_LIST_HOLDER_CLASS, CONTENT_LIST_CLASS } from './constants';
import GroupFilterableList from './groups_filterable_list';
import GroupsService from './service/groups_service';
import GroupsStore from './store/groups_store';
Vue.use(Translate);
-export default (containerId = 'js-groups-tree', endpoint, action = '') => {
- const containerEl = document.getElementById(containerId);
- let dataEl;
+export default () => {
+ const el = document.getElementById('js-groups-tree');
// eslint-disable-next-line no-new
new UserCallout();
- // Don't do anything if element doesn't exist (No groups)
- // This is for when the user enters directly to the page via URL
- if (!containerEl) {
+ if (!el) {
return;
}
- const el = action ? containerEl.querySelector(GROUPS_LIST_HOLDER_CLASS) : containerEl;
-
- if (action) {
- dataEl = containerEl.querySelector(CONTENT_LIST_CLASS);
- }
-
Vue.component('GroupFolder', GroupFolderComponent);
Vue.component('GroupItem', GroupItemComponent);
Vue.use(GlToast);
+ const { dataset } = el;
+
// eslint-disable-next-line no-new
new Vue({
el,
components: {
GroupsApp,
},
- provide() {
- const {
- dataset: {
- newSubgroupPath,
- newProjectPath,
- newSubgroupIllustration,
- newProjectIllustration,
- emptyProjectsIllustration,
- emptySubgroupIllustration,
- canCreateSubgroups,
- canCreateProjects,
- currentGroupVisibility,
- },
- } = this.$options.el;
-
- return {
- newSubgroupPath,
- newProjectPath,
- newSubgroupIllustration,
- newProjectIllustration,
- emptyProjectsIllustration,
- emptySubgroupIllustration,
- canCreateSubgroups: parseBoolean(canCreateSubgroups),
- canCreateProjects: parseBoolean(canCreateProjects),
- currentGroupVisibility,
- };
- },
data() {
- const { dataset } = dataEl || this.$options.el;
const showSchemaMarkup = parseBoolean(dataset.showSchemaMarkup);
const renderEmptyState = parseBoolean(dataset.renderEmptyState);
- const service = new GroupsService(endpoint || dataset.endpoint);
+ const service = new GroupsService(dataset.endpoint);
const store = new GroupsStore({ hideProjects: true, showSchemaMarkup });
return {
- action,
store,
service,
renderEmptyState,
loading: true,
- containerId,
};
},
beforeMount() {
- if (this.action) {
- return;
- }
-
- const { dataset } = dataEl || this.$options.el;
let groupFilterList = null;
const form = document.querySelector(dataset.formSel);
const filter = document.querySelector(dataset.filterSel);
@@ -102,11 +59,11 @@ export default (containerId = 'js-groups-tree', endpoint, action = '') => {
form,
filter,
holder,
- filterEndpoint: endpoint || dataset.endpoint,
+ filterEndpoint: dataset.endpoint,
pagePath: dataset.path,
dropdownSel: dataset.dropdownSel,
filterInputField: 'filter',
- action: this.action,
+ action: '',
};
groupFilterList = new GroupFilterableList(opts);
@@ -115,11 +72,9 @@ export default (containerId = 'js-groups-tree', endpoint, action = '') => {
render(createElement) {
return createElement('groups-app', {
props: {
- action: this.action,
store: this.store,
service: this.service,
renderEmptyState: this.renderEmptyState,
- containerId: this.containerId,
},
});
},
diff --git a/app/assets/javascripts/pages/explore/groups/index.js b/app/assets/javascripts/pages/explore/groups/index.js
index 05078191e5c..9b60b1f51a8 100644
--- a/app/assets/javascripts/pages/explore/groups/index.js
+++ b/app/assets/javascripts/pages/explore/groups/index.js
@@ -1,9 +1,7 @@
import initGroupsList from '~/groups';
-import GroupsList from '~/groups/groups_list';
import Landing from '~/groups/landing';
function exploreGroups() {
- new GroupsList(); // eslint-disable-line no-new
initGroupsList();
const landingElement = document.querySelector('.js-explore-groups-landing');
if (!landingElement) return;
diff --git a/app/assets/javascripts/profile/edit/components/profile_edit_app.vue b/app/assets/javascripts/profile/edit/components/profile_edit_app.vue
index df7f9a5be81..6b39f137880 100644
--- a/app/assets/javascripts/profile/edit/components/profile_edit_app.vue
+++ b/app/assets/javascripts/profile/edit/components/profile_edit_app.vue
@@ -4,8 +4,12 @@ import { GlForm, GlButton } from '@gitlab/ui';
import { VARIANT_DANGER, VARIANT_INFO, createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { readFileAsDataURL } from '~/lib/utils/file_utility';
+import SetStatusForm from '~/set_status_modal/set_status_form.vue';
+import SettingsBlock from '~/packages_and_registries/shared/components/settings_block.vue';
+import { isUserBusy, computedClearStatusAfterValue } from '~/set_status_modal/utils';
+import { AVAILABILITY_STATUS } from '~/set_status_modal/constants';
-import { i18n } from '../constants';
+import { i18n, statusI18n } from '../constants';
import UserAvatar from './user_avatar.vue';
export default {
@@ -13,7 +17,16 @@ export default {
UserAvatar,
GlForm,
GlButton,
+ SettingsBlock,
+ SetStatusForm,
},
+ inject: [
+ 'currentEmoji',
+ 'currentMessage',
+ 'currentAvailability',
+ 'defaultEmoji',
+ 'currentClearStatusAfter',
+ ],
props: {
profilePath: {
type: String,
@@ -28,14 +41,44 @@ export default {
return {
uploadingProfile: false,
avatarBlob: null,
+ status: {
+ emoji: this.currentEmoji,
+ message: this.currentMessage,
+ availability: isUserBusy(this.currentAvailability),
+ clearStatusAfter: null,
+ },
};
},
+ computed: {
+ shouldIncludeClearStatusAfterInApiRequest() {
+ return this.status.clearStatusAfter !== null;
+ },
+ clearStatusAfterApiRequestValue() {
+ return computedClearStatusAfterValue(this.status.clearStatusAfter);
+ },
+ },
methods: {
async onSubmit() {
// TODO: Do validation before organizing data.
this.uploadingProfile = true;
const formData = new FormData();
+ // Setting up status data
+ const statusFieldNameBase = 'user[status]';
+ formData.append(`${statusFieldNameBase}[emoji]`, this.status.emoji);
+ formData.append(`${statusFieldNameBase}[message]`, this.status.message);
+ formData.append(
+ `${statusFieldNameBase}[availability]`,
+ this.status.availability ? AVAILABILITY_STATUS.BUSY : AVAILABILITY_STATUS.NOT_SET,
+ );
+
+ if (this.shouldIncludeClearStatusAfterInApiRequest) {
+ formData.append(
+ `${statusFieldNameBase}[clear_status_after]`,
+ this.clearStatusAfterApiRequestValue,
+ );
+ }
+
if (this.avatarBlob) {
formData.append('user[avatar]', this.avatarBlob, 'avatar.png');
}
@@ -46,7 +89,6 @@ export default {
if (this.avatarBlob) {
this.syncHeaderAvatars();
}
-
createAlert({
message: data.message,
variant: data.status === 'error' ? VARIANT_DANGER : VARIANT_INFO,
@@ -79,14 +121,47 @@ export default {
onBlobChange(blob) {
this.avatarBlob = blob;
},
+ onMessageInput(value) {
+ this.status.message = value;
+ },
+ onEmojiClick(emoji) {
+ this.status.emoji = emoji;
+ },
+ onClearStatusAfterClick(after) {
+ this.status.clearStatusAfter = after;
+ },
+ onAvailabilityInput(value) {
+ this.status.availability = value;
+ },
+ },
+ i18n: {
+ ...i18n,
+ ...statusI18n,
},
- i18n,
};
</script>
<template>
- <gl-form @submit.prevent="onSubmit">
+ <gl-form class="edit-user" @submit.prevent="onSubmit">
<user-avatar @blob-change="onBlobChange" />
+ <settings-block class="js-search-settings-section">
+ <template #title>{{ $options.i18n.setStatusTitle }}</template>
+ <template #description>{{ $options.i18n.setStatusDescription }}</template>
+ <div class="gl-max-w-80">
+ <set-status-form
+ :default-emoji="defaultEmoji"
+ :emoji="status.emoji"
+ :message="status.message"
+ :availability="status.availability"
+ :clear-status-after="status.clearStatusAfter"
+ :current-clear-status-after="currentClearStatusAfter"
+ @message-input="onMessageInput"
+ @emoji-click="onEmojiClick"
+ @clear-status-after-click="onClearStatusAfterClick"
+ @availability-input="onAvailabilityInput"
+ />
+ </div>
+ </settings-block>
<!-- TODO: to implement profile editing form fields -->
<!-- It will be implemented in the upcoming MRs -->
<!-- Related issue: https://gitlab.com/gitlab-org/gitlab/-/issues/389918 -->
diff --git a/app/assets/javascripts/profile/edit/constants.js b/app/assets/javascripts/profile/edit/constants.js
index ecd6274e39b..e07615273f7 100644
--- a/app/assets/javascripts/profile/edit/constants.js
+++ b/app/assets/javascripts/profile/edit/constants.js
@@ -21,6 +21,13 @@ export const avatarI18n = {
cropAvatarSetAsNewAvatar: s__('Profiles|Set new profile picture'),
};
+export const statusI18n = {
+ setStatusTitle: s__('Profiles|Current status'),
+ setStatusDescription: s__(
+ 'Profiles|This emoji and message will appear on your profile and throughout the interface.',
+ ),
+};
+
export const i18n = {
updateProfileSettings: s__('Profiles|Update profile settings'),
cancel: __('Cancel'),
diff --git a/app/assets/javascripts/profile/edit/index.js b/app/assets/javascripts/profile/edit/index.js
index 1466eede864..27b410c3a12 100644
--- a/app/assets/javascripts/profile/edit/index.js
+++ b/app/assets/javascripts/profile/edit/index.js
@@ -7,13 +7,27 @@ export const initProfileEdit = () => {
if (!mountEl) return false;
- const { profilePath, userPath, ...provides } = mountEl.dataset;
+ const {
+ profilePath,
+ userPath,
+ currentEmoji,
+ currentMessage,
+ currentAvailability,
+ defaultEmoji,
+ currentClearStatusAfter,
+ ...provides
+ } = mountEl.dataset;
return new Vue({
el: mountEl,
name: 'ProfileEditRoot',
provide: {
...provides,
+ currentEmoji,
+ currentMessage,
+ currentAvailability,
+ defaultEmoji,
+ currentClearStatusAfter,
hasAvatar: parseBoolean(provides.hasAvatar),
gravatarEnabled: parseBoolean(provides.gravatarEnabled),
gravatarLink: JSON.parse(provides.gravatarLink),