Skip to content

Commit

Permalink
GUI Issue #3221: Notifications actions
Browse files Browse the repository at this point in the history
GUI Issue #3221: Postpone lifecycle rule action
  • Loading branch information
AleksandrGorodetskii committed Jun 6, 2023
1 parent 4965aba commit b7f540b
Show file tree
Hide file tree
Showing 8 changed files with 499 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@

.notification-grid-row {
display: grid;
grid: "status title body date readDate" 34px / 55px 1fr 1fr 135px 135px;
grid: "status title body date readDate actions" 34px / 55px 1fr 1fr 135px 135px 25px;
padding: 3px 0;
cursor: pointer;
transition: all 0.3s ease;
Expand Down Expand Up @@ -97,6 +97,10 @@
grid-area: readDate;
}

.notification-actions {
grid-area: actions;
}

.empty-placeholder {
padding: 15px;
text-align: center;
Expand Down
20 changes: 19 additions & 1 deletion client/src/components/main/notification/NotificationBrowser.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import NotificationsRequest from '../../../models/notifications/CurrentUserNotif
import ReadAllUserNotifications from '../../../models/notifications/ReadAllUserNotifications';
import displayDate from '../../../utils/displayDate';
import PreviewNotification from './PreviewNotification';
import NotificationActions from './notification-actions';
import styles from './NotificationBrowser.css';

const PAGE_SIZE = 20;
Expand All @@ -54,7 +55,7 @@ function dateSorter (a, b) {
}
};

@inject('userNotifications')
@inject('userNotifications', 'router')
@observer
export default class NotificationBrowser extends React.Component {
state = {
Expand Down Expand Up @@ -214,6 +215,11 @@ export default class NotificationBrowser extends React.Component {
)}>
Read date
</div>
<div className={classNames(
styles.notificationCell,
styles.notificationActions,
styles.header
)} />
</div>
);
};
Expand Down Expand Up @@ -288,6 +294,18 @@ export default class NotificationBrowser extends React.Component {
)}>
{displayDate(notification.readDate, 'YYYY-MM-DD HH:mm:ss')}
</div>
<div
className={classNames(
styles.notificationCell,
styles.notificationActions
)}
onClick={e => e.stopPropagation()}
>
<NotificationActions
notification={notification}
router={this.props.router}
/>
</div>
</div>
))
: emptyPlaceholder
Expand Down
12 changes: 7 additions & 5 deletions client/src/components/main/notification/NotificationCenter.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ function mapMessage (message) {
isRead: message.isRead,
userId: message.userId,
notificationId: `message_${message.id}`,
type: NOTIFICATION_TYPE.message
notificationType: NOTIFICATION_TYPE.message,
resources: message.resources,
type: message.type
};
}

Expand Down Expand Up @@ -309,7 +311,7 @@ export default class NotificationCenter extends React.Component {
id: notification.notificationId,
createdDate: notification.createdDate
});
if (notification.type === NOTIFICATION_TYPE.message) {
if (notification.notificationType === NOTIFICATION_TYPE.message) {
this.readMessage(notification);
}
if (notification.blocking) {
Expand Down Expand Up @@ -459,7 +461,7 @@ export default class NotificationCenter extends React.Component {

openPreviewNotification = (notification) => {
this.setState({previewNotification: notification}, () => {
if (notification.type === NOTIFICATION_TYPE.message) {
if (notification.notificationType === NOTIFICATION_TYPE.message) {
this.readMessage(notification, true);
}
});
Expand Down Expand Up @@ -489,8 +491,8 @@ export default class NotificationCenter extends React.Component {
onHeightInitialized={this.onHeightInitialized}
key={notification.notificationId || notification.createdDate}
notification={notification}
type={notification.type}
onClick={notification.type === NOTIFICATION_TYPE.message
type={notification.notificationType}
onClick={notification.notificationType === NOTIFICATION_TYPE.message
? this.openPreviewNotification
: undefined
}
Expand Down
6 changes: 6 additions & 0 deletions client/src/components/main/notification/SystemNotification.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import classNames from 'classnames';
import displayDate from '../../../utils/displayDate';
import PreviewNotification from './PreviewNotification';
import {NOTIFICATION_TYPE} from './NotificationCenter';
import NotificationActions from './notification-actions';
import styles from './SystemNotification.css';

@observer
Expand Down Expand Up @@ -200,6 +201,11 @@ export default class SystemNotification extends React.Component {
>
{displayDate(this.props.notification.createdDate)}
</span>
<NotificationActions
notification={this.props.notification}
router={this.props.router}
style={{marginLeft: '5px'}}
/>
</Row>
</Row>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
/*
* Copyright 2017-2023 EPAM Systems, Inc. (https://www.epam.com/)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import {message} from 'antd';
import moment from 'moment-timezone';
import StopPipeline from '../../../../models/pipelines/StopPipeline';
import ResumePipeline from '../../../../models/pipelines/ResumePipeline';
import PausePipeline from '../../../../models/pipelines/PausePipeline';
import TerminatePipeline from '../../../../models/pipelines/TerminatePipeline';
import DataStorageLifeCycleRulesPostpone
from '../../../../models/dataStorage/lifeCycleRules/DataStorageLifeCycleRulesPostpone';
import {canPauseRun, canStopRun} from '../../../runs/actions';
import RunStatuses from '../../../special/run-status-icon/run-statuses';

const ACTIONS = {
viewRun: {
key: 'View run',
actionFn: ({entity, router}) => {
router && router.push(`/run/${entity.id}`);
},
available: () => true
},
pauseRun: {
key: 'Pause run',
actionFn: async ({entity, callback}) => {
const hide = message.loading('Pausing...', -1);
const request = new PausePipeline(entity.id);
await request.send({});
if (request.error) {
message.error(request.error);
}
hide();
callback && callback();
},
available: (entity, preferences) => entity && preferences && canPauseRun(entity, preferences)
},
resumeRun: {
key: 'Resume run',
actionFn: async ({entity, callback}) => {
const hide = message.loading('Resuming...', -1);
const request = new ResumePipeline(entity.id);
await request.send({});
if (request.error) {
message.error(request.error);
}
hide();
callback && callback();
},
available: (entity) => entity && entity.status === RunStatuses.paused
},
stopRun: {
key: 'Stop run',
actionFn: async ({entity, callback}) => {
const hide = message.loading('Stopping...', -1);
const request = new StopPipeline(entity.id);
await request.send({
endDate: moment().format('YYYY-MM-DD HH:mm:ss.SSS'),
status: 'STOPPED'
});
if (request.error) {
message.error(request.error);
}
hide();
callback && callback();
},
available: (entity) => entity && canStopRun(entity)
},
terminateRun: {
key: 'Terminate run',
actionFn: async ({entity, callback}) => {
const hide = message.loading('Terminating run...', -1);
const request = new TerminatePipeline(entity.id);
await request.send({});
if (request.error) {
message.error(request.error);
}
hide();
callback && callback();
},
available: (entity) => entity && entity.status === RunStatuses.paused
},
openDatastorage: {
key: 'Open datastorage',
actionFn: ({notification = {}, router}) => {
const details = (notification.resources || [])[0] || {};
const {entityId} = details;
router && entityId && router.push(`/storage/${entityId}`);
},
available: () => true
},
postponeLifecycleRule: {
key: 'Postpone',
actionFn: async ({notification = {}, callback}) => {
const details = (notification.resources || [])[0] || {};
const hide = message.loading('Postpone...', -1);
const request = new DataStorageLifeCycleRulesPostpone({
datastorageId: details.entityId,
ruleId: details.storageRuleId,
path: details.storagePath
});
await request.fetch();
if (request.error) {
message.error(request.error);
}
hide();
callback && callback();
},
available: () => true
},
viewBilling: {
key: 'View billing',
actionFn: ({router}) => {
router && router.push('/billing/reports/storage');
},
available: () => true
},
openPoolsUsage: {
key: 'Open pools usage statistics',
actionFn: ({router}) => {
router && router.push('/cluster/usage');
},
available: () => true
}
};

const ENTITY_CLASSES = {
RUN: 'RUN',
STORAGE: 'STORAGE',
ISSUE: 'ISSUE',
QUOTA: 'QUOTA',
NODE_POOL: 'NODE_POOL',
USER: 'USER'
};

const NOTIFICATION_TYPES = {
BILLING_QUOTA_EXCEEDING: 'BILLING_QUOTA_EXCEEDING',
DATASTORAGE_LIFECYCLE_ACTION: 'DATASTORAGE_LIFECYCLE_ACTION',
DATASTORAGE_LIFECYCLE_RESTORE_ACTION: 'DATASTORAGE_LIFECYCLE_RESTORE_ACTION',
FULL_NODE_POOL: 'FULL_NODE_POOL',
HIGH_CONSUMED_RESOURCES: 'HIGH_CONSUMED_RESOURCES',
IDLE_RUN: 'IDLE_RUN',
IDLE_RUN_PAUSED: 'IDLE_RUN_PAUSED',
IDLE_RUN_STOPPED: 'IDLE_RUN_STOPPED',
LONG_INIT: 'LONG_INIT',
LONG_PAUSED: 'LONG_PAUSED',
LONG_PAUSED_STOPPED: 'LONG_PAUSED_STOPPED',
LONG_RUNNING: 'LONG_RUNNING',
LONG_STATUS: 'LONG_STATUS',
NEW_ISSUE: 'NEW_ISSUE',
NEW_ISSUE_COMMENT: 'NEW_ISSUE_COMMENT',
PIPELINE_RUN_STATUS: 'PIPELINE_RUN_STATUS',
STORAGE_QUOTA_EXCEEDING: 'STORAGE_QUOTA_EXCEEDING',
INACTIVE_USERS: 'INACTIVE_USERS',
LDAP_BLOCKED_POSTPONED_USERS: 'LDAP_BLOCKED_POSTPONED_USERS',
LDAP_BLOCKED_USERS: 'LDAP_BLOCKED_USERS'
};

export {ACTIONS, ENTITY_CLASSES, NOTIFICATION_TYPES};
Loading

0 comments on commit b7f540b

Please sign in to comment.