Odoo18-Base/addons/web/static/lib/hoot/ui/hoot_buttons.js
2025-01-06 10:57:38 +07:00

162 lines
5.5 KiB
JavaScript

/** @odoo-module */
import { Component, useState, xml } from "@odoo/owl";
import { refresh, subscribeToURLParams } from "../core/url";
import { STORAGE, storageSet } from "../hoot_utils";
import { HootLink } from "./hoot_link";
/**
* @typedef {{
* }} HootButtonsProps
*/
//-----------------------------------------------------------------------------
// Global
//-----------------------------------------------------------------------------
const {
clearTimeout,
Object: { keys: $keys },
setTimeout,
} = globalThis;
//-----------------------------------------------------------------------------
// Internal
//-----------------------------------------------------------------------------
const DISABLE_TIMEOUT = 500;
//-----------------------------------------------------------------------------
// Exports
//-----------------------------------------------------------------------------
/** @extends {Component<HootButtonsProps, import("../hoot").Environment>} */
export class HootButtons extends Component {
static components = { HootLink };
static props = {};
static template = xml`
<t t-set="isRunning" t-value="runnerState.status === 'running'" />
<t t-set="showAll" t-value="env.runner.hasFilter" />
<t t-set="showFailed" t-value="runnerState.failedIds.size" />
<t t-set="failedSuites" t-value="getFailedSuiteIds()" />
<div
class="${HootButtons.name} relative"
t-on-mouseenter="() => !isRunning and (state.open = true)"
t-on-mouseleave="() => state.open = false"
>
<div class="flex rounded gap-px overflow-hidden">
<button
type="button"
class="flex items-center bg-btn gap-2 px-2 py-1 transition-colors"
t-on-click.stop="onRunClick"
t-att-title="isRunning ? 'Stop (Esc)' : 'Run'"
t-att-disabled="state.disable"
>
<i t-attf-class="fa fa-{{ isRunning ? 'stop' : 'play' }}" />
<span t-esc="isRunning ? 'Stop' : 'Run'" />
</button>
<t t-if="showAll or showFailed">
<button
type="button"
class="bg-btn px-2 py-1 transition-colors animate-slide-left"
t-on-click.stop="() => state.open = !state.open"
>
<i class="fa fa-caret-down transition" t-att-class="{ 'rotate-180': state.open }" />
</button>
</t>
</div>
<t t-if="state.open">
<div
class="animate-slide-down w-fit absolute flex flex-col end-0 shadow rounded overflow-hidden shadow z-2"
>
<t t-if="showAll">
<HootLink class="'bg-btn p-2 whitespace-nowrap transition-colors'">
Run <strong>all</strong> tests
</HootLink>
</t>
<t t-if="showFailed">
<HootLink
type="'test'"
id="runnerState.failedIds"
class="'bg-btn p-2 whitespace-nowrap transition-colors'"
title="'Run failed tests'"
onClick="onRunFailedClick"
>
Run failed <strong>tests</strong>
</HootLink>
<HootLink
type="'suite'"
id="failedSuites"
class="'bg-btn p-2 whitespace-nowrap transition-colors'"
title="'Run failed suites'"
onClick="onRunFailedClick"
>
Run failed <strong>suites</strong>
</HootLink>
</t>
</div>
</t>
</div>
`;
setup() {
const { runner } = this.env;
this.state = useState({
disable: false,
open: false,
});
this.runnerState = useState(runner.state);
this.disableTimeout = 0;
subscribeToURLParams(...$keys(runner.config));
}
getFailedSuiteIds() {
const { tests } = this.env.runner;
const suiteIds = [];
for (const id of this.runnerState.failedIds) {
const test = tests.get(id);
if (test && !suiteIds.includes(test.parent.id)) {
suiteIds.push(test.parent.id);
}
}
return suiteIds;
}
onRunClick() {
const { runner } = this.env;
switch (runner.state.status) {
case "done": {
refresh();
break;
}
case "ready": {
if (runner.config.manual) {
runner.manualStart();
} else {
refresh();
}
break;
}
case "running": {
runner.stop();
if (this.disableTimeout) {
clearTimeout(this.disableTimeout);
}
this.state.disable = true;
this.disableTimeout = setTimeout(
() => (this.state.disable = false),
DISABLE_TIMEOUT
);
break;
}
}
}
onRunFailedClick() {
storageSet(STORAGE.failed, []);
}
}