Skip to content

Commit

Permalink
Support indeterminate progress notifications
Browse files Browse the repository at this point in the history
  * Default to `progress` notification type if `showProgress()` is used
     instead of overwriting it with `info`
  * Pass through `progress` notification type to view
  * Show indeterminate progress animation if type `progress`
     but without specifying a numeric `progress` value > 0
  * Use `info` icon by default in view for `progress` notifications
  * Add sample menu contributions to document and test progress
    notifications with determinate and indeterminate progress

Fixes eclipse-theia#10944

Change-Id: Ieaf0e775cd1ad282b396c26c9047f4930f483712
  • Loading branch information
planger committed Mar 29, 2022
1 parent 42c93b0 commit 9f7c090
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 4 deletions.
63 changes: 63 additions & 0 deletions examples/api-samples/src/browser/menu/sample-menu-contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ const SampleCommand2: Command = {
id: 'sample-command2',
label: 'Sample Command2'
};
const SampleCommandWithProgressMessage: Command = {
id: 'sample-command-with-progress',
label: 'Sample Command With Progress Message'
};
const SampleCommandWithIndeterminateProgressMessage: Command = {
id: 'sample-command-with-indeterminate-progress',
label: 'Sample Command With Indeterminate Progress Message'
};
const SampleQuickInputCommand: Command = {
id: 'sample-quick-input-command',
category: 'Quick Input',
Expand Down Expand Up @@ -77,6 +85,61 @@ export class SampleCommandContribution implements CommandContribution {
}
}
});
commands.registerCommand(SampleCommandWithProgressMessage, {
execute: () => {
this.messageService
.showProgress({
text: 'Starting to report progress',
})
.then(progress => {
window.setTimeout(() => {
progress.report({
message: 'First step completed',
work: { done: 25, total: 100 }
});
}, 2000);
window.setTimeout(() => {
progress.report({
message: 'Next step completed',
work: { done: 60, total: 100 }
});
}, 4000);
window.setTimeout(() => {
progress.report({
message: 'Complete',
work: { done: 100, total: 100 }
});
}, 6000);
window.setTimeout(() => progress.cancel(), 7000);
});
}
});
commands.registerCommand(SampleCommandWithIndeterminateProgressMessage, {
execute: () => {
this.messageService
.showProgress({
text: 'Starting to report indeterminate progress',
})
.then(progress => {
window.setTimeout(() => {
progress.report({
message: 'First step completed',
});
}, 2000);
window.setTimeout(() => {
progress.report({
message: 'Next step completed',
});
}, 4000);
window.setTimeout(() => {
progress.report({
message: 'Complete',
});
}, 6000);
window.setTimeout(() => progress.cancel(), 7000);
});
}
});
}

}
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/common/message-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,12 +195,13 @@ export class MessageService {
const report = (update: ProgressUpdate) => {
this.client.reportProgress(id, update, message, cancellationSource.token);
};
const type = message.type ?? MessageType.Progress;
const actions = new Set<string>(message.actions);
if (ProgressMessage.isCancelable(message)) {
actions.delete(ProgressMessage.Cancel);
actions.add(ProgressMessage.Cancel);
}
const clientMessage = { ...message, actions: Array.from(actions) };
const clientMessage = { ...message, type, actions: Array.from(actions) };
const result = this.client.showProgress(id, clientMessage, cancellationSource.token);
if (ProgressMessage.isCancelable(message) && typeof onDidCancel === 'function') {
result.then(value => {
Expand Down
8 changes: 5 additions & 3 deletions packages/messages/src/browser/notification-component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,12 @@ export class NotificationComponent extends React.Component<NotificationComponent

override render(): React.ReactNode {
const { messageId, message, type, progress, collapsed, expandable, source, actions } = this.props.notification;
const isProgress = typeof progress === 'number';
const isProgress = type === 'progress' || typeof progress === 'number';
const icon = type === 'progress' ? 'info' : type;
return (<div key={messageId} className='theia-notification-list-item' tabIndex={0}>
<div className={`theia-notification-list-item-content ${collapsed ? 'collapsed' : ''}`}>
<div className='theia-notification-list-item-content-main'>
<div className={`theia-notification-icon ${codicon(type)} ${type}`} />
<div className={`theia-notification-icon ${codicon(icon)} ${icon}`} />
<div className='theia-notification-message'>
<span
// eslint-disable-next-line react/no-danger
Expand Down Expand Up @@ -115,7 +116,8 @@ export class NotificationComponent extends React.Component<NotificationComponent
</div>
{isProgress && (
<div className='theia-notification-item-progress'>
<div className='theia-notification-item-progressbar' style={{ width: `${progress}%` }} />
<div className={`theia-notification-item-progressbar ${progress ? 'determinate' : 'indeterminate'}`}
style={{ width: `${progress ?? '100'}%` }} />
</div>
)}
</div>);
Expand Down
19 changes: 19 additions & 0 deletions packages/messages/src/browser/style/notifications.css
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,25 @@
width: 66%;
}

.theia-notification-item-progressbar.indeterminate {
animation: progress-animation 1.3s 0s infinite cubic-bezier(0.645, 0.045, 0.355, 1);
}

@keyframes progress-animation {
0% {
margin-left: 0%;
width: 3%;
}
60% {
margin-left: 45%;
width: 20%;
}
100% {
margin-left: 99%;
width: 1%;
}
}

/* Perfect scrollbar */

.theia-notification-list-scroll-container .ps__rail-y {
Expand Down

0 comments on commit 9f7c090

Please sign in to comment.