Skip to content

Commit

Permalink
Added busy indicator to StatusBar during activation, fixes #6
Browse files Browse the repository at this point in the history
  • Loading branch information
Radeonmann committed Jan 17, 2022
1 parent 9678470 commit 61dcbb2
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 2 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ Add new but unreleased features, fixes... here during development
[#31](https://github.com/br-automation-com/vscode-brautomationtools/issues/31)
- A new notification is shown, if a setting which requires a reload was changed. A reload can be triggered directly in the notification.
[#18](https://github.com/br-automation-com/vscode-brautomationtools/issues/18)
- A StatusBar item was added which shows that the extension is currently busy. When hovering it with the mouse, a tooltip shows which tasks are currently executed.
At the moment it is only shown during activation of the extension, but in the future other events, such as running builds etc. may be added.
[#6](https://github.com/br-automation-com/vscode-brautomationtools/issues/6)


## [0.0.5] - 2022-01-16
Expand Down
Binary file added Doc/Screenshots/StatusBarBusyIndicator.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ B&R ressources such as executuable binaries etc. are not provided by this extens
- [Transfer the project to a PLC or ArSim](#transfer-the-project-to-a-plc-or-arsim)
- [Detecting installed B&R PVI versions](#detecting-installed-br-pvi-versions)
- [Logging](#logging)
- [UI Elements](#ui-elements)
- [Commands](#commands)
- [Settings](#settings)
- [Requirements](#requirements)
- [Known issues](#known-issues)
Expand Down Expand Up @@ -336,6 +338,22 @@ logging.prettyPrintAdditionalData = true;
}
```

## UI Elements

### Status Bar

#### Busy indicator

The busy indicator in the status bar is shown whenever the extension is busy with a longer running task such as parsing the Automation Studio projects in the workspace. When hovering the indicator with the mouse pointer, a tooltip shows which tasks are currently executing.

![Status bar busy indicator](Doc/Screenshots/StatusBarBusyIndicator.png)

At the moment this indicator is only shown during extension activation.

## Commands

TODO command descriptions

## Settings

| Name | Description |
Expand Down
27 changes: 27 additions & 0 deletions src/Tools/ApiTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import * as BRAsProjectWorkspace from '../BRAsProjectWorkspace';
import * as BrAsProjectFiles from '../BrAsProjectFiles';
import { logger } from '../BrLog';
import { extensionConfiguration } from '../BRConfiguration';
import { statusBar } from '../UI/StatusBar';
//import * as NAME from '../BRxxxxxx';


Expand Down Expand Up @@ -68,6 +69,9 @@ async function testCommand(arg1: any, arg2: any, context: vscode.ExtensionContex
if (await Dialogs.yesNoDialog('Run tests for BrLog')) {
await testBrLog(context);
}
if (await Dialogs.yesNoDialog('Run tests for StatusBar')) {
await testStatusBar(context);
}
// end
logHeader('Test command end');
}
Expand Down Expand Up @@ -491,6 +495,29 @@ async function testBrLog(context: vscode.ExtensionContext): Promise<void> {
logHeader('Test BrLog end');
}


async function testStatusBar(context: vscode.ExtensionContext): Promise<void> {
logHeader('Test StatusBar start');
// start multiple timers
const resolveIn5 = new Promise((resolve) => setTimeout(resolve, 5000));
const resolveIn10 = new Promise((resolve) => setTimeout(resolve, 10000));
const resolveIn15 = new Promise((resolve) => setTimeout(resolve, 15000));
const rejectIn20 = new Promise((resolve, reject) => setTimeout(reject, 20000));
const resolveIn25 = new Promise((resolve) => setTimeout(resolve, 25000));
const resolveIn30 = new Promise((resolve) => setTimeout(resolve, 30000));
// Normal busy items
statusBar.addBusyItem(resolveIn5, 'Resolve in 5 seconds');
statusBar.addBusyItem(resolveIn10, 'Resolve in 10 seconds');
statusBar.addBusyItem(rejectIn20, 'Reject in 20 seconds');
// manual remove busy item
const manualRemove = statusBar.addBusyItem(resolveIn15, 'Resolve in 15 seconds, but remove after 10');
resolveIn10.then(() => statusBar.removeBusyItem(manualRemove));
// empty busy item coming later
resolveIn25.then(() => statusBar.addBusyItem(resolveIn30));
logHeader('Test StatusBar end');
}


function logHeader(text: string): void {
const separator = ''.padEnd(100, '*');
logger.info('');
Expand Down
90 changes: 90 additions & 0 deletions src/UI/StatusBar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**
* Handles notifications in the Status Bar of VS code
* Check the guidelines for dos and donts
* https://code.visualstudio.com/api/references/extension-guidelines#status-bar
* @packageDocumentation
*/

import * as vscode from 'vscode';


export interface BusyItem {
whenDone: Promise<any>,
text: string | undefined
}


/** Status bar handling */
class StatusBar {
static #instance: StatusBar = new StatusBar();
public static getInstance(): StatusBar {
return this.#instance;
}


private constructor() {
// init busy status
this.#busyStatus.name = 'B&R Tools busy indicator';
this.#busyStatus.text = '$(sync~spin) B&R Tools';
}


/** Status bar busy indicator */
#busyStatus = vscode.window.createStatusBarItem('vscode-brautomationtools.busyStatus',vscode.StatusBarAlignment.Left);
/** Items shown in the status bar busy indicator */
#busyItems: Set<BusyItem> = new Set();


/**
* Adds an item to the busy indicator in the status bar. Can be used for long running processes to show a feedback to the user.
* When no item has an unresolved promise left, the busy indicator will be hidden.
* @param hideWhenDone A promise which when resolved removes the item from the busy indicator
* @param text An optional text which is shown as a line in the tooltip of the busy indicator
* @returns The item which was created. It can be used to remove the item from the indicator before the promis was resolved.
*/
addBusyItem(hideWhenDone: Promise<any>, text?: string | undefined): BusyItem {
const item = {
whenDone: hideWhenDone,
text: text
};
this.#busyItems.add(item);
this.#updateBusyStatus();
hideWhenDone.then(() => this.removeBusyItem(item), () => this.removeBusyItem(item));
return item;
}


/**
* Removes an item from the busy indicator in the status bar.
* @param item The item to remove from the busy indicator
*/
removeBusyItem(item: BusyItem) {
this.#busyItems.delete(item);
this.#updateBusyStatus();
}


/** Updates the status of the busy indicator. */
#updateBusyStatus() {
if (this.#busyItems.size === 0) {
this.#busyStatus.hide();
return;
}
const tooltipLines: string[] = [];
for (const item of this.#busyItems) {
if (item.text) {
tooltipLines.push(`$(sync~spin) ${item.text}`);
}
}
const toolTipRaw = tooltipLines.join('\n\n');
this.#busyStatus.tooltip = new vscode.MarkdownString(toolTipRaw, true);
this.#busyStatus.show();
}

dispose() {
this.#busyStatus.dispose();
}
}

/** Access to the VS Code StatusBar */
export const statusBar = StatusBar.getInstance();
20 changes: 18 additions & 2 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ import {registerCppToolsConfigurationProvider} from './ExternalApi/CppToolsApi';
import {registerTaskProviders as registerBuildTaskProviders} from './BrAsBuildTaskProvider';
import {registerTaskProviders as registerTransferTaskProviders} from './BrAsTransferTaskProvider';
import {registerApiTests} from './Tools/ApiTests';
import {registerProjectWorkspace} from './BRAsProjectWorkspace';
import {getWorkspaceProjects, registerProjectWorkspace} from './BRAsProjectWorkspace';
import { notifications } from './UI/Notifications';
import { extensionState } from './BrExtensionState';
import { extensionConfiguration } from './BRConfiguration';
import { getAvailableAutomationStudioVersions, getAvailablePviVersions } from './BREnvironment';
import { statusBar } from './UI/StatusBar';


// Activation event
Expand All @@ -24,16 +26,30 @@ export async function activate(context: vscode.ExtensionContext) {
prettyPrintAdditionalData: extensionConfiguration.logging.prettyPrintAdditionalData
};
logger.info('Start activation of B&R Automation Tools extension');
//
// Initialize modules
extensionState.initialize(context);
notifications.initialize(context);
notifications.newVersionMessage();
registerApiTests(context);
registerCommands(context);
registerBuildTaskProviders(context);
registerTransferTaskProviders(context);
// get promises for long running activation events and add to status bar
const waitAsVersion = getAvailableAutomationStudioVersions();
statusBar.addBusyItem(waitAsVersion, 'Searching for installed AS versions');
const waitPviVersions = getAvailablePviVersions();
statusBar.addBusyItem(waitPviVersions, 'Searching for installed PVI versions');
const waitWorkspaceProjects = getWorkspaceProjects();
statusBar.addBusyItem(waitWorkspaceProjects, 'Parsing AS projects in workspace');
// TODO do we need to await these? Will probably be remove after architectural changes #5
await registerCppToolsConfigurationProvider(context);
await registerProjectWorkspace(context);
// Show activation message and log entry when all is done
await Promise.all([
waitAsVersion,
waitPviVersions,
waitWorkspaceProjects,
]);
logger.info('Activation of B&R Automation Tools extension finished');
notifications.activationMessage();
}
Expand Down

0 comments on commit 61dcbb2

Please sign in to comment.