Fix workspaces for UD (#15784)
* fix workspace list Signed-off-by: Oleksii Orel <oorel@redhat.com>7.20.x
parent
28b42e335b
commit
e8ab082be1
|
|
@ -76,7 +76,6 @@ export class TemplateListController {
|
|||
this.cheNotification = cheNotification;
|
||||
this.devfileRegistry = devfileRegistry;
|
||||
this.createWorkspaceSvc = createWorkspaceSvc;
|
||||
this.devfileRegistryUrl = cheWorkspace.getWorkspaceSettings().cheWorkspaceDevfileRegistryUrl;
|
||||
|
||||
this.createButtonConfig = {
|
||||
mainAction: {
|
||||
|
|
@ -102,10 +101,20 @@ export class TemplateListController {
|
|||
}]
|
||||
};
|
||||
|
||||
this.init();
|
||||
cheWorkspace.fetchWorkspaceSettings().then(() => {
|
||||
const workspaceSettings = cheWorkspace.getWorkspaceSettings();
|
||||
this.devfileRegistryUrl = workspaceSettings && workspaceSettings.cheWorkspaceDevfileRegistryUrl;
|
||||
this.init();
|
||||
});
|
||||
}
|
||||
|
||||
private init(): void {
|
||||
if (!this.devfileRegistryUrl) {
|
||||
const message = 'Failed to load the devfile registry URL.';
|
||||
this.cheNotification.showError(message);
|
||||
this.$log.error(message);
|
||||
return;
|
||||
}
|
||||
this.isLoading = true;
|
||||
this.devfileRegistry.fetchDevfiles(this.devfileRegistryUrl).then((devfiles: Array<IDevfileMetaData>) => {
|
||||
this.devfiles = devfiles.map(devfile => {
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@
|
|||
<!-- Template header -->
|
||||
<div flex="100" layout="row" layout-align="start center" class="template-header">
|
||||
<div flex>
|
||||
<div class="header-title">Select a Template</div>
|
||||
<div class="header-description">Use a sample template to create your first workspace.</div>
|
||||
<div class="header-title">Select a Sample</div>
|
||||
<div class="header-description">Use a sample to create your first workspace.</div>
|
||||
</div>
|
||||
<div flex class="template-search">
|
||||
<div flex="100" layout="row">
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
.getting-started-toolbar
|
||||
div.getting-started-toolbar
|
||||
border-bottom 1px solid $very-light-grey-background-color
|
||||
user-select none
|
||||
|
||||
md-toolbar
|
||||
height: 110px;
|
||||
height 110px
|
||||
max-height 110px
|
||||
|
||||
div.che-toolbar-header div:last-child
|
||||
bottom initial
|
||||
|
|
@ -28,15 +29,13 @@
|
|||
line-height 40px !important
|
||||
|
||||
md-content.getting-started
|
||||
background-color $very-light-grey-background-color
|
||||
padding-left 10px
|
||||
|
||||
& > *
|
||||
background-color $background-color
|
||||
|
||||
.getting-started-list
|
||||
che-box-shadow()
|
||||
margin 15px
|
||||
border 15px solid $very-light-grey-background-color
|
||||
border-left-width 25px
|
||||
|
||||
.template-header
|
||||
margin 15px
|
||||
|
|
|
|||
|
|
@ -71,6 +71,9 @@ export class CheNavBarController {
|
|||
private isPermissionServiceAvailable: boolean;
|
||||
private isKeycloackPresent: boolean;
|
||||
|
||||
private workspacesNumber: number;
|
||||
private pageFactories: Array<che.IFactory>;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
|
|
@ -92,6 +95,15 @@ export class CheNavBarController {
|
|||
this.chePermissions = chePermissions;
|
||||
this.cheKeycloak = cheKeycloak;
|
||||
this.cheService = cheService;
|
||||
|
||||
const handler = (workspaces: Array<che.IWorkspace>) => {
|
||||
this.workspacesNumber = workspaces.length;
|
||||
};
|
||||
this.cheAPI.getWorkspace().addListener('onChangeWorkspaces', handler);
|
||||
|
||||
$scope.$on('$destroy', () => {
|
||||
this.cheAPI.getWorkspace().removeListener('onChangeWorkspaces', handler);
|
||||
});
|
||||
}
|
||||
|
||||
$onInit(): void {
|
||||
|
|
@ -105,8 +117,13 @@ export class CheNavBarController {
|
|||
this.$scope.$broadcast('navbar-selected:set', path);
|
||||
});
|
||||
|
||||
this.cheAPI.getWorkspace().fetchWorkspaces();
|
||||
this.cheAPI.getFactory().fetchFactories();
|
||||
this.cheAPI.getWorkspace().fetchWorkspaces().then((workspaces: Array<che.IWorkspace>) => {
|
||||
this.workspacesNumber = workspaces.length;
|
||||
});
|
||||
|
||||
this.cheAPI.getFactory().fetchFactories().then(() => {
|
||||
this.pageFactories = this.cheAPI.getFactory().getPageFactories();
|
||||
});
|
||||
|
||||
this.isPermissionServiceAvailable = false;
|
||||
this.resolvePermissionServiceAvailability().then((isAvailable: boolean) => {
|
||||
|
|
@ -167,20 +184,12 @@ export class CheNavBarController {
|
|||
return fullName ? fullName : email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of workspaces.
|
||||
* @return {number}
|
||||
*/
|
||||
getWorkspacesNumber(): number {
|
||||
return this.cheAPI.getWorkspace().getWorkspaces().length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of factories.
|
||||
* @return {number}
|
||||
*/
|
||||
getFactoriesNumber(): number {
|
||||
return this.cheAPI.getFactory().getPageFactories().length;
|
||||
return this.pageFactories.length;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -55,8 +55,8 @@
|
|||
<div class="navbar-item" layout="row" layout-align="start center" id="workspaces-item">
|
||||
<md-icon md-font-icon="navbar-icon chefont cheico-workspace"></md-icon>
|
||||
<span>Workspaces</span>
|
||||
<span class="navbar-number" ng-show="navbarController.getWorkspacesNumber()">
|
||||
({{navbarController.getWorkspacesNumber()}})
|
||||
<span class="navbar-number" ng-show="navbarController.workspacesNumber">
|
||||
({{navbarController.workspacesNumber}})
|
||||
</span>
|
||||
</div>
|
||||
</md-button>
|
||||
|
|
|
|||
|
|
@ -92,6 +92,15 @@ export class NavbarRecentWorkspacesController {
|
|||
this.dropdownItems = {};
|
||||
this.dropdownItemTempl = [];
|
||||
|
||||
const handler = (workspaces: Array<che.IWorkspace>) => {
|
||||
this.workspaces = workspaces;
|
||||
this.updateRecentWorkspaces();
|
||||
};
|
||||
this.cheWorkspace.addListener('onChangeWorkspaces', handler);
|
||||
$scope.$on('$destroy', () => {
|
||||
this.cheWorkspace.removeListener('onChangeWorkspaces', handler);
|
||||
});
|
||||
|
||||
let cleanup = $rootScope.$on('recent-workspace:set', (event: ng.IAngularEvent, workspaceId: string) => {
|
||||
this.veryRecentWorkspaceId = workspaceId;
|
||||
this.updateRecentWorkspaces();
|
||||
|
|
@ -99,22 +108,14 @@ export class NavbarRecentWorkspacesController {
|
|||
$rootScope.$on('$destroy', () => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
$scope.$watch(() => {
|
||||
return this.workspaces;
|
||||
}, () => {
|
||||
this.updateRecentWorkspaces();
|
||||
}, true);
|
||||
}
|
||||
|
||||
$onInit(): void {
|
||||
this.workspaceCreationLink = this.cheBranding.getWorkspace().creationLink;
|
||||
|
||||
// get workspaces
|
||||
this.workspaces = this.cheWorkspace.getWorkspaces();
|
||||
|
||||
// fetch workspaces when initializing
|
||||
this.cheWorkspace.fetchWorkspaces();
|
||||
this.cheWorkspace.fetchWorkspaces().then(() => {
|
||||
this.workspaces = this.cheWorkspace.getWorkspaces();
|
||||
});
|
||||
|
||||
this.updateRecentWorkspaces();
|
||||
this.fetchWorkspaceSettings();
|
||||
|
|
|
|||
|
|
@ -193,8 +193,6 @@ export class ListOrganizationWorkspacesController {
|
|||
|
||||
/**
|
||||
* Filter workspaces by namespace.
|
||||
*
|
||||
* @returns {Array<che.IWorkspace>}
|
||||
*/
|
||||
filterWorkspacesByNamespace(): Array<che.IWorkspace> {
|
||||
return this.lodash.filter(this.cheWorkspace.getWorkspaces(), (workspace: che.IWorkspace) => {
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ export class ListWorkspacesCtrl {
|
|||
// map of workspaces' used resources (consumed GBH):
|
||||
this.workspaceUsedResources = new Map();
|
||||
|
||||
this.getUserWorkspaces();
|
||||
this.fetchUserWorkspaces();
|
||||
|
||||
this.cheNamespaceRegistry.fetchNamespaces().then(() => {
|
||||
this.namespaceLabels = this.getNamespaceLabelsList();
|
||||
|
|
@ -123,69 +123,26 @@ export class ListWorkspacesCtrl {
|
|||
}
|
||||
|
||||
/**
|
||||
* Fetch current user's workspaces (where he is a member):
|
||||
* Fetch current user's workspaces.
|
||||
*/
|
||||
getUserWorkspaces(): void {
|
||||
// fetch workspaces when initializing
|
||||
fetchUserWorkspaces(): void {
|
||||
const promise = this.cheAPI.getWorkspace().fetchWorkspaces();
|
||||
|
||||
promise.then(() => {
|
||||
return this.updateSharedWorkspaces();
|
||||
this.userWorkspaces = this.cheAPI.getWorkspace().getWorkspaces();
|
||||
return this.$q.resolve();
|
||||
}, (error: any) => {
|
||||
if (error && error.status === 304) {
|
||||
// ok
|
||||
return this.updateSharedWorkspaces();
|
||||
this.userWorkspaces = this.cheAPI.getWorkspace().getWorkspaces();
|
||||
return this.$q.resolve();
|
||||
}
|
||||
this.state = 'error';
|
||||
this.isInfoLoading = false;
|
||||
return this.$q.reject(error);
|
||||
}).then(() => {
|
||||
this.cheListHelper.setList(this.userWorkspaces, 'id');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the info of all user workspaces:
|
||||
*
|
||||
* @return {IPromise<any>}
|
||||
*/
|
||||
updateSharedWorkspaces(): ng.IPromise<any> {
|
||||
this.userWorkspaces = [];
|
||||
let workspaces = this.cheAPI.getWorkspace().getWorkspaces();
|
||||
if (workspaces.length === 0) {
|
||||
}).finally(()=> {
|
||||
this.isInfoLoading = false;
|
||||
}
|
||||
const promises: Array<ng.IPromise<any>> = [];
|
||||
workspaces.forEach((workspace: che.IWorkspace) => {
|
||||
// first check the list of already received workspace info:
|
||||
if (!this.workspacesById.get(workspace.id)) {
|
||||
const promise = this.cheWorkspace.fetchWorkspaceDetails(workspace.id)
|
||||
.catch((error: any) => {
|
||||
if (error && error.status === 304) {
|
||||
return this.$q.when();
|
||||
}
|
||||
let message = error.data && error.data.message ? ' Reason: ' + error.data.message : '';
|
||||
let workspaceName = this.cheWorkspace.getWorkspaceDataManager().getName(workspace);
|
||||
this.cheNotification.showError('Failed to retrieve workspace ' + workspaceName + ' data.' + message) ;
|
||||
return this.$q.reject(error);
|
||||
})
|
||||
.then(() => {
|
||||
let userWorkspace = this.cheAPI.getWorkspace().getWorkspaceById(workspace.id);
|
||||
this.getWorkspaceInfo(userWorkspace);
|
||||
this.userWorkspaces.push(userWorkspace);
|
||||
return this.$q.when();
|
||||
});
|
||||
promises.push(promise);
|
||||
} else {
|
||||
let userWorkspace = this.workspacesById.get(workspace.id);
|
||||
this.userWorkspaces.push(userWorkspace);
|
||||
this.isInfoLoading = false;
|
||||
}
|
||||
});
|
||||
|
||||
this.state = 'loaded';
|
||||
|
||||
return this.$q.all(promises);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -199,39 +156,13 @@ export class ListWorkspacesCtrl {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all necessary workspace info to be displayed.
|
||||
*
|
||||
* @param {che.IWorkspace} workspace
|
||||
*/
|
||||
getWorkspaceInfo(workspace: che.IWorkspace): void {
|
||||
let promises = [];
|
||||
this.workspacesById.set(workspace.id, workspace);
|
||||
|
||||
workspace.isLocked = false;
|
||||
workspace.usedResources = this.workspaceUsedResources.get(workspace.id);
|
||||
|
||||
// no access to runner resources if workspace is locked:
|
||||
if (!workspace.isLocked) {
|
||||
let promiseWorkspace = this.cheAPI.getWorkspace().fetchWorkspaceDetails(workspace.id);
|
||||
promises.push(promiseWorkspace);
|
||||
}
|
||||
|
||||
this.$q.all(promises).finally(() => {
|
||||
this.isInfoLoading = false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all selected workspaces
|
||||
*/
|
||||
deleteSelectedWorkspaces(): void {
|
||||
const selectedWorkspaces = this.cheListHelper.getSelectedItems(),
|
||||
selectedWorkspacesIds = selectedWorkspaces.map((workspace: che.IWorkspace) => {
|
||||
return workspace.id;
|
||||
});
|
||||
const selectedWorkspaces = this.cheListHelper.getSelectedItems();
|
||||
|
||||
let queueLength = selectedWorkspacesIds.length;
|
||||
let queueLength = selectedWorkspaces.length;
|
||||
if (!queueLength) {
|
||||
this.cheNotification.showError('No such workspace.');
|
||||
return;
|
||||
|
|
@ -244,26 +175,22 @@ export class ListWorkspacesCtrl {
|
|||
let deleteWorkspacePromises = [];
|
||||
let workspaceName;
|
||||
|
||||
selectedWorkspacesIds.forEach((workspaceId: string) => {
|
||||
this.cheListHelper.itemsSelectionStatus[workspaceId] = false;
|
||||
selectedWorkspaces.forEach((workspace: che.IWorkspace) => {
|
||||
this.cheListHelper.itemsSelectionStatus[workspace.id] = false;
|
||||
|
||||
let workspace = this.cheWorkspace.getWorkspaceById(workspaceId);
|
||||
if (!workspace) {
|
||||
return;
|
||||
}
|
||||
workspaceName = this.cheWorkspace.getWorkspaceDataManager().getName(workspace);
|
||||
let stoppedStatusPromise = this.cheWorkspace.fetchStatusChange(workspaceId, 'STOPPED');
|
||||
let stoppedStatusPromise = this.cheWorkspace.fetchStatusChange(workspace.id, 'STOPPED');
|
||||
|
||||
// stop workspace if it's status is RUNNING
|
||||
if (workspace.status === 'RUNNING') {
|
||||
this.cheWorkspace.stopWorkspace(workspaceId);
|
||||
this.cheWorkspace.stopWorkspace(workspace.id);
|
||||
}
|
||||
|
||||
// delete stopped workspace
|
||||
let promise = stoppedStatusPromise.then(() => {
|
||||
return this.cheWorkspace.deleteWorkspace(workspaceId);
|
||||
return this.cheWorkspace.deleteWorkspace(workspace.id);
|
||||
}).then(() => {
|
||||
this.workspacesById.delete(workspaceId);
|
||||
this.workspacesById.delete(workspace.id);
|
||||
queueLength--;
|
||||
},
|
||||
(error: any) => {
|
||||
|
|
@ -274,7 +201,7 @@ export class ListWorkspacesCtrl {
|
|||
});
|
||||
|
||||
this.$q.all(deleteWorkspacePromises).finally(() => {
|
||||
this.getUserWorkspaces();
|
||||
this.fetchUserWorkspaces();
|
||||
|
||||
if (isError) {
|
||||
this.cheNotification.showError('Delete failed.');
|
||||
|
|
|
|||
|
|
@ -16,9 +16,11 @@
|
|||
A workspace is where your projects live and run. Create workspaces from stacks that define projects, runtimes, and commands.
|
||||
</che-description>
|
||||
<md-content md-scroll-y flex layout="column" md-theme="maincontent-theme">
|
||||
<div class="progress-line"><md-progress-linear md-mode="indeterminate"
|
||||
ng-show="listWorkspacesCtrl.isInfoLoading || listWorkspacesCtrl.isRequestPending"></md-progress-linear>
|
||||
<md-content flex class="workspace-list-content" ng-hide="listWorkspacesCtrl.isInfoLoading"><div>
|
||||
<div class="progress-line">
|
||||
<md-progress-linear md-mode="indeterminate"
|
||||
ng-show="listWorkspacesCtrl.isInfoLoading"></md-progress-linear>
|
||||
</div>
|
||||
<md-content flex class="workspace-list-content" ng-hide="listWorkspacesCtrl.isInfoLoading">
|
||||
<che-list-header che-input-placeholder="Search"
|
||||
che-on-search-change="listWorkspacesCtrl.onSearchChanged(str)"
|
||||
che-hide-search="listWorkspacesCtrl.userWorkspaces.length === 0"
|
||||
|
|
@ -64,15 +66,14 @@
|
|||
</div>
|
||||
</div>
|
||||
</che-list-header>
|
||||
<che-list ng-show="listWorkspacesCtrl.cheListHelper.visibleItemsNumber > 0">
|
||||
<che-list>
|
||||
<che-workspace-item
|
||||
ng-repeat="workspace in listWorkspacesCtrl.cheListHelper.getVisibleItems() | orderBy:[listWorkspacesCtrl.workspaceOrderBy, 'devfile.metadata.name']"
|
||||
ng-model="listWorkspacesCtrl.cheListHelper.itemsSelectionStatus[workspace.id]"
|
||||
is-request-pending="listWorkspacesCtrl.isRequestPending"
|
||||
che-selectable="true"
|
||||
che-display-labels="false"
|
||||
che-on-checkbox-click="listWorkspacesCtrl.cheListHelper.updateBulkSelectionStatus()"
|
||||
che-workspace-item="workspace"></che-workspace-item>
|
||||
ng-repeat="workspace in listWorkspacesCtrl.cheListHelper.getVisibleItems() | orderBy:[listWorkspacesCtrl.workspaceOrderBy, 'devfile.metadata.name']"
|
||||
ng-model="listWorkspacesCtrl.cheListHelper.itemsSelectionStatus[workspace.id]"
|
||||
che-selectable="true"
|
||||
che-display-labels="false"
|
||||
che-on-checkbox-click="listWorkspacesCtrl.cheListHelper.updateBulkSelectionStatus()"
|
||||
che-workspace-item="workspace"></che-workspace-item>
|
||||
</che-list>
|
||||
<div class="che-list-empty">
|
||||
<span ng-show="listWorkspacesCtrl.userWorkspaces.length > 0 && listWorkspacesCtrl.cheListHelper.visibleItemsNumber === 0">
|
||||
|
|
|
|||
|
|
@ -10,10 +10,10 @@
|
|||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
'use strict';
|
||||
import {CheWorkspace} from '../../../../components/api/workspace/che-workspace.factory';
|
||||
import {CheWorkspace, WorkspaceStatus} from '../../../../components/api/workspace/che-workspace.factory';
|
||||
import {CheBranding} from '../../../../components/branding/che-branding.factory';
|
||||
import {WorkspacesService} from '../../workspaces.service';
|
||||
import { WorkspaceDataManager } from '../../../../components/api/workspace/workspace-data-manager';
|
||||
import {WorkspaceDataManager} from '../../../../components/api/workspace/workspace-data-manager';
|
||||
|
||||
const BLUR_TIMEOUT = 5000;
|
||||
|
||||
|
|
@ -34,6 +34,7 @@ export class WorkspaceItemCtrl {
|
|||
'cheWorkspace',
|
||||
'lodash',
|
||||
'workspacesService',
|
||||
'$filter'
|
||||
];
|
||||
|
||||
$document: ng.IDocumentService;
|
||||
|
|
@ -47,6 +48,7 @@ export class WorkspaceItemCtrl {
|
|||
workspace: che.IWorkspace;
|
||||
workspaceName: string;
|
||||
workspaceSupportIssues: any;
|
||||
$filter: ng.IFilterService;
|
||||
|
||||
private supportedVersionTypeIssue: any;
|
||||
private timeoutPromise: ng.IPromise<any>;
|
||||
|
|
@ -63,6 +65,7 @@ export class WorkspaceItemCtrl {
|
|||
cheWorkspace: CheWorkspace,
|
||||
lodash: any,
|
||||
workspacesService: WorkspacesService,
|
||||
$filter: ng.IFilterService,
|
||||
) {
|
||||
this.$document = $document;
|
||||
this.$location = $location;
|
||||
|
|
@ -70,6 +73,7 @@ export class WorkspaceItemCtrl {
|
|||
this.cheWorkspace = cheWorkspace;
|
||||
this.lodash = lodash;
|
||||
this.workspacesService = workspacesService;
|
||||
this.$filter = $filter;
|
||||
|
||||
this.workspaceDataManager = new WorkspaceDataManager();
|
||||
|
||||
|
|
@ -123,12 +127,12 @@ export class WorkspaceItemCtrl {
|
|||
* Redirects to workspace details.
|
||||
* @param tab {string}
|
||||
*/
|
||||
redirectToWorkspaceDetails(tab?: string): void {
|
||||
this.$location.path('/workspace/' + this.workspace.namespace + '/' + this.workspaceName).search({tab: tab ? tab : 'Overview'});
|
||||
redirectToWorkspaceDetails(tab: string = 'Overview'): void {
|
||||
this.$location.path(`/workspace/${this.workspace.namespace}/${this.workspaceName}`).search({tab});
|
||||
}
|
||||
|
||||
getMemoryLimit(workspace: che.IWorkspace): string {
|
||||
return '-';
|
||||
getMemoryLimit(): string {
|
||||
return '-';
|
||||
}
|
||||
|
||||
setTemporaryFocus(elementId?: string): void {
|
||||
|
|
@ -151,12 +155,28 @@ export class WorkspaceItemCtrl {
|
|||
}
|
||||
}
|
||||
|
||||
get workspaceTooltip(): string {
|
||||
const isWorkspaceRunning = WorkspaceStatus.RUNNING === WorkspaceStatus[this.getWorkspaceStatus()];
|
||||
const attributes = this.workspace.attributes;
|
||||
const time = parseInt('' + (attributes.updated ? attributes.updated : attributes.created), 10);
|
||||
const amTimeAgo: (time: number) => string = this.$filter('amTimeAgo');
|
||||
return isWorkspaceRunning ? 'Running' : 'Last modified: ' + amTimeAgo(time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current status of workspace
|
||||
* @returns {String}
|
||||
*/
|
||||
getWorkspaceStatus(): string {
|
||||
let workspace = this.cheWorkspace.getWorkspaceById(this.workspace.id);
|
||||
return workspace ? workspace.status : 'unknown';
|
||||
const workspace = this.cheWorkspace.getWorkspaceById(this.workspace.id);
|
||||
if (!workspace || !workspace.status) {
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
return workspace.status;
|
||||
}
|
||||
|
||||
isCheckboxEnable(): boolean {
|
||||
const status = WorkspaceStatus[this.getWorkspaceStatus()];
|
||||
return status === WorkspaceStatus.RUNNING || status === WorkspaceStatus.STOPPED;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
Red Hat, Inc. - initial API and implementation
|
||||
|
||||
-->
|
||||
<che-list-item flex ng-mouseover="hover=true" ng-mouseout="hover=false">
|
||||
<che-list-item flex>
|
||||
<div flex="100"
|
||||
id="ws-name-{{workspaceItemCtrl.workspaceName}}"
|
||||
data-ws-status="{{workspaceItemCtrl.getWorkspaceStatus()}}"
|
||||
|
|
@ -21,9 +21,9 @@
|
|||
<div layout="row"
|
||||
layout-align="start center"
|
||||
class="che-checkbox-area"
|
||||
ng-if="workspaceItemCtrl.isSelectable === true">
|
||||
ng-if="workspaceItemCtrl.isSelectable">
|
||||
<che-list-item-checked ng-model="workspaceItemCtrl.isSelect"
|
||||
ng-show="('RUNNING' === workspaceItemCtrl.getWorkspaceStatus() || 'STOPPED' === workspaceItemCtrl.getWorkspaceStatus())"
|
||||
ng-show="workspaceItemCtrl.isCheckboxEnable()"
|
||||
che-aria-label-checkbox="Workspace {{workspaceItemCtrl.workspaceName}}"
|
||||
ng-click="workspaceItemCtrl.onCheckboxClick()"></che-list-item-checked>
|
||||
</div>
|
||||
|
|
@ -32,7 +32,6 @@
|
|||
layout-align-gt-xs="start center"
|
||||
layout-align-xs="start start"
|
||||
class="che-list-item-details">
|
||||
|
||||
<!-- Name -->
|
||||
<div flex-gt-xs="25"
|
||||
layout="row"
|
||||
|
|
@ -40,25 +39,25 @@
|
|||
ng-click="workspaceItemCtrl.redirectToWorkspaceDetails();">
|
||||
<span class="che-xs-header noselect" hide-gt-xs>Name</span>
|
||||
<div layout="row" flex>
|
||||
<workspace-status-indicator flex="none" che-status="workspaceItemCtrl.getWorkspaceStatus()"></workspace-status-indicator>
|
||||
<div class="workspace-name-clip" id="ws-full-name-{{workspaceItemCtrl.workspace.namespace}}/{{workspaceItemCtrl.workspaceName}}">
|
||||
<span uib-tooltip="{{'RUNNING' === workspaceItemCtrl.getWorkspaceStatus() ? 'Running' : 'Last modified: ' + (workspaceItemCtrl.workspace.attributes.updated | amTimeAgo)}}"
|
||||
<workspace-status-indicator che-status="workspaceItemCtrl.getWorkspaceStatus()"
|
||||
flex="none"></workspace-status-indicator>
|
||||
<div class="workspace-name-clip"
|
||||
id="ws-full-name-{{workspaceItemCtrl.workspace.namespace}}/{{workspaceItemCtrl.workspaceName}}">
|
||||
<span uib-tooltip="{{workspaceItemCtrl.workspaceTooltip}}"
|
||||
class="che-hover">
|
||||
<che-clip-the-middle>{{workspaceItemCtrl.workspace.namespace}}/{{workspaceItemCtrl.workspaceName}}</che-clip-the-middle>
|
||||
{{workspaceItemCtrl.workspace.namespace}}/{{workspaceItemCtrl.workspaceName}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<i class="fa fa-clock-o workspace-item-temp" ng-if="workspaceItemCtrl.workspace.temporary"></i>
|
||||
</div>
|
||||
|
||||
<!-- RAM -->
|
||||
<div flex-gt-xs="10"
|
||||
class="che-list-item-name workspace-item-ram"
|
||||
ng-click="workspaceItemCtrl.redirectToWorkspaceDetails();">
|
||||
<span class="che-xs-header noselect" hide-gt-xs>RAM</span>
|
||||
<span class="workspace-consumed-value" name="workspace-ram-value">{{workspaceItemCtrl.getMemoryLimit(workspaceItemCtrl.workspace)}}</span>
|
||||
<span class="workspace-consumed-value" name="workspace-ram-value">{{workspaceItemCtrl.getMemoryLimit()}}</span>
|
||||
</div>
|
||||
|
||||
<!-- Projects -->
|
||||
<div flex-gt-xs="10"
|
||||
class="che-list-item-name workspace-item-projects"
|
||||
|
|
@ -66,12 +65,11 @@
|
|||
<span class="che-xs-header noselect" hide-gt-xs>Projects</span>
|
||||
<span class="che-hover" name="workspace-projects-value">
|
||||
{{workspaceItemCtrl.projects.length > 0 ? workspaceItemCtrl.projects.length : '-'}}
|
||||
<span ng-show="workspaceItemCtrl.displayLabels && (workspaceItemCtrl.projects.length > 0) === true">
|
||||
project<span ng-if="workspaceItemCtrl.workspace.config.projects.length > 1">s</span>
|
||||
<span ng-show="workspaceItemCtrl.displayLabels && workspaceItemCtrl.projects.length">
|
||||
project<span ng-if="workspaceItemCtrl.workspace.projects.length > 1">s</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Stack ID -->
|
||||
<div flex-gt-xs="40"
|
||||
class="che-list-item-name workspace-item-stack"
|
||||
|
|
@ -79,7 +77,6 @@
|
|||
<span class="che-xs-header noselect" hide-gt-xs>Stack</span>
|
||||
<span class="che-hover" name="workspace-stacks-name">{{workspaceItemCtrl.stackDescription}}</span>
|
||||
</div>
|
||||
|
||||
<!-- Actions -->
|
||||
<div flex-gt-xs="15"
|
||||
class="workspace-item-actions">
|
||||
|
|
@ -90,11 +87,11 @@
|
|||
workspace-id="workspaceItemCtrl.workspace.id"
|
||||
name="workspace-stop-start-button"
|
||||
is-request-pending="workspaceItemCtrl.isRequestPending"></che-workspace-status>
|
||||
<a href="#/workspace/{{workspaceItemCtrl.workspace.namespace}}/{{workspaceItemCtrl.workspaceName}}?tab={{workspaceItemCtrl.workspace.devfile ? 'Devfile':'Config'}}"
|
||||
<span ng-click="workspaceItemCtrl.redirectToWorkspaceDetails('Devfile');"
|
||||
name="configure-workspace-button"
|
||||
uib-tooltip="Configure workspace">
|
||||
<span class="fa fa-cog"></span>
|
||||
</a>
|
||||
</span>
|
||||
<span ng-if="workspaceItemCtrl.isSupported"
|
||||
ng-click="workspaceItemCtrl.redirectToWorkspaceDetails('Projects');"
|
||||
uib-tooltip="Add project">
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ import {CheWorkspaceStatusButton} from './status-button/workspace-status-button.
|
|||
import {WorkspaceDetailsOverviewController} from './workspace-overview/workspace-details-overview.controller';
|
||||
import {WorkspaceDetailsOverview} from './workspace-overview/workspace-details-overview.directive';
|
||||
import {CheWorkspace} from '../../../components/api/workspace/che-workspace.factory';
|
||||
import {WorkspaceConfigService} from '../workspace-config.service';
|
||||
import {CheProjectItem} from './workspace-projects/project-item/project-item.directive';
|
||||
import {ProjectItemCtrl} from './workspace-projects/project-item/project-item.controller';
|
||||
import {NoGithubOauthDialogController} from '../create-workspace/ready-to-go-stacks/project-source-selector/add-import-project/import-github-project/oauth-dialog/no-github-oauth-dialog.controller';
|
||||
|
|
@ -80,10 +79,16 @@ export class WorkspaceDetailsConfig {
|
|||
controller: 'WorkspaceDetailsController',
|
||||
controllerAs: 'workspaceDetailsController',
|
||||
resolve: {
|
||||
initData: ['$q', '$route', 'cheWorkspace', 'workspaceConfigService', ($q: ng.IQService, $route: ng.route.IRouteService, cheWorkspace: CheWorkspace, workspaceConfigService: WorkspaceConfigService) => {
|
||||
return workspaceConfigService.resolveWorkspaceRoute().then(() => {
|
||||
const {namespace, workspaceName} = $route.current.params;
|
||||
const workspaceDetails = cheWorkspace.getWorkspaceByName(namespace, workspaceName);
|
||||
initData: ['$q', '$route', 'cheWorkspace', ($q: ng.IQService, $route: ng.route.IRouteService, cheWorkspace: CheWorkspace) => {
|
||||
const {namespace, workspaceName} = $route.current.params;
|
||||
const getName = (workspace: che.IWorkspace) => {
|
||||
if (workspace.config) {
|
||||
return workspace.config.name;
|
||||
}
|
||||
return workspace.devfile.metadata.name;
|
||||
};
|
||||
return cheWorkspace.fetchWorkspacesByNamespace(namespace).then(() => {
|
||||
const workspaceDetails = cheWorkspace.getWorkspacesByNamespace(namespace).find( workspace => getName(workspace) === workspaceName);
|
||||
return {namespaceId: namespace, workspaceName: workspaceName, workspaceDetails: workspaceDetails};
|
||||
});
|
||||
}]
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ div.workspace-details-warning-info
|
|||
background-color $warning-color
|
||||
|
||||
.workspace-details-content
|
||||
& > md-tabs
|
||||
height 100%
|
||||
|
||||
md-tab-content
|
||||
padding 0
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ export class CheFactory {
|
|||
private factoryContentsByWorkspaceId: Map<string, any>;
|
||||
private pageFactories: Array<che.IFactory>;
|
||||
private factoryPagesMap: Map<number, any>;
|
||||
private pageInfo: any;
|
||||
private pageInfo: {currentPageNumber: number, countOfPages: number} = {currentPageNumber: 1, countOfPages: 1};
|
||||
private itemsPerPage: number;
|
||||
private cheUser: CheUser;
|
||||
|
||||
|
|
@ -70,7 +70,6 @@ export class CheFactory {
|
|||
// paging
|
||||
this.pageFactories = [];
|
||||
this.factoryPagesMap = new Map();
|
||||
this.pageInfo = {};
|
||||
|
||||
this.remoteFactoryAPI = <IFactoriesResource<any>>this.$resource('/api/factory/:factoryId', {factoryId: '@id'}, {
|
||||
updateFactory: {method: 'PUT', url: '/api/factory/:factoryId'},
|
||||
|
|
@ -96,26 +95,6 @@ export class CheFactory {
|
|||
|
||||
_getPageFromResponse(data: any, headersLink: any): any {
|
||||
let links = new Map();
|
||||
if (!headersLink) {
|
||||
// TODO remove it after adding headers paging links on server side
|
||||
let user = this.cheUser.getUser();
|
||||
if (!this.itemsPerPage || !user) {
|
||||
return {factories: data};
|
||||
}
|
||||
this.pageInfo.currentPageNumber = this.pageInfo.currentPageNumber ? this.pageInfo.currentPageNumber : 1;
|
||||
let link = '/api/factory/find?creator.userId=' + user.id + '&maxItems=' + this.itemsPerPage;
|
||||
links.set('first', link + '&skipCount=0');
|
||||
if (data && data.length > 0) {
|
||||
links.set('next', link + '&skipCount=' + this.pageInfo.currentPageNumber * this.itemsPerPage);
|
||||
}
|
||||
if (this.pageInfo.currentPageNumber > 1) {
|
||||
links.set('prev', link + '&skipCount=' + (this.pageInfo.currentPageNumber - 2) * this.itemsPerPage);
|
||||
}
|
||||
return {
|
||||
factories: data,
|
||||
links: links
|
||||
};
|
||||
}
|
||||
let pattern = new RegExp('<([^>]+?)>.+?rel="([^"]+?)"', 'g');
|
||||
let result;
|
||||
while (result = pattern.exec(headersLink)) {
|
||||
|
|
@ -253,8 +232,8 @@ export class CheFactory {
|
|||
}
|
||||
|
||||
/**
|
||||
* Ask for loading the factories page in asynchronous way
|
||||
* If there are no changes, it's not updated
|
||||
* Ask for loading the factories page in asynchronous way.
|
||||
* If there are no changes, page info won't be updated.
|
||||
* @param pageKey - the key of page ('first', 'prev', 'next', 'last' or '1', '2', '3' ...)
|
||||
* @returns {*} the promise
|
||||
*/
|
||||
|
|
@ -278,7 +257,7 @@ export class CheFactory {
|
|||
pageNumber = this.pageInfo.countOfPages;
|
||||
}
|
||||
let pageData = this.factoryPagesMap.get(pageNumber);
|
||||
if (pageData.link) {
|
||||
if (pageData && pageData.link) {
|
||||
this.pageInfo.currentPageNumber = pageNumber;
|
||||
let queryData = this._getPageParamByLink(pageData.link);
|
||||
if (!queryData) {
|
||||
|
|
@ -316,23 +295,15 @@ export class CheFactory {
|
|||
});
|
||||
}
|
||||
|
||||
let resultPromise = deferred.promise.then((userId: string) => {
|
||||
return deferred.promise.then((userId: string) => {
|
||||
queryData.userId = userId;
|
||||
return this.remoteFactoryAPI.getFactories(queryData).$promise.then((data: any) => {
|
||||
return this._updateFactoriesDetails(data.factories).then((factoriesDetails: any) => {
|
||||
data.factories = factoriesDetails;
|
||||
return this.$q.when(data);
|
||||
}, (error: any) => {
|
||||
return this.$q.reject(error);
|
||||
});
|
||||
}, (error: any) => {
|
||||
return this.$q.reject(error);
|
||||
});
|
||||
}, (error: any) => {
|
||||
return this.$q.reject(error);
|
||||
});
|
||||
|
||||
return resultPromise;
|
||||
}
|
||||
|
||||
_updateFactoriesDetails(factories: Array<any>): ng.IPromise<any> {
|
||||
|
|
@ -526,13 +497,11 @@ export class CheFactory {
|
|||
* @returns {Array<string>} links acceptance links
|
||||
*/
|
||||
detectLinks(factory: che.IFactory): Array<string> {
|
||||
let links = [];
|
||||
|
||||
if (!factory || !factory.links) {
|
||||
const links = [];
|
||||
if (!factory || !angular.isArray(factory.links)) {
|
||||
return links;
|
||||
}
|
||||
|
||||
this.lodash.find(factory.links, (link: any) => {
|
||||
factory.links.forEach((link: any) => {
|
||||
if (link.rel === 'accept' || link.rel === 'accept-named') {
|
||||
links.push(link.href);
|
||||
}
|
||||
|
|
@ -567,18 +536,15 @@ export class CheFactory {
|
|||
* @returns {ng.IPromise<any>} the promise
|
||||
*/
|
||||
setFactory(factory: che.IFactory): ng.IPromise<any> {
|
||||
let deferred = this.$q.defer();
|
||||
// check factory
|
||||
const deferred = this.$q.defer();
|
||||
if (!factory || !factory.id) {
|
||||
deferred.reject({data: {message: 'Read factory error.'}});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
let promise = this.remoteFactoryAPI.updateFactory({factoryId: factory.id}, factory).$promise;
|
||||
// check if was OK or not
|
||||
promise.then((factory: any) => {
|
||||
this.remoteFactoryAPI.updateFactory({factoryId: factory.id}, factory).$promise.then((factory: any) => {
|
||||
factory.name = factory.name ? factory.name : '';
|
||||
this.fetchFactoryPage(this.pageInfo.currentPageNumber);
|
||||
this.fetchFactoryPage(this.pageInfo.currentPageNumber.toString());
|
||||
deferred.resolve(factory);
|
||||
}, (error: any) => {
|
||||
deferred.reject(error);
|
||||
|
|
@ -594,14 +560,14 @@ export class CheFactory {
|
|||
* @returns {ng.IPromise<any>} the promise
|
||||
*/
|
||||
setFactoryContent(factoryId: string, factoryContent: any): ng.IPromise<any> {
|
||||
let deferred = this.$q.defer();
|
||||
let promise = this.remoteFactoryAPI.updateFactory({factoryId: factoryId}, factoryContent).$promise;
|
||||
const deferred = this.$q.defer();
|
||||
const promise = this.remoteFactoryAPI.updateFactory({factoryId: factoryId}, factoryContent).$promise;
|
||||
|
||||
promise.then(() => {
|
||||
let fetchFactoryPromise = this.fetchFactoryById(factoryId);
|
||||
// check if was OK or not
|
||||
fetchFactoryPromise.then((factory: any) => {
|
||||
this.fetchFactoryPage(this.pageInfo.currentPageNumber);
|
||||
this.fetchFactoryPage(this.pageInfo.currentPageNumber.toString());
|
||||
deferred.resolve(factory);
|
||||
}, (error: any) => {
|
||||
deferred.reject(error);
|
||||
|
|
@ -619,37 +585,22 @@ export class CheFactory {
|
|||
* @returns {ng.IPromise<any>} the promise
|
||||
*/
|
||||
deleteFactoryById(factoryId: string): ng.IPromise<any> {
|
||||
let promise = this.remoteFactoryAPI.delete({factoryId: factoryId}).$promise;
|
||||
// check if was OK or not
|
||||
const promise = this.remoteFactoryAPI.delete({factoryId: factoryId}).$promise;
|
||||
|
||||
return promise.then(() => {
|
||||
this.factoriesById.delete(factoryId);
|
||||
if (this.pageInfo && this.pageInfo.currentPageNumber) {
|
||||
this.fetchFactoryPage(this.pageInfo.currentPageNumber);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method that extract the factory ID from a factory URL
|
||||
* @param factoryURL the factory URL to analyze
|
||||
* @returns the stringified ID of a factory
|
||||
*/
|
||||
getIDFromFactoryAPIURL(factoryURL: string): string {
|
||||
let index = factoryURL.lastIndexOf('/factory/');
|
||||
if (index > 0) {
|
||||
return factoryURL.slice(index + '/factory/'.length, factoryURL.length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the factory url based on id.
|
||||
* @returns {link.href|*} link value
|
||||
*/
|
||||
getFactoryIdUrl(factory: che.IFactory): string {
|
||||
let link = this.lodash.find(factory.links, (link: any) => {
|
||||
const link = this.lodash.find(factory.links, (link: any) => {
|
||||
return 'accept' === link.rel;
|
||||
});
|
||||
return link ? link.href : 'No value';
|
||||
return link ? link.href : '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -658,10 +609,9 @@ export class CheFactory {
|
|||
* @returns {link.href|*} link value
|
||||
*/
|
||||
getFactoryNamedUrl(factory: che.IFactory): string {
|
||||
let link = this.lodash.find(factory.links, (link: any) => {
|
||||
const link = this.lodash.find(factory.links, (link: any) => {
|
||||
return 'accept-named' === link.rel;
|
||||
});
|
||||
|
||||
return link ? link.href : null;
|
||||
return link ? link.href : '';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ export class CheHttpBackend {
|
|||
this.$httpBackend.when('DELETE', '/api/workspace/' + key).respond(200);
|
||||
}
|
||||
|
||||
this.$httpBackend.when('GET', '/api/workspace').respond(workspaceReturn);
|
||||
this.$httpBackend.when('GET', /\/api\/workspace(\?.*$)?/).respond(workspaceReturn);
|
||||
|
||||
this.$httpBackend.when('GET', '/api/stack?maxItems=50').respond(this.stacks);
|
||||
|
||||
|
|
|
|||
|
|
@ -18,9 +18,6 @@ import {CheBranding} from '../../branding/che-branding.factory';
|
|||
import {CheNotification} from '../../notification/che-notification.factory';
|
||||
import {WorkspaceDataManager} from './workspace-data-manager';
|
||||
|
||||
const WS_AGENT_HTTP_LINK: string = 'wsagent/http';
|
||||
const WS_AGENT_WS_LINK: string = 'wsagent/ws';
|
||||
|
||||
interface ICHELicenseResource<T> extends ng.resource.IResourceClass<T> {
|
||||
createDevfile: any;
|
||||
deleteWorkspace: any;
|
||||
|
|
@ -43,14 +40,29 @@ export enum WorkspaceStatus {
|
|||
ERROR
|
||||
}
|
||||
|
||||
type workspacesEvent = 'onChangeWorkspaces' | 'onDeleteWorkspace';
|
||||
|
||||
const MAX_ITEMS = 256;
|
||||
|
||||
/**
|
||||
* This class is handling the workspace retrieval
|
||||
* It sets to the array workspaces the current workspaces which are not temporary
|
||||
* @author Florent Benoit
|
||||
* @author Oleksii Orel
|
||||
*/
|
||||
export class CheWorkspace {
|
||||
|
||||
static $inject = ['$resource', '$http', '$q', 'cheJsonRpcApi', 'cheNotification', '$websocket', '$location', 'proxySettings', 'userDashboardConfig', 'lodash', 'cheBranding'];
|
||||
static $inject = ['$resource',
|
||||
'$http',
|
||||
'$q',
|
||||
'cheJsonRpcApi',
|
||||
'cheNotification',
|
||||
'$websocket',
|
||||
'$location',
|
||||
'proxySettings',
|
||||
'userDashboardConfig',
|
||||
'lodash',
|
||||
'cheBranding'];
|
||||
|
||||
private $resource: ng.resource.IResourceService;
|
||||
private $http: ng.IHttpService;
|
||||
|
|
@ -58,9 +70,8 @@ export class CheWorkspace {
|
|||
private $websocket: any;
|
||||
private cheNotification: CheNotification;
|
||||
private cheJsonRpcMasterApi: CheJsonRpcMasterApi;
|
||||
private listeners: Array<any>;
|
||||
private workspaceStatuses: Array<string>;
|
||||
private workspaces: Array<che.IWorkspace>;
|
||||
private handlers: { [paramName: string]: Array<any> };
|
||||
private workspaceIds: Array<string>;
|
||||
private subscribedWorkspacesIds: Array<string>;
|
||||
private workspacesByNamespace: Map<string, Array<che.IWorkspace>>;
|
||||
private workspacesById: Map<string, che.IWorkspace>;
|
||||
|
|
@ -98,8 +109,6 @@ export class CheWorkspace {
|
|||
lodash: any,
|
||||
cheBranding: CheBranding
|
||||
) {
|
||||
this.workspaceStatuses = ['RUNNING', 'STOPPED', 'PAUSED', 'STARTING', 'STOPPING', 'ERROR'];
|
||||
// keep resource
|
||||
this.$q = $q;
|
||||
this.$resource = $resource;
|
||||
this.$http = $http;
|
||||
|
|
@ -109,7 +118,7 @@ export class CheWorkspace {
|
|||
this.workspaceDataManager = new WorkspaceDataManager();
|
||||
|
||||
// current list of workspaces
|
||||
this.workspaces = [];
|
||||
this.workspaceIds = [];
|
||||
|
||||
// per Id
|
||||
this.workspacesById = new Map();
|
||||
|
|
@ -118,7 +127,7 @@ export class CheWorkspace {
|
|||
this.workspacesByNamespace = new Map();
|
||||
|
||||
// listeners if workspaces are changed/updated
|
||||
this.listeners = [];
|
||||
this.handlers = {};
|
||||
|
||||
// list of subscribed to websocket workspace Ids
|
||||
this.subscribedWorkspacesIds = [];
|
||||
|
|
@ -152,7 +161,6 @@ export class CheWorkspace {
|
|||
|
||||
/**
|
||||
* Add callback to the list of on workspace change subscribers.
|
||||
*
|
||||
* @param {string} workspaceId
|
||||
* @param {IObservableCallbackFn<che.IWorkspace>} action the callback
|
||||
*/
|
||||
|
|
@ -170,7 +178,6 @@ export class CheWorkspace {
|
|||
|
||||
/**
|
||||
* Unregister on workspace change callback.
|
||||
*
|
||||
* @param {string} workspaceId
|
||||
* @param {IObservableCallbackFn<che.IWorkspace>} action the callback
|
||||
*/
|
||||
|
|
@ -183,20 +190,39 @@ export class CheWorkspace {
|
|||
}
|
||||
|
||||
/**
|
||||
* Add a listener that need to have the onChangeWorkspaces(workspaces: Array) method
|
||||
* @param listener {Function} a changing listener
|
||||
* Adds a listener on an event.
|
||||
* @param {workspacesEvent} event
|
||||
* @param {Function} handler
|
||||
*/
|
||||
addListener(listener: Function): void {
|
||||
this.listeners.push(listener);
|
||||
addListener(event: workspacesEvent, handler: Function): void {
|
||||
if (!this.handlers[event]) {
|
||||
this.handlers[event] = [];
|
||||
}
|
||||
this.handlers[event].push(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a listener.
|
||||
* @param {workspacesEvent} event
|
||||
* @param {Function} handler
|
||||
*/
|
||||
removeListener(event: workspacesEvent, handler: Function): void {
|
||||
if (!this.handlers[event] || !handler) {
|
||||
return;
|
||||
}
|
||||
const index = this.handlers[event].indexOf(handler);
|
||||
if (index === -1) {
|
||||
return;
|
||||
}
|
||||
this.handlers[event].splice(index, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the workspaces of this remote
|
||||
* @returns {Array}
|
||||
*/
|
||||
getWorkspaces(): Array<che.IWorkspace> {
|
||||
return this.workspaces;
|
||||
return this.workspaceIds.map(id => this.workspacesById.get(id));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -208,18 +234,17 @@ export class CheWorkspace {
|
|||
}
|
||||
|
||||
getWorkspaceByName(namespace: string, name: string): che.IWorkspace {
|
||||
return this.lodash.find(this.workspaces, (workspace: che.IWorkspace) => {
|
||||
return this.lodash.find(this.getWorkspaces(), (workspace: che.IWorkspace) => {
|
||||
return workspace.namespace === namespace && this.workspaceDataManager.getName(workspace) === name;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches workspaces by provided namespace.
|
||||
*
|
||||
* @param namespace namespace
|
||||
*/
|
||||
fetchWorkspacesByNamespace(namespace: string): ng.IPromise<void> {
|
||||
let promise = this.$http.get('/api/workspace/namespace/' + namespace);
|
||||
let promise = this.$http.get(`/api/workspace/namespace/${namespace}?maxItems=${MAX_ITEMS}`);
|
||||
let resultPromise = promise.then((response: ng.IHttpResponse<che.IWorkspace[]>) => {
|
||||
const workspaces = this.getWorkspacesByNamespace(namespace);
|
||||
|
||||
|
|
@ -258,39 +283,34 @@ export class CheWorkspace {
|
|||
/**
|
||||
* Ask for loading the workspaces in asynchronous way
|
||||
* If there are no changes, it's not updated
|
||||
* @returns {ng.IPromise<Array<che.IWorkspace>>}
|
||||
*/
|
||||
fetchWorkspaces(): ng.IPromise<Array<che.IWorkspace>> {
|
||||
let promise = this.remoteWorkspaceAPI.query().$promise;
|
||||
let updatedPromise = promise.then((data: Array<che.IWorkspace>) => {
|
||||
this.workspaces.length = 0;
|
||||
this.workspacesById.clear();
|
||||
// add workspace if not temporary
|
||||
data.forEach((workspace: che.IWorkspace) => {
|
||||
let promise = this.remoteWorkspaceAPI.query({'maxItems': 256}).$promise;
|
||||
|
||||
promise.then((workspaces: Array<che.IWorkspace>) => {
|
||||
this.workspaceIds.length = 0;
|
||||
workspaces.forEach((workspace: che.IWorkspace) => {
|
||||
if (!workspace.temporary) {
|
||||
this.workspaceIds.push(workspace.id);
|
||||
}
|
||||
this.updateWorkspacesList(workspace);
|
||||
});
|
||||
return this.workspaces;
|
||||
|
||||
const onChangeHandlers = this.handlers['onChangeWorkspaces'];
|
||||
if (onChangeHandlers) {
|
||||
onChangeHandlers.forEach(handler => {
|
||||
handler(this.getWorkspaces());
|
||||
});
|
||||
}
|
||||
return this.$q.resolve(this.getWorkspaces());
|
||||
}, (error: any) => {
|
||||
if (error && error.status === 304) {
|
||||
return this.workspaces;
|
||||
return this.$q.resolve(this.getWorkspaces());
|
||||
}
|
||||
return this.$q.reject(error);
|
||||
});
|
||||
|
||||
let callbackPromises = updatedPromise.then((data: Array<che.IWorkspace>) => {
|
||||
let promises = [];
|
||||
promises.push(updatedPromise);
|
||||
|
||||
this.listeners.forEach((listener: any) => {
|
||||
let promise = listener.onChangeWorkspaces(data);
|
||||
promises.push(promise);
|
||||
});
|
||||
return this.$q.all(promises).then(() => data);
|
||||
}, (error: any) => {
|
||||
return this.$q.reject(error);
|
||||
});
|
||||
|
||||
return callbackPromises;
|
||||
return promise;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -454,20 +474,20 @@ export class CheWorkspace {
|
|||
* Performs workspace config update by the given workspaceId and new data.
|
||||
* @param workspaceId {string} the workspace ID
|
||||
* @param data {che.IWorkspace} the new workspace details
|
||||
* @returns {ng.IPromise<any>}
|
||||
*/
|
||||
updateWorkspace(workspaceId: string, data: che.IWorkspace): ng.IPromise<any> {
|
||||
let defer = this.$q.defer();
|
||||
let promise = this.remoteWorkspaceAPI.updateWorkspace({workspaceId: workspaceId}, data).$promise;
|
||||
promise.then((data: che.IWorkspace) => {
|
||||
this.updateWorkspacesList(data);
|
||||
this.startUpdateWorkspaceStatus(data.id);
|
||||
defer.resolve(data);
|
||||
}, (error: any) => {
|
||||
defer.reject(error);
|
||||
});
|
||||
updateWorkspace(workspaceId: string, data: che.IWorkspace): ng.IPromise<che.IWorkspace> {
|
||||
const promise = this.remoteWorkspaceAPI.updateWorkspace({workspaceId: workspaceId}, data).$promise;
|
||||
|
||||
return defer.promise;
|
||||
return promise.then(data => {
|
||||
this.updateWorkspacesList(data);
|
||||
const onChangeHandlers = this.handlers['onChangeWorkspaces'];
|
||||
if (onChangeHandlers) {
|
||||
onChangeHandlers.forEach(handler => {
|
||||
handler(this.getWorkspaces());
|
||||
});
|
||||
}
|
||||
return this.$q.resolve(data);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -479,9 +499,12 @@ export class CheWorkspace {
|
|||
let defer = this.$q.defer();
|
||||
let promise = this.remoteWorkspaceAPI.deleteWorkspace({workspaceId: workspaceId}).$promise;
|
||||
promise.then(() => {
|
||||
this.listeners.forEach((listener: any) => {
|
||||
listener.onDeleteWorkspace(workspaceId);
|
||||
});
|
||||
const onDeleteHandlers = this.handlers['onDeleteWorkspace'];
|
||||
if (onDeleteHandlers) {
|
||||
onDeleteHandlers.forEach(handler => {
|
||||
handler(workspaceId);
|
||||
});
|
||||
}
|
||||
defer.resolve();
|
||||
}, (error: any) => {
|
||||
defer.reject(error);
|
||||
|
|
@ -557,9 +580,9 @@ export class CheWorkspace {
|
|||
if (this.subscribedWorkspacesIds.indexOf(workspaceId) < 0) {
|
||||
this.subscribedWorkspacesIds.push(workspaceId);
|
||||
this.cheJsonRpcMasterApi.subscribeWorkspaceStatus(workspaceId, (message: any) => {
|
||||
let status = message.error ? 'ERROR' : message.status;
|
||||
const status = message.error ? 'ERROR' : message.status;
|
||||
|
||||
if (this.workspaceStatuses.indexOf(status) >= 0) {
|
||||
if (WorkspaceStatus[status]) {
|
||||
this.getWorkspaceById(workspaceId).status = status;
|
||||
}
|
||||
|
||||
|
|
@ -615,27 +638,15 @@ export class CheWorkspace {
|
|||
this.workspacesById.set(workspace.id, workspace);
|
||||
return;
|
||||
}
|
||||
|
||||
const workspaceDetails = this.getWorkspaceById(workspace.id);
|
||||
|
||||
if (!workspaceDetails) {
|
||||
this.workspacesById.set(workspace.id, workspace);
|
||||
if (workspaceDetails && this.isWorkspaceRunning(workspaceDetails) && !workspace.runtime) {
|
||||
workspace.runtime = workspaceDetails.runtime;
|
||||
}
|
||||
if (workspaceDetails && WorkspaceStatus[workspaceDetails.status] === WorkspaceStatus.RUNNING && workspaceDetails.runtime && !workspace.runtime) {
|
||||
workspace.runtime = angular.copy(workspaceDetails.runtime);
|
||||
}
|
||||
this.lodash.remove(this.workspaces, (_workspace: che.IWorkspace) => {
|
||||
return _workspace.id === workspace.id;
|
||||
});
|
||||
this.workspaces.push(workspace);
|
||||
this.workspacesById.set(workspace.id, workspace);
|
||||
// publish change
|
||||
if (this.observables.has(workspace.id)) {
|
||||
this.observables.get(workspace.id).publish(workspace);
|
||||
}
|
||||
if (!angular.equals(workspaceDetails, workspace)) {
|
||||
this.fetchWorkspaceDetails(workspace.id);
|
||||
return;
|
||||
}
|
||||
|
||||
this.startUpdateWorkspaceStatus(workspace.id);
|
||||
|
||||
|
|
@ -649,6 +660,10 @@ export class CheWorkspace {
|
|||
});
|
||||
}
|
||||
|
||||
private isWorkspaceRunning(workspace: che.IWorkspace): boolean {
|
||||
return workspace && WorkspaceStatus[workspace.status] === WorkspaceStatus.RUNNING;
|
||||
}
|
||||
|
||||
private formJsonRpcApiLocation($location: ng.ILocationService, proxySettings: string, devmode: boolean): string {
|
||||
let wsUrl;
|
||||
|
||||
|
|
|
|||
|
|
@ -86,15 +86,12 @@ describe('CheWorkspace', () => {
|
|||
|
||||
// add the listener
|
||||
let listener = new Listener();
|
||||
factory.addListener(listener);
|
||||
factory.addListener('onChangeWorkspaces', listener.onChangeWorkspaces);
|
||||
|
||||
// no workspaces now on factory or on listener
|
||||
expect(factory.getWorkspaces().length).toEqual(0);
|
||||
expect(listener.getWorkspaces().length).toEqual(0);
|
||||
|
||||
// expecting a GET
|
||||
httpBackend.expectGET('/api/workspace');
|
||||
|
||||
// providing request
|
||||
// add workspaces on Http backend
|
||||
cheBackend.addWorkspaces([workspace1, tmpWorkspace2]);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
background-color $white-color
|
||||
border-top 1px solid $list-separator-color
|
||||
padding 0 10px
|
||||
height 30px
|
||||
max-height 30px
|
||||
|
||||
& > div
|
||||
height 30px
|
||||
|
|
|
|||
|
|
@ -38,9 +38,9 @@
|
|||
cursor pointer
|
||||
|
||||
span:not(.tooltip)
|
||||
max-width 100%
|
||||
white-space nowrap
|
||||
padding-right 3px
|
||||
overflow visible
|
||||
padding 0
|
||||
|
||||
& .che-xs-header
|
||||
display inline-block
|
||||
|
|
@ -81,10 +81,9 @@
|
|||
|
||||
& > *:not(.tooltip)
|
||||
display inline-block
|
||||
text-align center
|
||||
float left
|
||||
width 16px
|
||||
height 16px
|
||||
max-width 16px
|
||||
max-height 16px
|
||||
line-height 16px
|
||||
margin-right 10px
|
||||
|
|
|
|||
Loading…
Reference in New Issue