diff --git a/deadlock-plugins/deadlock-extension/src/core/commandHandler.ts b/deadlock-plugins/deadlock-extension/src/core/commandHandler.ts index 85a89d5c2294833e36efb58753d0145a1a03deaf..cf1e95717c0fda9cb5ca9382790fa8a501c80039 100644 --- a/deadlock-plugins/deadlock-extension/src/core/commandHandler.ts +++ b/deadlock-plugins/deadlock-extension/src/core/commandHandler.ts @@ -1,5 +1,5 @@ import { commands } from 'vscode'; -import { Command } from '../theia/command'; +import { VsCommand } from '../theia/command'; import Controller from './controller'; export class CommandHandler { constructor(private controller: Controller) { @@ -12,6 +12,6 @@ export class CommandHandler { } } -export const disconnectCommand = new Command('Disconnect', 'deadlock.disconnect'); -export const authenticateCommand = new Command('Authenticate', 'deadlock.authenticate'); -export const openUrlInBrowserCommand = new Command('Open url in browser', 'vscode.open'); +export const disconnectCommand = new VsCommand('Disconnect', 'deadlock.disconnect'); +export const authenticateCommand = new VsCommand('Authenticate', 'deadlock.authenticate'); +export const openUrlInBrowserCommand = new VsCommand('Open url in browser', 'vscode.open'); diff --git a/deadlock-plugins/deadlock-extension/src/core/controller.ts b/deadlock-plugins/deadlock-extension/src/core/controller.ts index 0b638a78ba511b1233a66baf4cde5b415d714633..087121c433ee9412d8254a669136e7548de7dd32 100644 --- a/deadlock-plugins/deadlock-extension/src/core/controller.ts +++ b/deadlock-plugins/deadlock-extension/src/core/controller.ts @@ -6,7 +6,6 @@ import ExtensionStore from './extensionStore'; import KeycloakOAuth2DeviceFlowConnection from './keycloakOAuth2DeviceFlowConnection'; import ApiService from './api.service'; import { GiteaPublicProperties } from '../model/giteaPublicProperties.model'; -import { Mission } from './mission/models/mission'; import { MissionDevContainer } from './mission/missionDevContainer'; import { extensionLog as log } from '../recorder/utils/log'; import { commands, ExtensionContext, Uri, window } from 'vscode'; @@ -118,15 +117,13 @@ export default class Controller { window.showInformationMessage('Connexion validée'); } - const mission = new Mission(missionId, missionVersion); - const currentUser = await this.apiService.getCurrentUser(); const user: User = userId ? await this.apiService.getUser(userId) : currentUser; if (!!userId && userId !== currentUser.id) { try { - await this.apiService.grantAccessToRepository(user.id, mission.id); + await this.apiService.grantAccessToRepository(user.id, missionId); } catch (e) { if (hasStatusNumber(e)) { if (e.status === 403) { @@ -141,7 +138,13 @@ export default class Controller { const giteaPublicProperties: GiteaPublicProperties = await this.apiService.getGiteaPublicProperties(); - const missionDevcontainer = new MissionDevContainer(user, currentUser, mission, giteaPublicProperties); + const missionDevcontainer = new MissionDevContainer( + user, + currentUser, + missionId, + missionVersion, + giteaPublicProperties, + ); try { await missionDevcontainer.open(); diff --git a/deadlock-plugins/deadlock-extension/src/core/mission/missionDevContainer.ts b/deadlock-plugins/deadlock-extension/src/core/mission/missionDevContainer.ts index f595c87d27d68cbf10c2639f1958b6a6c0b245c7..ddd9555cf09d61b23c6958aed83640df7287de16 100644 --- a/deadlock-plugins/deadlock-extension/src/core/mission/missionDevContainer.ts +++ b/deadlock-plugins/deadlock-extension/src/core/mission/missionDevContainer.ts @@ -1,7 +1,6 @@ import { missionWorkdir, userSshKeyFolderPath } from '../config'; import { Base, DockerfileSpecific, LifecycleScripts, VSCodespecific } from './models/devContainer'; import { mkdir, writeFile } from 'fs/promises'; -import { Mission } from './models/mission'; import { GiteaPublicProperties } from '../../model/giteaPublicProperties.model'; import { commands, Uri } from 'vscode'; import { existsSync, copyFileSync } from 'fs'; @@ -33,7 +32,8 @@ export class MissionDevContainer { constructor( private readonly user: User, private readonly currentUser: User, - private readonly mission: Mission, + private readonly missionId: string, + private readonly missionVersion: string, private readonly giteaProperties: GiteaPublicProperties, ) { let prefix = missionWorkdir; @@ -41,10 +41,10 @@ export class MissionDevContainer { prefix += `/students/${this.user.details.lastName}_${this.user.details.firstName}_${this.user.id}`; } this.dirs = { - missionWorkdir: `${prefix}/${this.mission.id}`, - config: `${prefix}/${this.mission.id}/.config`, - devcontainer: `${prefix}/${this.mission.id}/.devcontainer`, - mounted: `${prefix}/${this.mission.id}/mounted`, + missionWorkdir: `${prefix}/${this.missionId}`, + config: `${prefix}/${this.missionId}/.config`, + devcontainer: `${prefix}/${this.missionId}/.devcontainer`, + mounted: `${prefix}/${this.missionId}/mounted`, }; if (process.env.DL_MOUNT_EXTENSION === 'true') { this.extentionPath = '/injected-extension/extension.vsix'; @@ -84,8 +84,8 @@ export class MissionDevContainer { giteaSshPort: this.giteaProperties.sshPort, username: this.user.id.split('-').join(''), email: `${this.user.id.split('-').join('')}@deadlock.io`, - missionId: this.mission.id, - missionVersion: this.mission.version, + missionId: this.missionId, + missionVersion: this.missionVersion, remoteGitUsername: this.user.id.split('-').join(''), currentUserDetails: this.currentUser.details, currentUserId: this.currentUser.id, @@ -130,8 +130,8 @@ export class MissionDevContainer { `${this.dirs.devcontainer}/devcontainer.json`, (() => { const devcontainer: Partial<DockerfileSpecific & Base & VSCodespecific & LifecycleScripts> = { - name: `deadlock-${this.mission.id}`, - image: `${REGISTRY_MISSION_URL}/${this.mission.id}:${this.mission.version}`, + name: `deadlock-${this.missionId}`, + image: `${REGISTRY_MISSION_URL}/${this.missionId}:${this.missionVersion}`, containerEnv: { WORKDIR: `${remoteMissionDir}`, }, diff --git a/deadlock-plugins/deadlock-extension/src/core/mission/models/mission.ts b/deadlock-plugins/deadlock-extension/src/core/mission/models/mission.ts deleted file mode 100644 index ba27109c96a09ddd2633e3ff21045b3b8f192da9..0000000000000000000000000000000000000000 --- a/deadlock-plugins/deadlock-extension/src/core/mission/models/mission.ts +++ /dev/null @@ -1,9 +0,0 @@ -export class Mission { - readonly id: string; - readonly version: string; - - constructor(id: string, version: string) { - this.id = id; - this.version = version; - } -} diff --git a/deadlock-plugins/deadlock-extension/src/model/challengeYaml.ts b/deadlock-plugins/deadlock-extension/src/model/challengeYaml.ts deleted file mode 100644 index 257beec6c4ed9cc3d7936c42f752e0fed6532053..0000000000000000000000000000000000000000 --- a/deadlock-plugins/deadlock-extension/src/model/challengeYaml.ts +++ /dev/null @@ -1,25 +0,0 @@ -interface ChallengeYaml { - version: number; - name: string; - label: string; - description: string; - level: - | 'Jajarbinks' // le plus facile - | 'Ewok' - | 'Padawan' - | 'Jedi' - | 'Master'; // le plus difficile - type: 'DESKTOP'; - xp: Map<string, number>; - desktop: { - scripts: MissionCommand[]; - }; -} - -export interface MissionCommand { - name: string; - command: string; - description?: string; -} - -export default ChallengeYaml; diff --git a/deadlock-plugins/deadlock-extension/src/model/mission.ts b/deadlock-plugins/deadlock-extension/src/model/mission.ts new file mode 100644 index 0000000000000000000000000000000000000000..3595f571c05890346038d63ea8be7af2270fc47c --- /dev/null +++ b/deadlock-plugins/deadlock-extension/src/model/mission.ts @@ -0,0 +1,28 @@ +interface Mission { + version: string; + name: string; + label: string; + description: string; + level: + | 'Jajarbinks' // le plus facile + | 'Ewok' + | 'Padawan' + | 'Jedi' + | 'Master'; // le plus difficile + type: 'DESKTOP'; + xp: Map<string, number>; + desktop: { + scripts: MissionCommand[]; + }; +} + +export class MissionCommand { + constructor( + public readonly name: string, + public readonly command: string, + public readonly description?: string, + public readonly type: 'submit' | 'setup' | 'run' = 'run', + ) {} +} + +export default Mission; diff --git a/deadlock-plugins/deadlock-extension/src/recorder/services/automatic-save.ts b/deadlock-plugins/deadlock-extension/src/recorder/services/automatic-save.ts index 7637bb089560c0251704ba5e6c09508fd8ea8a80..faa7925bb1dd2b4c6a0cb676a2541fe43b9025b1 100644 --- a/deadlock-plugins/deadlock-extension/src/recorder/services/automatic-save.ts +++ b/deadlock-plugins/deadlock-extension/src/recorder/services/automatic-save.ts @@ -1,4 +1,4 @@ -import { CommitFrom, getIgnorePatternFromIgnoreFile } from '../utils/gitea'; +import { getIgnorePatternFromIgnoreFile } from '../utils/gitea'; import FileWatcher from './file-watcher'; import { commitAndPushOnQueue } from '../utils/gitea'; import GitMission from '../../core/gitMission'; @@ -11,7 +11,7 @@ export default class AutomaticSave { async setupAutomaticSave() { const ignoreFilePatterns = await getIgnorePatternFromIgnoreFile('/deadlock/.gitignore'); new FileWatcher(this.folderToWatch, ['**/*'], ignoreFilePatterns, () => { - commitAndPushOnQueue(this.gitMission, CommitFrom.Auto); + commitAndPushOnQueue(this.gitMission, 'Auto'); }); } } diff --git a/deadlock-plugins/deadlock-extension/src/recorder/utils/gitea.ts b/deadlock-plugins/deadlock-extension/src/recorder/utils/gitea.ts index bda09447464f43e10ae5952989b449e49a16b8ed..438528736d04c83a14ba3eaa0eb577277ef1bec5 100644 --- a/deadlock-plugins/deadlock-extension/src/recorder/utils/gitea.ts +++ b/deadlock-plugins/deadlock-extension/src/recorder/utils/gitea.ts @@ -17,14 +17,8 @@ const gitQueue = queue(async (task: CallableFunction) => { await task(); }, 1); -export enum CommitFrom { - Run = 'Run', - Auto = 'Auto', - HttpServer = 'HttpServer', -} - -export async function commitAndPushOnQueue(gitMission: GitMission, from: CommitFrom) { - if (from === CommitFrom.Run) { +export async function commitAndPushOnQueue(gitMission: GitMission, from: 'Run' | 'Auto' | 'HttpServer') { + if (from === 'Run') { gitQueue.push(async () => { await mergeMaster(gitMission); }); diff --git a/deadlock-plugins/deadlock-extension/src/theia/command.ts b/deadlock-plugins/deadlock-extension/src/theia/command.ts index aa88aad0bee4350989d4ac73cd0be5dedc93dafb..f785eb10101000de8879e5fd68626b5c6a74d388 100644 --- a/deadlock-plugins/deadlock-extension/src/theia/command.ts +++ b/deadlock-plugins/deadlock-extension/src/theia/command.ts @@ -1,6 +1,6 @@ import { Command as VscodeComand } from 'vscode'; -export class Command { +export class VsCommand { constructor(private _title: string, private command: string) {} get title() { @@ -16,5 +16,5 @@ export class Command { } } -export const openBriefingCommand = new Command('Open Briefing', 'deadlock.openBriefing'); -export const openQuickSetupCommand = new Command('Open Deadlock quick setup page', 'deadlock.openQuickSetup'); +export const openBriefingCommand = new VsCommand('Open Briefing', 'deadlock.openBriefing'); +export const openQuickSetupCommand = new VsCommand('Open Deadlock quick setup page', 'deadlock.openQuickSetup'); diff --git a/deadlock-plugins/deadlock-extension/src/view/CommandTree.ts b/deadlock-plugins/deadlock-extension/src/view/CommandTree.ts index a762606e7cdf8459d0289554aa775f72ab5f9991..9edb00cea6ccc2aebc732af93831eaad24d17702 100644 --- a/deadlock-plugins/deadlock-extension/src/view/CommandTree.ts +++ b/deadlock-plugins/deadlock-extension/src/view/CommandTree.ts @@ -1,13 +1,13 @@ import isDocker from '../core/utils/isdocker'; -import ChallengeYaml, { MissionCommand as MissionCommandYaml } from '../model/challengeYaml'; +import Mission, { MissionCommand } from '../model/mission'; import { parse } from 'yaml'; import { readFileSync } from 'fs'; import { commands, ExtensionContext, ThemeColor, ThemeIcon, TreeDataProvider, TreeItem, window } from 'vscode'; -import { commitAndPushOnQueue, CommitFrom } from '../recorder/utils/gitea'; +import { commitAndPushOnQueue } from '../recorder/utils/gitea'; import Recorder from '../recorder/recorder'; -export class CommandTreeProvider implements TreeDataProvider<MissionCommand> { - challenge: ChallengeYaml; +export class CommandTreeProvider implements TreeDataProvider<CommandItem> { + challenge: Mission; context: ExtensionContext; constructor(context: ExtensionContext) { this.context = context; @@ -19,42 +19,59 @@ export class CommandTreeProvider implements TreeDataProvider<MissionCommand> { } } - getTreeItem(element: MissionCommand): TreeItem { + getTreeItem(element: CommandItem): TreeItem { return element; } - getChildren(element?: MissionCommand): Thenable<MissionCommand[]> { + getChildren(element?: CommandItem): Thenable<CommandItem[]> { if (element) { return Promise.resolve([]); } else { - return Promise.resolve(this.challenge.desktop?.scripts?.map((script) => new MissionCommand(script)) ?? []); + return Promise.resolve(this.challenge.desktop?.scripts?.map((script) => new CommandItem(script)) ?? []); } } } -class MissionCommand extends TreeItem { - missionCommandYaml: MissionCommandYaml; - constructor(missionCommandYaml: MissionCommandYaml) { - super(missionCommandYaml.name); - this.missionCommandYaml = missionCommandYaml; - this.tooltip = missionCommandYaml.description; - this.description = missionCommandYaml.description; - this.iconPath = new ThemeIcon('notebook-execute', new ThemeColor('debugIcon.startForeground')); - commands.registerCommand(missionCommandYaml.name, () => { - const terminalName = `Deadlock`; - const terminal = - window.terminals.filter((terminal) => terminal.name === terminalName)[0] ?? - window.createTerminal({ - cwd: process.env.WORKDIR, - name: terminalName, - }); - terminal.sendText(missionCommandYaml.command); - terminal.show(); - commitAndPushOnQueue(Recorder.instance.gitMission, CommitFrom.Run); - }); +const terminalName = `Deadlock`; + +class CommandItem extends TreeItem { + constructor(private readonly missionCommand: MissionCommand) { + super(missionCommand.name); + this.tooltip = missionCommand.description ?? missionCommand.name; + this.description = missionCommand.description ?? missionCommand.name; + this.iconPath = new ThemeIcon( + 'notebook-execute', + new ThemeColor(missionCommand.type === 'submit' ? 'debugIcon.stopForeground' : 'debugIcon.startForeground'), + ); this.command = { - title: missionCommandYaml.name, - command: missionCommandYaml.name, + title: missionCommand.name, + command: missionCommand.name, + tooltip: this.tooltip, }; + commands.registerCommand(missionCommand.name, () => { + if (missionCommand.type === 'submit') { + window.showInformationMessage('Êtes-vous sûr de soumettre votre solution ?', 'Oui', 'Non').then((answer) => { + if (answer === 'Oui') { + this.apply(); + } + }); + } else { + this.apply(); + } + }); + } + + apply() { + const terminal = + window.terminals.filter((terminal) => terminal.name === terminalName)[0] ?? + window.createTerminal({ + cwd: process.env.WORKDIR, + name: terminalName, + }); + terminal.sendText(this.missionCommand.command); + terminal.show(); + if (this.missionCommand.type === 'submit' || this.missionCommand.type === 'run') { + commitAndPushOnQueue(Recorder.instance.gitMission, 'Run'); + } } } diff --git a/deadlock-plugins/deadlock-extension/src/view/webviewBase.ts b/deadlock-plugins/deadlock-extension/src/view/webviewBase.ts index a543bd861bc104fa0e0aaac7c45a13a2f8a750a4..ebfbe6836aba9e3d46ae7b7c6d2e0b62672846ae 100644 --- a/deadlock-plugins/deadlock-extension/src/view/webviewBase.ts +++ b/deadlock-plugins/deadlock-extension/src/view/webviewBase.ts @@ -9,7 +9,7 @@ import { WebviewPanelOnDidChangeViewStateEvent, window, } from 'vscode'; -import { Command } from '../theia/command'; +import { VsCommand } from '../theia/command'; const emptyCommands: Disposable[] = [ { @@ -28,7 +28,7 @@ export abstract class WebviewBase implements Disposable { private disposablePanel: Disposable | undefined; protected panel: WebviewPanel | undefined; - constructor(private id: string, private title: string, command: Command, private readonly _column?: ViewColumn) { + constructor(private id: string, private title: string, command: VsCommand, private readonly _column?: ViewColumn) { this.disposable = Disposable.from(commands.registerCommand(command.cmd, this.onShowCommand, this)); this.load(); }