diff --git a/app/ide-desktop/eslint.config.js b/app/ide-desktop/eslint.config.js index f8ce15ecdf..2e77490b66 100644 --- a/app/ide-desktop/eslint.config.js +++ b/app/ide-desktop/eslint.config.js @@ -392,7 +392,7 @@ export default [ '@typescript-eslint/no-magic-numbers': [ 'error', { - ignore: [0, 1, 2], + ignore: [-1, 0, 1, 2], ignoreArrayIndexes: true, ignoreEnums: true, detectObjects: true, diff --git a/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/backend.ts b/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/backend.ts index 4aba07cf09..da2c7a6a03 100644 --- a/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/backend.ts +++ b/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/backend.ts @@ -5,15 +5,9 @@ import * as newtype from '../newtype' import * as permissions from './permissions' import * as uniqueString from '../uniqueString' -// ============= -// === Types === -// ============= - -/** The {@link Backend} variant. If a new variant is created, it should be added to this enum. */ -export enum BackendType { - local = 'local', - remote = 'remote', -} +// ================ +// === Newtypes === +// ================ // These are constructor functions that construct values of the type they are named after. /* eslint-disable @typescript-eslint/no-redeclare */ @@ -76,6 +70,46 @@ export const Subject = newtype.newtypeConstructor() /* eslint-enable @typescript-eslint/no-redeclare */ +// ======================== +// === PermissionAction === +// ======================== + +/** Backend representation of user permission types. */ +export enum PermissionAction { + own = 'Own', + admin = 'Admin', + edit = 'Edit', + read = 'Read', + readAndDocs = 'Read_docs', + readAndExec = 'Read_exec', + view = 'View', + viewAndDocs = 'View_docs', + viewAndExec = 'View_exec', +} + +/** Whether each {@link PermissionAction} can execute a project. */ +export const PERMISSION_ACTION_CAN_EXECUTE: Record = { + [PermissionAction.own]: true, + [PermissionAction.admin]: true, + [PermissionAction.edit]: true, + [PermissionAction.read]: false, + [PermissionAction.readAndDocs]: false, + [PermissionAction.readAndExec]: true, + [PermissionAction.view]: false, + [PermissionAction.viewAndDocs]: false, + [PermissionAction.viewAndExec]: true, +} + +// ============= +// === Types === +// ============= + +/** The {@link Backend} variant. If a new variant is created, it should be added to this enum. */ +export enum BackendType { + local = 'local', + remote = 'remote', +} + /** A user/organization in the application. These are the primary owners of a project. */ export interface UserOrOrganization { id: UserOrOrganizationId @@ -112,6 +146,28 @@ export enum ProjectState { /** Wrapper around a project state value. */ export interface ProjectStateType { type: ProjectState + /* eslint-disable @typescript-eslint/naming-convention */ + volume_id: string + instance_id?: string + execute_async?: boolean + address?: string + security_group_id?: string + ec2_id?: string + ec2_public_ip_address?: string + current_session_id?: string + opened_by?: string + /* eslint-enable @typescript-eslint/naming-convention */ +} + +export const IS_PROJECT_STATE_OPENING_OR_OPENED: Record = { + [ProjectState.created]: false, + [ProjectState.new]: false, + [ProjectState.openInProgress]: true, + [ProjectState.provisioned]: true, + [ProjectState.opened]: true, + [ProjectState.closed]: false, + [ProjectState.placeholder]: true, + [ProjectState.closing]: false, } /** Common `Project` fields returned by all `Project`-related endpoints. */ @@ -158,6 +214,7 @@ export interface Project extends ListedProject { /** This must not be null as it is required to determine the base URL for backend assets. */ ideVersion: VersionNumber engineVersion: VersionNumber | null + openedBy?: EmailAddress } /** Information required to open a project. */ @@ -293,19 +350,6 @@ export interface SimpleUser { email: EmailAddress } -/** Backend representation of user permission types. */ -export enum PermissionAction { - own = 'Own', - admin = 'Admin', - edit = 'Edit', - read = 'Read', - readAndDocs = 'Read_docs', - readAndExec = 'Read_exec', - view = 'View', - viewAndDocs = 'View_docs', - viewAndExec = 'View_exec', -} - /** User permission for a specific user. */ export interface UserPermission { user: User diff --git a/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/components/assetContextMenu.tsx b/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/components/assetContextMenu.tsx index 38e100064d..8ed83f7fb0 100644 --- a/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/components/assetContextMenu.tsx +++ b/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/components/assetContextMenu.tsx @@ -68,6 +68,12 @@ export default function AssetContextMenu(props: AssetContextMenuProps) { const managesThisAsset = self?.permission === backendModule.PermissionAction.own || self?.permission === backendModule.PermissionAction.admin + const canExecute = + self?.permission != null && backendModule.PERMISSION_ACTION_CAN_EXECUTE[self.permission] + const isOtherUserUsingProject = + backendModule.assetIsProject(asset) && + organization != null && + asset.projectState.opened_by !== organization.email const setAsset = React.useCallback( (valueOrUpdater: React.SetStateAction) => { if (typeof valueOrUpdater === 'function') { @@ -84,20 +90,22 @@ export default function AssetContextMenu(props: AssetContextMenuProps) { return (