Files
nomad/ui/app/components/task-sub-row.js
Phil Renaud fb14c2b556 [ui] Actions service and flyout (#19084)
* Initial pass at a global actions instance queue

* Action card with a bunch of functionality that needs to be pared back a bit

* Happy little actions button

* runAction performs updated to use actions service

* Stop All and Clear Finished buttons

* Keyboard service now passes element, so we can pseudo-click the actions dropdown

* resizable sidebar code blocks

* Contextual actions within task and job levels

* runAction greatly consolidated

* Pluralize action text

* Peer grouping of flyout action intances

* ShortIDs instead of full alloc IDs

* Testfixes that previously depended on notifications

* Stop and stop all for peered action instances

* Job name in action instance card linkable

* Componentized actions global button

* scss consolidation

* Clear and Stop buttons become mutually exclusive in an action card

* Clean up action card title styles a bit

* todo-bashing

* stopAll and stopPeers separated and fixed up

* Socket handling functions moved to the Actions service

* Error handling on socket message

* Smarter import

* Documentation note: need alloc-exec and alloc-raw-exec for raw_exec jobs

* Tests for flyout and dropdown actions

* Docs link when in empty flyout/queue state and percy snapshot test for it
2023-11-26 23:46:44 -05:00

124 lines
2.9 KiB
JavaScript

/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
// @ts-check
import Ember from 'ember';
import Component from '@glimmer/component';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
import { computed } from '@ember/object';
import { alias } from '@ember/object/computed';
import { task, timeout } from 'ember-concurrency';
import { tracked } from '@glimmer/tracking';
export default class TaskSubRowComponent extends Component {
@service store;
@service router;
@service notifications;
@service nomadActions;
@service('stats-trackers-registry') statsTrackersRegistry;
constructor() {
super(...arguments);
// Kick off stats polling
const allocation = this.task.allocation;
if (allocation) {
this.fetchStats.perform();
} else {
this.fetchStats.cancelAll();
}
}
@alias('args.taskState') task;
@action
gotoTask(allocation, task) {
this.router.transitionTo('allocations.allocation.task', allocation, task);
}
// Since all tasks for an allocation share the same tracker, use the registry
@computed('task.{allocation,isRunning}')
get stats() {
if (!this.task.isRunning) return undefined;
return this.statsTrackersRegistry.getTracker(this.task.allocation);
}
// Internal state
@tracked statsError = false;
@computed
get enablePolling() {
return !Ember.testing;
}
@computed('task.name', 'stats.tasks.[]')
get taskStats() {
if (!this.stats) return undefined;
return this.stats.tasks.findBy('task', this.task.name);
}
@alias('taskStats.cpu.lastObject') cpu;
@alias('taskStats.memory.lastObject') memory;
@(task(function* () {
do {
if (this.stats) {
try {
yield this.stats.poll.linked().perform();
this.statsError = false;
} catch (error) {
this.statsError = true;
}
}
yield timeout(500);
} while (this.enablePolling);
}).drop())
fetchStats;
//#region Logs Sidebar
@alias('args.active') shouldShowLogs;
@action handleTaskLogsClick(task) {
if (this.args.onSetActiveTask) {
this.args.onSetActiveTask(task);
}
}
@action closeSidebar() {
if (this.args.onSetActiveTask) {
this.args.onSetActiveTask(null);
}
}
//#endregion Logs Sidebar
get namespace() {
return this.task.task?.taskGroup.job.namespace;
}
/**
* @param {string} action - The action to run
* @param {string} allocID - The allocation ID to run the action on
* @param {Event} ev - The event that triggered the action
*/
@task(function* (action, allocID) {
try {
yield this.nomadActions.runAction({ action, allocID });
} catch (err) {
this.notifications.add({
title: `Error starting ${action.name}`,
message: err,
sticky: true,
color: 'critical',
});
}
})
runAction;
}