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
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-11-22 18:11:39 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-11-22 18:11:39 +0300
commit51ad17b4112ce677613ed2af7f8b742fe2ba2afe (patch)
treec67859e3f7f5551a48e5dd3a541e645a1fd1a12d /app
parent49203bfa3c7eb607a7561ae7da9b5c52aa49fd77 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/environments/components/kubernetes_summary.vue1
-rw-r--r--app/assets/javascripts/environments/graphql/resolvers/kubernetes.js46
-rw-r--r--app/assets/javascripts/environments/helpers/k8s_integration_helper.js12
-rw-r--r--app/assets/javascripts/graphql_shared/constants.js1
-rw-r--r--app/assets/javascripts/import/constants.js3
-rw-r--r--app/assets/javascripts/import/details/components/import_details_table.vue1
-rw-r--r--app/assets/javascripts/import_entities/import_groups/graphql/client_factory.js2
-rw-r--r--app/assets/javascripts/invite_members/components/invite_groups_modal.vue6
-rw-r--r--app/assets/javascripts/invite_members/components/invite_members_modal.vue19
-rw-r--r--app/assets/javascripts/invite_members/components/invite_modal_base.vue43
-rw-r--r--app/assets/javascripts/invite_members/init_invite_members_modal.js1
11 files changed, 115 insertions, 20 deletions
diff --git a/app/assets/javascripts/environments/components/kubernetes_summary.vue b/app/assets/javascripts/environments/components/kubernetes_summary.vue
index e2fbc6fd2e7..1f4e91afe35 100644
--- a/app/assets/javascripts/environments/components/kubernetes_summary.vue
+++ b/app/assets/javascripts/environments/components/kubernetes_summary.vue
@@ -159,6 +159,7 @@ export default {
completed: 'success',
failed: 'danger',
suspended: 'neutral',
+ pending: 'info',
},
icons: {
Active: { icon: 'status_success', class: 'gl-text-green-500' },
diff --git a/app/assets/javascripts/environments/graphql/resolvers/kubernetes.js b/app/assets/javascripts/environments/graphql/resolvers/kubernetes.js
index 8375b8793d9..1bc8706cfce 100644
--- a/app/assets/javascripts/environments/graphql/resolvers/kubernetes.js
+++ b/app/assets/javascripts/environments/graphql/resolvers/kubernetes.js
@@ -6,8 +6,10 @@ import {
WatchApi,
EVENT_DATA,
} from '@gitlab/cluster-client';
+import produce from 'immer';
import { humanizeClusterErrors } from '../../helpers/k8s_integration_helper';
import k8sPodsQuery from '../queries/k8s_pods.query.graphql';
+import k8sWorkloadsQuery from '../queries/k8s_workloads.query.graphql';
const mapWorkloadItems = (items, kind) => {
return items.map((item) => {
@@ -88,6 +90,44 @@ const watchPods = ({ configuration, namespace, client }) => {
});
};
+const watchWorkloadItems = ({ kind, apiVersion, configuration, namespace, client }) => {
+ const itemKind = kind.toLowerCase().replace('list', 's');
+
+ const path = namespace
+ ? `/apis/${apiVersion}/namespaces/${namespace}/${itemKind}`
+ : `/apis/${apiVersion}/${itemKind}`;
+ const config = new Configuration(configuration);
+ const watcherApi = new WatchApi(config);
+
+ watcherApi
+ .subscribeToStream(path, { watch: true })
+ .then((watcher) => {
+ let result = [];
+
+ watcher.on(EVENT_DATA, (data) => {
+ result = mapWorkloadItems(data, kind);
+
+ const sourceData = client.readQuery({
+ query: k8sWorkloadsQuery,
+ variables: { configuration, namespace },
+ });
+
+ const updatedData = produce(sourceData, (draft) => {
+ draft.k8sWorkloads[kind] = result;
+ });
+
+ client.writeQuery({
+ query: k8sWorkloadsQuery,
+ variables: { configuration, namespace },
+ data: updatedData,
+ });
+ });
+ })
+ .catch((err) => {
+ handleClusterError(err);
+ });
+};
+
export default {
k8sPods(_, { configuration, namespace }, { client }) {
const config = new Configuration(configuration);
@@ -143,7 +183,7 @@ export default {
}
});
},
- k8sWorkloads(_, { configuration, namespace }) {
+ k8sWorkloads(_, { configuration, namespace }, { client }) {
const appsV1api = new AppsV1Api(new Configuration(configuration));
const batchV1api = new BatchV1Api(new Configuration(configuration));
@@ -189,10 +229,12 @@ export default {
}
for (const promiseResult of results) {
if (promiseResult.status === 'fulfilled' && promiseResult?.value) {
- const { kind, items } = promiseResult.value;
+ const { kind, items, apiVersion } = promiseResult.value;
if (items?.length > 0) {
summaryList[kind] = mapWorkloadItems(items, kind);
+
+ watchWorkloadItems({ kind, apiVersion, configuration, namespace, client });
}
}
}
diff --git a/app/assets/javascripts/environments/helpers/k8s_integration_helper.js b/app/assets/javascripts/environments/helpers/k8s_integration_helper.js
index 164a2d98e90..93a78e21dfb 100644
--- a/app/assets/javascripts/environments/helpers/k8s_integration_helper.js
+++ b/app/assets/javascripts/environments/helpers/k8s_integration_helper.js
@@ -1,5 +1,5 @@
import { differenceInSeconds } from '~/lib/utils/datetime_utility';
-import { CLUSTER_AGENT_ERROR_MESSAGES } from '../constants';
+import { CLUSTER_AGENT_ERROR_MESSAGES, STATUS_TRUE, STATUS_FALSE } from '../constants';
export function generateServicePortsString(ports) {
if (!ports?.length) return '';
@@ -39,19 +39,21 @@ export function getServiceAge(creationTimestamp) {
export function getDeploymentsStatuses(items) {
const failed = [];
const ready = [];
+ const pending = [];
items.forEach((item) => {
const [available, progressing] = item.status?.conditions ?? [];
- // eslint-disable-next-line @gitlab/require-i18n-strings
- if (available.status === 'True') {
+ if (available?.status === STATUS_TRUE) {
ready.push(item);
- // eslint-disable-next-line @gitlab/require-i18n-strings
- } else if (available.status !== 'True' && progressing.status !== 'True') {
+ } else if (available?.status === STATUS_FALSE && progressing?.status !== STATUS_TRUE) {
failed.push(item);
+ } else {
+ pending.push(item);
}
});
return {
+ ...(pending.length && { pending }),
...(failed.length && { failed }),
...(ready.length && { ready }),
};
diff --git a/app/assets/javascripts/graphql_shared/constants.js b/app/assets/javascripts/graphql_shared/constants.js
index 7f2c41d9aaf..ef0dcea26ad 100644
--- a/app/assets/javascripts/graphql_shared/constants.js
+++ b/app/assets/javascripts/graphql_shared/constants.js
@@ -15,6 +15,7 @@ export const TYPENAME_GROUP = 'Group';
export const TYPENAME_ISSUE = 'Issue';
export const TYPENAME_ITERATION = 'Iteration';
export const TYPENAME_ITERATIONS_CADENCE = 'Iterations::Cadence';
+export const TYPENAME_MEMBER_ROLE = 'MemberRole';
export const TYPENAME_MERGE_REQUEST = 'MergeRequest';
export const TYPENAME_MILESTONE = 'Milestone';
export const TYPENAME_NOTE = 'Note';
diff --git a/app/assets/javascripts/import/constants.js b/app/assets/javascripts/import/constants.js
index b02eb3c4307..cbb01d0bbf1 100644
--- a/app/assets/javascripts/import/constants.js
+++ b/app/assets/javascripts/import/constants.js
@@ -7,9 +7,12 @@ export const BULK_IMPORT_STATIC_ITEMS = {
epics: __('Epic'),
issues: __('Issue'),
labels: __('Label'),
+ iterations: __('Iteration'),
+ iterations_cadences: s__('Iterations|Iteration cadence'),
members: __('Member'),
merge_requests: __('Merge request'),
milestones: __('Milestone'),
+ namespace_settings: s__('GroupSettings|Namespace setting'),
project: __('Project'),
};
diff --git a/app/assets/javascripts/import/details/components/import_details_table.vue b/app/assets/javascripts/import/details/components/import_details_table.vue
index 535ccb525ac..fa22991bec0 100644
--- a/app/assets/javascripts/import/details/components/import_details_table.vue
+++ b/app/assets/javascripts/import/details/components/import_details_table.vue
@@ -21,7 +21,6 @@ export default {
GlTable,
PaginationBar,
},
- STATISTIC_ITEMS,
i18n: {
fetchErrorMessage: s__('Import|An error occurred while fetching import details.'),
diff --git a/app/assets/javascripts/import_entities/import_groups/graphql/client_factory.js b/app/assets/javascripts/import_entities/import_groups/graphql/client_factory.js
index 69e669b9abd..4046d25acc3 100644
--- a/app/assets/javascripts/import_entities/import_groups/graphql/client_factory.js
+++ b/app/assets/javascripts/import_entities/import_groups/graphql/client_factory.js
@@ -111,7 +111,7 @@ export function createResolvers({ endpoints }) {
},
},
Mutation: {
- async updateImportStatus(
+ updateImportStatus(
_,
{ id, status: newStatus, hasFailures = false },
{ client, getCacheKey },
diff --git a/app/assets/javascripts/invite_members/components/invite_groups_modal.vue b/app/assets/javascripts/invite_members/components/invite_groups_modal.vue
index ceb9200dfad..9893572ae16 100644
--- a/app/assets/javascripts/invite_members/components/invite_groups_modal.vue
+++ b/app/assets/javascripts/invite_members/components/invite_groups_modal.vue
@@ -106,6 +106,9 @@ export default {
inviteDisabled() {
return Object.keys(this.groupToBeSharedWith).length === 0;
},
+ staticRoles() {
+ return { validRoles: this.accessLevels };
+ },
},
mounted() {
if (this.reloadPageOnSubmit) {
@@ -182,7 +185,7 @@ export default {
:modal-id="modalId"
:modal-title="$options.labels.title"
:name="name"
- :access-levels="accessLevels"
+ :access-levels="staticRoles"
:default-access-level="defaultAccessLevel"
:help-link="helpLink"
v-bind="$attrs"
@@ -194,6 +197,7 @@ export default {
:invalid-feedback-message="invalidFeedbackMessage"
:is-loading="isLoading"
:full-path="fullPath"
+ is-group-invite
@reset="resetFields"
@submit="sendInvite"
>
diff --git a/app/assets/javascripts/invite_members/components/invite_members_modal.vue b/app/assets/javascripts/invite_members/components/invite_members_modal.vue
index 27124808550..91158ef15c8 100644
--- a/app/assets/javascripts/invite_members/components/invite_members_modal.vue
+++ b/app/assets/javascripts/invite_members/components/invite_members_modal.vue
@@ -85,6 +85,11 @@ export default {
type: Number,
required: true,
},
+ defaultMemberRoleId: {
+ type: Number,
+ required: false,
+ default: null,
+ },
helpLink: {
type: String,
required: true,
@@ -181,6 +186,9 @@ export default {
showUserLimitNotification() {
return !isEmpty(this.usersLimitDataset.alertVariant);
},
+ staticRoles() {
+ return { validRoles: this.accessLevels };
+ },
limitVariant() {
return this.usersLimitDataset.alertVariant;
},
@@ -267,7 +275,7 @@ export default {
this.shouldShowEmptyInvitesAlert = true;
this.$refs.alerts.focus();
},
- getInvitePayload({ accessLevel, expiresAt }) {
+ getInvitePayload({ accessLevel, expiresAt, memberRoleId }) {
const [usersToInviteByEmail, usersToAddById] = this.partitionNewUsersToInvite();
const email = usersToInviteByEmail !== '' ? { email: usersToInviteByEmail } : {};
@@ -277,12 +285,13 @@ export default {
format: 'json',
expires_at: expiresAt,
access_level: accessLevel,
+ member_role_id: memberRoleId,
invite_source: this.source,
...email,
...userId,
};
},
- async sendInvite({ accessLevel, expiresAt }) {
+ async sendInvite({ accessLevel, expiresAt, memberRoleId }) {
this.isLoading = true;
this.clearValidation();
@@ -296,7 +305,7 @@ export default {
: Api.inviteGroupMembers.bind(Api);
try {
- const payload = this.getInvitePayload({ accessLevel, expiresAt });
+ const payload = this.getInvitePayload({ accessLevel, expiresAt, memberRoleId });
const response = await apiAddByInvite(this.id, payload);
const { error, message } = responseFromSuccess(response);
@@ -377,14 +386,16 @@ export default {
:modal-id="modalId"
:modal-title="modalTitle"
:name="name"
- :access-levels="accessLevels"
+ :access-levels="staticRoles"
:default-access-level="defaultAccessLevel"
+ :default-member-role-id="defaultMemberRoleId"
:help-link="helpLink"
:label-intro-text="labelIntroText"
:label-search-field="labelSearchField"
:form-group-description="formGroupDescription"
:invalid-feedback-message="invalidFeedbackMessage"
:is-loading="isLoading"
+ :is-project="isProject"
:new-users-to-invite="newUsersToInvite"
:root-group-id="rootId"
:users-limit-dataset="usersLimitDataset"
diff --git a/app/assets/javascripts/invite_members/components/invite_modal_base.vue b/app/assets/javascripts/invite_members/components/invite_modal_base.vue
index 86e3e56a525..00b7c3f4bdd 100644
--- a/app/assets/javascripts/invite_members/components/invite_modal_base.vue
+++ b/app/assets/javascripts/invite_members/components/invite_modal_base.vue
@@ -12,6 +12,7 @@ import {
import Tracking from '~/tracking';
import { sprintf } from '~/locale';
import ContentTransition from '~/vue_shared/components/content_transition.vue';
+import { initialSelectedRole, roleDropdownItems } from 'ee_else_ce/members/utils';
import {
ACCESS_LEVEL,
ACCESS_EXPIRE_DATE,
@@ -68,6 +69,11 @@ export default {
type: Number,
required: true,
},
+ defaultMemberRoleId: {
+ type: Number,
+ required: false,
+ default: null,
+ },
helpLink: {
type: String,
required: true,
@@ -95,6 +101,11 @@ export default {
required: false,
default: false,
},
+ isLoadingRoles: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
invalidFeedbackMessage: {
type: String,
required: false,
@@ -134,14 +145,14 @@ export default {
data() {
// Be sure to check out reset!
return {
- selectedAccessLevel: this.defaultAccessLevel,
+ selectedAccessLevel: null,
selectedDate: undefined,
minDate: new Date(),
};
},
computed: {
- accessLevelsOptions() {
- return Object.entries(this.accessLevels).map(([text, value]) => ({ text, value }));
+ accessLevelOptions() {
+ return roleDropdownItems(this.accessLevels);
},
introText() {
return sprintf(this.labelIntroText, { name: this.name });
@@ -188,11 +199,17 @@ export default {
};
},
},
+ watch: {
+ accessLevelOptions: {
+ immediate: true,
+ handler: 'resetSelectedAccessLevel',
+ },
+ },
methods: {
onReset() {
// This component isn't necessarily disposed,
// so we might need to reset it's state.
- this.selectedAccessLevel = this.defaultAccessLevel;
+ this.resetSelectedAccessLevel();
this.selectedDate = undefined;
this.$emit('reset');
@@ -216,14 +233,27 @@ export default {
// We never want to hide when submitting
e.preventDefault();
+ const { accessLevel, memberRoleId } = this.accessLevelOptions.flatten.find(
+ (item) => item.value === this.selectedAccessLevel,
+ );
this.$emit('submit', {
- accessLevel: this.selectedAccessLevel,
+ accessLevel,
+ memberRoleId,
expiresAt: this.selectedDate,
});
},
onClose() {
this.$emit('close');
},
+ resetSelectedAccessLevel() {
+ const accessLevel = {
+ integerValue: this.defaultAccessLevel,
+ memberRoleId: this.defaultMemberRoleId,
+ };
+ this.selectedAccessLevel = initialSelectedRole(this.accessLevelOptions.flatten, {
+ accessLevel,
+ });
+ },
},
HEADER_CLOSE_LABEL,
ACCESS_EXPIRE_DATE,
@@ -298,7 +328,8 @@ export default {
:id="dropdownId"
v-model="selectedAccessLevel"
data-testid="access-level-dropdown"
- :items="accessLevelsOptions"
+ :items="accessLevelOptions.formatted"
+ :loading="isLoadingRoles"
block
/>
</gl-form-group>
diff --git a/app/assets/javascripts/invite_members/init_invite_members_modal.js b/app/assets/javascripts/invite_members/init_invite_members_modal.js
index 8dfe697e2cb..bd291ecc90f 100644
--- a/app/assets/javascripts/invite_members/init_invite_members_modal.js
+++ b/app/assets/javascripts/invite_members/init_invite_members_modal.js
@@ -36,6 +36,7 @@ export default (function initInviteMembersModal() {
isProject: parseBoolean(el.dataset.isProject),
accessLevels: JSON.parse(el.dataset.accessLevels),
defaultAccessLevel: parseInt(el.dataset.defaultAccessLevel, 10),
+ defaultMemberRoleId: parseInt(el.dataset.defaultMemberRoleId, 10) || null,
usersFilter: el.dataset.usersFilter,
filterId: parseInt(el.dataset.filterId, 10),
usersLimitDataset: convertObjectPropsToCamelCase(