diff --git a/front/Dockerfile b/front/Dockerfile index 7765b402d..bf2b9133c 100644 --- a/front/Dockerfile +++ b/front/Dockerfile @@ -47,9 +47,8 @@ RUN mix sentry_recompile && mix compile --warnings-as-errors # -- node stage FROM node:16-alpine AS node WORKDIR /assets -COPY front/assets/package.json front/assets/package-lock.json ./ -RUN npm set progress=false && npm install COPY front/assets ./ +RUN npm ci --force # -- node stage # -- dev stage - for local development diff --git a/front/assets/.eslintrc.js b/front/assets/.eslintrc.js index c155256e6..b8a9aec04 100644 --- a/front/assets/.eslintrc.js +++ b/front/assets/.eslintrc.js @@ -26,7 +26,7 @@ module.exports = { }, ignorePatterns: ["*.js", "*.json"], rules: {}, - overrides: [ + overrides: [ { files: ["js/**/*.spec.js"], env: { @@ -86,7 +86,8 @@ module.exports = { }, }, ], - "no-console": 1, + "no-console": ["error", { allow: ["warn", "error"] }], + "max-len": ["error", {"code": 140, "ignoreComments": true, "ignoreStrings": true, "ignoreTemplateLiterals": true}], "no-multi-spaces": "error", "@typescript-eslint/member-delimiter-style": [ "warn", @@ -97,7 +98,7 @@ module.exports = { }, singleline: { delimiter: "comma", - requireLast: true, + requireLast: false, }, }, ], @@ -105,6 +106,9 @@ module.exports = { "react/jsx-uses-react": "off", "react/react-in-jsx-scope": "off", "react/display-name": "off", + "react/jsx-first-prop-new-line": ["error", "multiline"], + "react/jsx-max-props-per-line": ["error", { maximum: {single: 2, multi: 1} }], + "react/jsx-closing-bracket-location": ["error", { selfClosing: "line-aligned", nonEmpty: "line-aligned" }], "react/jsx-tag-spacing": [ "error", { @@ -114,6 +118,27 @@ module.exports = { beforeClosing: "never", }, ], + "comma-dangle": "off", + "@typescript-eslint/comma-dangle": [ + "error", + { + arrays: "always-multiline", + objects: "always-multiline", + imports: "always-multiline", + exports: "always-multiline", + functions: "never", + enums: "always-multiline", + generics: "always-multiline", + tuples: "always-multiline" + } + ], + "@typescript-eslint/consistent-type-imports": ["warn", { prefer: "type-imports" }], + "@typescript-eslint/no-misused-promises": [ + "error", + { + "checksVoidReturn": false + } + ] }, }, ], diff --git a/front/assets/build.js b/front/assets/build.js index e4bf10708..14090d257 100644 --- a/front/assets/build.js +++ b/front/assets/build.js @@ -83,7 +83,7 @@ const buildOptions = { if (watch) { esbuild.context(buildOptions).then(async context => { - context.watch() + await context.watch() await copyAssets() const chokidar = require('chokidar') diff --git a/front/assets/css/app.css b/front/assets/css/app.css index 42db35208..e7a9796ee 100644 --- a/front/assets/css/app.css +++ b/front/assets/css/app.css @@ -107,42 +107,22 @@ summary.no-expand::marker { } .material-symbols-outlined { - font-variation-settings: 'FILL' 0, 'wght' 300, 'GRAD' 0, 'opsz' 16; - font-size: 16px; -} - -.material-symbols-outlined.f1 { - font-size: 3rem; -} - -.material-symbols-outlined.f2 { - font-size: 2.25rem; -} - -.material-symbols-outlined.f3 { - font-size: 1.5rem; -} - -.material-symbols-outlined.f4 { - font-size: 1.25rem; -} - -.material-symbols-outlined.f5 { - font-size: 1rem; -} - -.material-symbols-outlined.f6 { - font-size: .875rem; + font-variation-settings: + 'FILL' var(--material-symbol-fill, 0), + 'wght' var(--material-symbol-weight, 300), + 'GRAD' var(--material-symbol-grad, 0), + 'opsz' var(--material-symbol-opsz, 20); } -.material-symbols-outlined.f7 { - font-size: .75rem; +.material-symbols-outlined.fill { + --material-symbol-fill: 1; } .material-symbols-outlined.b { - font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 20; + --material-symbol-weight: 400; } + sem-tooltip slot[slot="content"], sem-popover slot[slot="content"] { display: none; @@ -466,21 +446,43 @@ sem-popover { user-select: none; } -.material-symbols-outlined { - font-variation-settings: - 'FILL' 0, - 'wght' 300, - 'GRAD' 0, - 'opsz' 20 +.gap1 { + gap: 0.25rem; +} + +.gap2 { + gap: 0.5rem; +} + +.gap3 { + gap: 0.75rem; +} + +.gap4 { + gap: 1rem; +} + +.flex1 { + flex: 1 1 0%; +} + +.flex2 { + flex: 2 2 0%; +} + +.flex3 { + flex: 3 3 0%; +} + +.flex4 { + flex: 4 4 0%; +} + +.flex-break { + flex-basis: 100%; + height: 0; +} +.break-column { + flex-basis: 100%; + width: 0; } -.material-symbols-outlined.fill { - font-variation-settings: - 'FILL' 1, - 'wght' 300, - 'GRAD' 0, - 'opsz' 20 -} -.material-symbols-outlined.md-18 { font-size: 18px; } -.material-symbols-outlined.md-24 { font-size: 24px; } -.material-symbols-outlined.md-36 { font-size: 36px; } -.material-symbols-outlined.md-48 { font-size: 48px; } diff --git a/front/assets/js/agents/components/activity_item.tsx b/front/assets/js/agents/components/activity_item.tsx index bc130d1a2..6fd3f80b3 100644 --- a/front/assets/js/agents/components/activity_item.tsx +++ b/front/assets/js/agents/components/activity_item.tsx @@ -1,4 +1,5 @@ -import { Fragment, h, VNode } from "preact"; +import type { h, VNode } from "preact"; +import { Fragment } from "preact"; import { useContext, useState } from "preact/hooks"; import * as stores from "../stores"; import * as toolbox from "js/toolbox"; diff --git a/front/assets/js/agents/components/activity_monitor.tsx b/front/assets/js/agents/components/activity_monitor.tsx index c0191df39..9bdc55218 100644 --- a/front/assets/js/agents/components/activity_monitor.tsx +++ b/front/assets/js/agents/components/activity_monitor.tsx @@ -59,7 +59,11 @@ const LobbyItems = () => { in their branch, pull request and delivery queue {lobbyItems.map((item, idx) => ( - + ))} ); diff --git a/front/assets/js/agents/components/agents.tsx b/front/assets/js/agents/components/agents.tsx index ed8403788..e8c409343 100644 --- a/front/assets/js/agents/components/agents.tsx +++ b/front/assets/js/agents/components/agents.tsx @@ -1,4 +1,5 @@ -import { h, Fragment } from "preact"; +import type { h } from "preact"; +import { Fragment } from "preact"; import { useContext } from "preact/hooks"; import * as stores from "../stores"; import { useNavigate } from "react-router-dom"; diff --git a/front/assets/js/agents/components/code.tsx b/front/assets/js/agents/components/code.tsx index 09b50ff7a..2375a75a1 100644 --- a/front/assets/js/agents/components/code.tsx +++ b/front/assets/js/agents/components/code.tsx @@ -1,4 +1,4 @@ -import { h } from "preact"; +import type { h } from "preact"; interface CodeProps extends h.JSX.HTMLAttributes { content: string; } diff --git a/front/assets/js/agents/components/git_providers.tsx b/front/assets/js/agents/components/git_providers.tsx index 8830dca49..aa66b1382 100644 --- a/front/assets/js/agents/components/git_providers.tsx +++ b/front/assets/js/agents/components/git_providers.tsx @@ -1,4 +1,4 @@ -import { h } from "preact"; +import type { h } from "preact"; import * as components from "."; import { useState } from "preact/compat"; import styled from "styled-components"; diff --git a/front/assets/js/agents/components/instructions/aws.tsx b/front/assets/js/agents/components/instructions/aws.tsx index 2b7b615de..a8cf4c32a 100644 --- a/front/assets/js/agents/components/instructions/aws.tsx +++ b/front/assets/js/agents/components/instructions/aws.tsx @@ -1,7 +1,8 @@ import * as stores from "../../stores"; import * as components from "../"; import { useContext, useState } from "preact/hooks"; -import { Fragment, h, VNode } from "preact"; +import type { h, VNode } from "preact"; +import { Fragment } from "preact"; import styled from "styled-components"; export const name = `AWS`; diff --git a/front/assets/js/agents/components/instructions/kubernetes.tsx b/front/assets/js/agents/components/instructions/kubernetes.tsx index 0d4ce1b92..291a4fc99 100644 --- a/front/assets/js/agents/components/instructions/kubernetes.tsx +++ b/front/assets/js/agents/components/instructions/kubernetes.tsx @@ -1,4 +1,5 @@ -import { Fragment, VNode } from "preact"; +import type { VNode } from "preact"; +import { Fragment } from "preact"; import * as stores from "../../stores"; import * as components from "../"; import { useContext } from "preact/hooks"; @@ -18,7 +19,11 @@ export const Component = (): VNode => {
  • Install{` `} - + helm
    diff --git a/front/assets/js/agents/components/instructions/linux.tsx b/front/assets/js/agents/components/instructions/linux.tsx index 1d2b4e94a..9c92d66f3 100644 --- a/front/assets/js/agents/components/instructions/linux.tsx +++ b/front/assets/js/agents/components/instructions/linux.tsx @@ -1,4 +1,5 @@ -import { Fragment, VNode } from "preact"; +import type { VNode } from "preact"; +import { Fragment } from "preact"; import * as stores from "../../stores"; import * as components from "../"; import { useContext } from "preact/hooks"; diff --git a/front/assets/js/agents/components/instructions/macos.tsx b/front/assets/js/agents/components/instructions/macos.tsx index 7270d7766..2f6e6ffc3 100644 --- a/front/assets/js/agents/components/instructions/macos.tsx +++ b/front/assets/js/agents/components/instructions/macos.tsx @@ -1,4 +1,5 @@ -import { Fragment, h, VNode } from "preact"; +import type { h, VNode } from "preact"; +import { Fragment } from "preact"; import * as stores from "../../stores"; import * as components from "../"; import { useContext, useState } from "preact/hooks"; @@ -182,7 +183,11 @@ export const HomebrewInstructions = () => {
  • Install{` `} - + Homebrew
    diff --git a/front/assets/js/agents/components/instructions/rhel.tsx b/front/assets/js/agents/components/instructions/rhel.tsx index a08fd7ac6..c5e6595be 100644 --- a/front/assets/js/agents/components/instructions/rhel.tsx +++ b/front/assets/js/agents/components/instructions/rhel.tsx @@ -1,4 +1,5 @@ -import { Fragment, VNode } from "preact"; +import type { VNode } from "preact"; +import { Fragment } from "preact"; import * as stores from "../../stores"; import * as components from "../"; import { useContext } from "preact/hooks"; diff --git a/front/assets/js/agents/components/instructions/ubuntu.tsx b/front/assets/js/agents/components/instructions/ubuntu.tsx index 4eda90bb3..52cf68507 100644 --- a/front/assets/js/agents/components/instructions/ubuntu.tsx +++ b/front/assets/js/agents/components/instructions/ubuntu.tsx @@ -1,4 +1,5 @@ -import { Fragment, VNode } from "preact"; +import type { VNode } from "preact"; +import { Fragment } from "preact"; import * as stores from "../../stores"; import * as components from "../"; import { useContext } from "preact/hooks"; diff --git a/front/assets/js/agents/components/instructions/windows.tsx b/front/assets/js/agents/components/instructions/windows.tsx index a80462ef5..d2d1ff91e 100644 --- a/front/assets/js/agents/components/instructions/windows.tsx +++ b/front/assets/js/agents/components/instructions/windows.tsx @@ -1,4 +1,5 @@ -import { Fragment, VNode } from "preact"; +import type { VNode } from "preact"; +import { Fragment } from "preact"; import * as stores from "../../stores"; import * as components from "../"; import { useContext } from "preact/hooks"; diff --git a/front/assets/js/agents/components/os_box.tsx b/front/assets/js/agents/components/os_box.tsx index 3bf1d2d87..19624ec0e 100644 --- a/front/assets/js/agents/components/os_box.tsx +++ b/front/assets/js/agents/components/os_box.tsx @@ -1,5 +1,5 @@ import * as toolbox from "js/toolbox"; -import { VNode, h } from "preact"; +import type { VNode, h } from "preact"; interface OsBoxProps extends h.JSX.HTMLAttributes { name: string; icon?: string; diff --git a/front/assets/js/agents/components/pre_copy.tsx b/front/assets/js/agents/components/pre_copy.tsx index 2989fae0f..af44fd6a3 100644 --- a/front/assets/js/agents/components/pre_copy.tsx +++ b/front/assets/js/agents/components/pre_copy.tsx @@ -1,4 +1,4 @@ -import { h } from "preact"; +import type { h } from "preact"; import * as toolbox from "js/toolbox"; import { useState } from "preact/hooks"; import dedent from "dedent"; diff --git a/front/assets/js/agents/components/self_hosted.tsx b/front/assets/js/agents/components/self_hosted.tsx index 96f6fc177..7684011ba 100644 --- a/front/assets/js/agents/components/self_hosted.tsx +++ b/front/assets/js/agents/components/self_hosted.tsx @@ -1,7 +1,7 @@ -import { h } from "preact"; +import type { h } from "preact"; import * as components from "../components"; import { useEffect, useState } from "preact/hooks"; -import * as types from "../types"; +import type * as types from "../types"; import * as Instructions from "./instructions"; export interface Instruction { diff --git a/front/assets/js/agents/index.tsx b/front/assets/js/agents/index.tsx index 6cc209bf7..2136dc146 100644 --- a/front/assets/js/agents/index.tsx +++ b/front/assets/js/agents/index.tsx @@ -5,7 +5,7 @@ import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom"; import * as stores from "js/agents/stores"; import * as pages from "js/agents/pages"; -export default function ({ dom, config }: { dom: HTMLElement, config: any, }) { +export default function ({ dom, config }: { dom: HTMLElement, config: any }) { const configState = stores.Config.State.fromJSON(config); render( diff --git a/front/assets/js/agents/pages/self_hosted/agent.tsx b/front/assets/js/agents/pages/self_hosted/agent.tsx index 2cc94b135..5fd61982f 100644 --- a/front/assets/js/agents/pages/self_hosted/agent.tsx +++ b/front/assets/js/agents/pages/self_hosted/agent.tsx @@ -12,9 +12,7 @@ import moment from "moment"; import { Notice } from "js/notice"; export const Agent = () => { - const { state, dispatch: dispatchSelfHostedAgent } = useContext( - stores.SelfHostedAgent.Context - ); + const { state, dispatch: dispatchSelfHostedAgent } = useContext(stores.SelfHostedAgent.Context); const navigate = useNavigate(); const selfHostedAgent = state.type; const [showGuide, setShowGuide] = useState(false); @@ -29,7 +27,7 @@ export const Agent = () => { if (!selfHostedAgent) return; const { state: locationState } = useLocation(); - const targetId = (locationState as any)?.targetId as string; + const targetId = (locationState )?.targetId as string; useEffect(() => { if (state.type && state.type.totalAgentCount === 0) { @@ -47,10 +45,7 @@ export const Agent = () => { const refreshActivity = async () => { setRefreshing(true); try { - await types.SelfHosted.AgentType.get( - config.selfHostedUrl, - state.type.name - ) + await types.SelfHosted.AgentType.get(config.selfHostedUrl, state.type.name) .then((agentType) => { dispatchSelfHostedAgent({ type: `SET_AGENT_TYPE`, @@ -84,9 +79,7 @@ export const Agent = () => { const EmptyList = () => { return (
    -

    - No agents are currently connected to this agent type. -

    +

    No agents are currently connected to this agent type.

    ); }; @@ -100,28 +93,16 @@ export const Agent = () => { {config.accessProvider.canManageAgents() && (
    - - - -
    @@ -169,13 +150,7 @@ export const Agent = () => {

    - - {toolbox.Pluralize( - selfHostedAgent.totalAgentCount, - `connected agent`, - `connected agents` - )} - + {toolbox.Pluralize(selfHostedAgent.totalAgentCount, `connected agent`, `connected agents`)} · @@ -209,9 +184,7 @@ const ConnectedAgent = (props: ConnectAgentProps) => { } }; const disableAgent = async () => { - await toolbox.APIRequest.post( - `${config.selfHostedUrl}/${selfHostedState.type.name}/agents/${agent.name}/disable?format=json` - ); + await toolbox.APIRequest.post(`${config.selfHostedUrl}/${selfHostedState.type.name}/agents/${agent.name}/disable?format=json`); }; const agent = props.agent; @@ -222,9 +195,7 @@ const ConnectedAgent = (props: ConnectAgentProps) => { onMouseOver={() => setShowStop(true)} onMouseOut={() => setShowStop(false)} > - {showStop && ( - - )} + {showStop && }

    @@ -270,16 +241,10 @@ const StopAgent = (props: StopAgentProps) => { return (
    Are you sure? - -
    @@ -293,7 +258,5 @@ const StopAgent = (props: StopAgentProps) => { } }; - return ( -
    {content()}
    - ); + return
    {content()}
    ; }; diff --git a/front/assets/js/agents/pages/self_hosted/delete.tsx b/front/assets/js/agents/pages/self_hosted/delete.tsx index dbcfafd0b..a0cfada41 100644 --- a/front/assets/js/agents/pages/self_hosted/delete.tsx +++ b/front/assets/js/agents/pages/self_hosted/delete.tsx @@ -1,4 +1,3 @@ - import { useNavigate, useParams } from "react-router-dom"; import { useContext } from "preact/hooks"; import * as stores from "js/agents/stores"; @@ -36,16 +35,10 @@ export const Delete = () => {
    - - navigate(`..`)} - > + navigate(`..`)}> Nevermind
    diff --git a/front/assets/js/agents/pages/self_hosted/disable_all.tsx b/front/assets/js/agents/pages/self_hosted/disable_all.tsx index 2f0cefe9a..25323ece8 100644 --- a/front/assets/js/agents/pages/self_hosted/disable_all.tsx +++ b/front/assets/js/agents/pages/self_hosted/disable_all.tsx @@ -6,7 +6,7 @@ import * as stores from "js/agents/stores"; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore import { Notice } from "js/notice"; -import { TargetedEvent } from "preact/compat"; +import type { TargetedEvent } from "preact/compat"; export const DisableAll = () => { const navigate = useNavigate(); diff --git a/front/assets/js/agents/pages/self_hosted/edit.tsx b/front/assets/js/agents/pages/self_hosted/edit.tsx index 655e71e8b..2300951f8 100644 --- a/front/assets/js/agents/pages/self_hosted/edit.tsx +++ b/front/assets/js/agents/pages/self_hosted/edit.tsx @@ -3,8 +3,8 @@ import { useNavigate } from "react-router-dom"; import * as toolbox from "js/toolbox"; import { useContext, useEffect, useState } from "preact/hooks"; import * as stores from "js/agents/stores"; -import * as types from "js/agents/types"; -import { TargetedEvent } from "preact/compat"; +import type * as types from "js/agents/types"; +import type { TargetedEvent } from "preact/compat"; import _ from "lodash"; // eslint-disable-next-line @typescript-eslint/ban-ts-comment diff --git a/front/assets/js/agents/stores/activity.tsx b/front/assets/js/agents/stores/activity.tsx index 0924a2277..1ea75a032 100644 --- a/front/assets/js/agents/stores/activity.tsx +++ b/front/assets/js/agents/stores/activity.tsx @@ -125,13 +125,13 @@ export class Item { } export type Action = - | { type: `SET_WAITING_ITEMS`, value: Item[], } - | { type: `SET_RUNNING_ITEMS`, value: Item[], } - | { type: `SET_LOBBY_ITEMS`, value: Item[], } - | { type: `SET_HOSTED_AGENTS`, value: Agent[], } - | { type: `SET_SELF_HOSTED_AGENTS`, value: Agent[], } - | { type: `DELETE_SELF_HOSTED_AGENT`, value: string, } - | { type: `SET_INVISIBLE_JOBS_COUNT`, value: number, }; + | { type: `SET_WAITING_ITEMS`, value: Item[] } + | { type: `SET_RUNNING_ITEMS`, value: Item[] } + | { type: `SET_LOBBY_ITEMS`, value: Item[] } + | { type: `SET_HOSTED_AGENTS`, value: Agent[] } + | { type: `SET_SELF_HOSTED_AGENTS`, value: Agent[] } + | { type: `DELETE_SELF_HOSTED_AGENT`, value: string } + | { type: `SET_INVISIBLE_JOBS_COUNT`, value: number }; export interface State { hostedAgents: Agent[]; diff --git a/front/assets/js/agents/stores/self_hosted_agent.tsx b/front/assets/js/agents/stores/self_hosted_agent.tsx index 82d79e77f..732ab1eb0 100644 --- a/front/assets/js/agents/stores/self_hosted_agent.tsx +++ b/front/assets/js/agents/stores/self_hosted_agent.tsx @@ -1,14 +1,14 @@ import { createContext } from "preact"; -import * as types from "../types"; +import type * as types from "../types"; export type Action = - | { type: `SET_AGENT_TYPE`, value: types.SelfHosted.AgentType, } - | { type: `SET_AGENTS`, value: types.SelfHosted.Agent[], } - | { type: `SET_TOKEN`, value: string, } - | { type: `REVEAL_TOKEN`, } - | { type: `HIDE_TOKEN`, } - | { type: `JUST_CREATED`, } - | { type: `JUST_RESET`, }; + | { type: `SET_AGENT_TYPE`, value: types.SelfHosted.AgentType } + | { type: `SET_AGENTS`, value: types.SelfHosted.Agent[] } + | { type: `SET_TOKEN`, value: string } + | { type: `REVEAL_TOKEN` } + | { type: `HIDE_TOKEN` } + | { type: `JUST_CREATED` } + | { type: `JUST_RESET` }; export interface State { token: string; diff --git a/front/assets/js/agents/types/instruction.ts b/front/assets/js/agents/types/instruction.ts index f31b63ba1..fbe5dc5a6 100644 --- a/front/assets/js/agents/types/instruction.ts +++ b/front/assets/js/agents/types/instruction.ts @@ -1,4 +1,4 @@ -import { VNode } from "preact"; +import type { VNode } from "preact"; export default interface Instruction { name: string; diff --git a/front/assets/js/billing/app.tsx b/front/assets/js/billing/app.tsx index cbec22670..58d793bfd 100644 --- a/front/assets/js/billing/app.tsx +++ b/front/assets/js/billing/app.tsx @@ -1,4 +1,5 @@ -import { Fragment, VNode } from "preact"; +import type { VNode } from "preact"; +import { Fragment } from "preact"; import * as pages from "./pages"; import * as components from "./components"; import * as stores from "./stores"; diff --git a/front/assets/js/billing/components/available_credits.tsx b/front/assets/js/billing/components/available_credits.tsx index 7c129d5d6..0794fe868 100644 --- a/front/assets/js/billing/components/available_credits.tsx +++ b/front/assets/js/billing/components/available_credits.tsx @@ -1,10 +1,8 @@ - import * as toolbox from "js/toolbox"; -import * as types from "../types"; +import type * as types from "../types"; import * as stores from "../stores"; import { useContext } from "preact/hooks"; - interface AvailableCreditsProps { credits: types.Credits.Available[]; } @@ -13,56 +11,57 @@ export const AvailableCredits = (props: AvailableCreditsProps) => { const { state } = useContext(stores.Spendings.Context); const currentCredits = state.currentSpending.summary.creditsStarting; - const tooltipContent =
    -
    -
    What is this?
    -
    Your monthly spending will always be substracted first from the credits batch with the earliest expiry date.
    -
    Credits batches that have expired or were consumed are not displayed.
    + const tooltipContent = ( +
    +
    +
    What is this?
    +
    + Your monthly spending will always be substracted first from the credits batch with the earliest expiry date. +
    +
    Credits batches that have expired or were consumed are not displayed.
    +
    -
    ; + ); - return
    -
    -
    -
    - payments -
    Available credits
    + return ( +
    +
    +
    +
    + payments +
    Available credits
    - } - content={tooltipContent} - /> + } content={tooltipContent}/> +
    -
    -
    -
    -
    -
    -
    -
    -
    Date expiring
    -
    Date added
    -
    Type
    -
    Credits remaining
    +
    +
    +
    +
    +
    +
    +
    Date expiring
    +
    Date added
    +
    Type
    +
    Credits remaining
    +
    +
    - - -
    -
    -
    -
    -
    -
    - {currentCredits} +
    +
    +
    +
    + {currentCredits} +
    -
    ; + ); }; const ListAvailableCredits = (props: AvailableCreditsProps) => { @@ -70,23 +69,27 @@ const ListAvailableCredits = (props: AvailableCreditsProps) => { return idx === props.credits.length - 1; }; - return
    - {props.credits.map((credit, idx) => { - return
    -
    -
    -
    -
    {toolbox.Formatter.dateFull(credit.expiresAt)}
    -
    {toolbox.Formatter.dateFull(credit.givenAt)}
    -
    {credit.typeName}
    -
    - {credit.amount} + return ( +
    + {props.credits.map((credit, idx) => { + return ( +
    +
    +
    +
    +
    {toolbox.Formatter.dateFull(credit.expiresAt)}
    +
    {toolbox.Formatter.dateFull(credit.givenAt)}
    +
    {credit.typeName}
    +
    + {credit.amount} +
    +
    -
    -
    ; - })} - {props.credits.length === 0 &&
    No credits available
    } -
    ; + ); + })} + {props.credits.length === 0 &&
    No credits available
    } +
    + ); }; diff --git a/front/assets/js/billing/components/charts.tsx b/front/assets/js/billing/components/charts.tsx index a0624e344..35397d786 100644 --- a/front/assets/js/billing/components/charts.tsx +++ b/front/assets/js/billing/components/charts.tsx @@ -1,4 +1,5 @@ -import { Fragment, VNode, createContext, createRef } from "preact"; +import type { VNode } from "preact"; +import { Fragment, createContext, createRef } from "preact"; import * as d3 from "d3"; import { useContext, useEffect, useLayoutEffect, useState } from "preact/hooks"; import _ from "lodash"; @@ -21,7 +22,7 @@ const DefaultPlotState: PlotState = { width: 0, }; -const PlotContext = createContext<{ plotState: PlotState, plotData: PlotData[], }>({ +const PlotContext = createContext<{ plotState: PlotState, plotData: PlotData[] }>({ plotState: DefaultPlotState, plotData: [], }); @@ -202,7 +203,12 @@ export const DateAxisX = () => { }, [yTranslation, plotState.xScale]); return ( - + ); }; @@ -254,7 +260,7 @@ export const LineChartLeft = (props: YScaleProps) => { middown, mid, midup, - top + top, ].map(d => Math.floor(d))); d3.select(yScaleRef.current) @@ -264,7 +270,12 @@ export const LineChartLeft = (props: YScaleProps) => { return ( - + ); @@ -302,7 +313,7 @@ export const MoneyScaleY = () => { middown, mid, midup, - top + top, ].map(d => Math.floor(d))); @@ -312,7 +323,12 @@ export const MoneyScaleY = () => { }, [plotState.yScale, plotState.width, plotData]); return ( - + ); }; @@ -377,8 +393,16 @@ export const LineChart = (props: ChartProps) => { return ( - - + + ); }; diff --git a/front/assets/js/billing/components/group_tooltip.tsx b/front/assets/js/billing/components/group_tooltip.tsx index b161a2bd1..12a31be2f 100644 --- a/front/assets/js/billing/components/group_tooltip.tsx +++ b/front/assets/js/billing/components/group_tooltip.tsx @@ -14,7 +14,7 @@ export const GroupTooltip = (props: GroupTooltipProps) => { />; }; -const GroupDescription = ({ group }: { group: types.Spendings.Group, }) => { +const GroupDescription = ({ group }: { group: types.Spendings.Group }) => { switch (group.type) { case types.Spendings.GroupType.MachineCapacity: return ( @@ -53,7 +53,11 @@ const GroupDescription = ({ group }: { group: types.Spendings.Group, }) => {
    What is this?
    - Storage and Egress spending is generated by using artifacts, which are files generated during your builds. + Storage and Egress spending is generated by using artifacts, which are files generated during your builds.
    Storage is measured in GB per month and increases as you store more data in your artifacts over time.
    Egress is measured in GB and represents the network egress incurred when you download artifacts to an external location or within your jobs.
    diff --git a/front/assets/js/billing/components/index.ts b/front/assets/js/billing/components/index.ts index 1dfe3bff8..51213c541 100644 --- a/front/assets/js/billing/components/index.ts +++ b/front/assets/js/billing/components/index.ts @@ -29,5 +29,5 @@ export { ProjectChart, SpendingGroup, Charts, - Loader + Loader, }; diff --git a/front/assets/js/billing/components/invoice_list.tsx b/front/assets/js/billing/components/invoice_list.tsx index 19feb14f7..df232517a 100644 --- a/front/assets/js/billing/components/invoice_list.tsx +++ b/front/assets/js/billing/components/invoice_list.tsx @@ -61,7 +61,7 @@ export const InvoiceList = () => { ); }; -const Invoice = ({ invoice, lastItem }: { invoice: types.Spendings.Invoice, lastItem?: boolean, }) => { +const Invoice = ({ invoice, lastItem }: { invoice: types.Spendings.Invoice, lastItem?: boolean }) => { return (
    diff --git a/front/assets/js/billing/components/loader.tsx b/front/assets/js/billing/components/loader.tsx index 909e92050..e03b55515 100644 --- a/front/assets/js/billing/components/loader.tsx +++ b/front/assets/js/billing/components/loader.tsx @@ -1,4 +1,5 @@ -import { Fragment, VNode } from "preact"; +import type { VNode } from "preact"; +import { Fragment } from "preact"; import * as stores from "../stores"; import * as toolbox from "js/toolbox"; import * as types from "../types"; @@ -22,14 +23,18 @@ export const Container = (props: Props) => { } }; -export const LoadingSpinner = ({ text }: { text: string, }) => { +export const LoadingSpinner = ({ text }: { text: string }) => { return (
    - +
    {text}
    ); }; -export const LoadingFailed = ({ text, retry }: { text: string, retry?: boolean, }) => { +export const LoadingFailed = ({ text, retry }: { text: string, retry?: boolean }) => { const { dispatch: dispatchRequest } = useContext(stores.Request.Context); if(retry) { diff --git a/front/assets/js/billing/components/navigation.tsx b/front/assets/js/billing/components/navigation.tsx index 500e09507..38eddb805 100644 --- a/front/assets/js/billing/components/navigation.tsx +++ b/front/assets/js/billing/components/navigation.tsx @@ -14,7 +14,7 @@ export const Navigation = () => { const displayProjects = config.projectSpendings; const hasPlans = config.availablePlans.length > 0; - const className = ({ isActive }: { isActive: boolean, }) => { + const className = ({ isActive }: { isActive: boolean }) => { return ( `link db pv1 ph2 br3 ` + (isActive ? `white active bg-green` : `dark-gray hover-bg-lightest-gray`) diff --git a/front/assets/js/billing/components/plan_flags.tsx b/front/assets/js/billing/components/plan_flags.tsx index b3d328455..e9fc9f251 100644 --- a/front/assets/js/billing/components/plan_flags.tsx +++ b/front/assets/js/billing/components/plan_flags.tsx @@ -1,5 +1,5 @@ import { Fragment } from "preact"; -import * as types from "../types"; +import type * as types from "../types"; import * as toolbox from "js/toolbox"; import * as stores from "../stores"; import { useContext } from "preact/hooks"; @@ -16,7 +16,7 @@ export const PlanFlags = () => { ); }; -const SuspensionFlag = ({ plan }: { plan: types.Spendings.Plan, }) => { +const SuspensionFlag = ({ plan }: { plan: types.Spendings.Plan }) => { if (plan.didCreditsRunOut()) { return ; } @@ -30,7 +30,7 @@ const SuspensionFlag = ({ plan }: { plan: types.Spendings.Plan, }) => { } }; -const NoPaymentMethod = ({ plan }: { plan: types.Spendings.Plan, }) => { +const NoPaymentMethod = ({ plan }: { plan: types.Spendings.Plan }) => { return (
    Payment method not set.
    @@ -39,7 +39,7 @@ const NoPaymentMethod = ({ plan }: { plan: types.Spendings.Plan, }) => { ); }; -const PaymentFailed = ({ plan }: { plan: types.Spendings.Plan, }) => { +const PaymentFailed = ({ plan }: { plan: types.Spendings.Plan }) => { return (
    Your last payment failed.
    @@ -48,7 +48,7 @@ const PaymentFailed = ({ plan }: { plan: types.Spendings.Plan, }) => { ); }; -const CreditsRunOut = ({ plan }: { plan: types.Spendings.Plan, }) => { +const CreditsRunOut = ({ plan }: { plan: types.Spendings.Plan }) => { let content = `You ran out of credits.`; if (plan.isFree()) { content = `You used up your free credit quota.`; diff --git a/front/assets/js/billing/components/project_chart.tsx b/front/assets/js/billing/components/project_chart.tsx index 25de474bb..82d7f1c80 100644 --- a/front/assets/js/billing/components/project_chart.tsx +++ b/front/assets/js/billing/components/project_chart.tsx @@ -1,9 +1,10 @@ -import { Spendings } from "../types"; +import type { Spendings } from "../types"; import * as components from "../components"; -import * as types from "../types"; +import type * as types from "../types"; import * as stores from "../stores"; -import { Dispatch, StateUpdater, useContext, useEffect, useLayoutEffect, useReducer, useState } from "preact/hooks"; +import type { Dispatch, StateUpdater } from "preact/hooks"; +import { useContext, useEffect, useLayoutEffect, useReducer, useState } from "preact/hooks"; import _ from "lodash"; import { Formatter } from "js/toolbox"; import moment from "moment"; @@ -11,7 +12,7 @@ import * as d3 from "d3"; enum AggregationType { Daily = `daily`, - Cumulative = `cumulative` + Cumulative = `cumulative`, } interface Props { @@ -28,7 +29,7 @@ export const ProjectChart = (props: Props) => { const [groupTypes, setGroupTypes] = useState([props.project.cost.groups[0].type]); const [tooltipState, dispatchTooltip] = useReducer(stores.Tooltip.Reducer, { - ...stores.Tooltip.EmptyState + ...stores.Tooltip.EmptyState, }); const [colorScale, setColorScale] = useState<(arg0: string) => string>(() => d3.scaleOrdinal(d3.schemeTableau10)); @@ -125,7 +126,11 @@ export const ProjectChart = (props: Props) => { - + { "top": tooltip.y, "left": left, "width": width, - "z-index": `3` + "z-index": `3`, }} >
    @@ -265,14 +270,22 @@ const Legend = (props: LegendProps) => {
    - for {props.project.cost.groups.map((group, idx) => ( ))} @@ -287,7 +300,11 @@ const Legend = (props: LegendProps) => { classes += `o-50`; } - return
    selectMetric(label)}> + return
    selectMetric(label)} + > {label}
    ; diff --git a/front/assets/js/billing/components/projects_chart.tsx b/front/assets/js/billing/components/projects_chart.tsx index c7206cc5e..cd26cd27d 100644 --- a/front/assets/js/billing/components/projects_chart.tsx +++ b/front/assets/js/billing/components/projects_chart.tsx @@ -1,8 +1,9 @@ -import { Spendings } from "../types"; +import type { Spendings } from "../types"; import * as stores from "../stores"; import * as components from "../components"; import * as types from "../types"; -import { Dispatch, StateUpdater, useContext, useLayoutEffect, useReducer, useState } from "preact/hooks"; +import type { Dispatch, StateUpdater } from "preact/hooks"; +import { useContext, useLayoutEffect, useReducer, useState } from "preact/hooks"; import _ from "lodash"; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore @@ -13,7 +14,7 @@ import * as d3 from "d3"; enum AggregationType { Daily = `daily`, - Cumulative = `cumulative` + Cumulative = `cumulative`, } export const ProjectsChart = () => { @@ -25,13 +26,11 @@ export const ProjectsChart = () => { }); const [projects, setProjects] = useState([]); - const spending = spendings.state.selectedSpending; - if(!spending) - return; + if (!spending) return; useLayoutEffect(() => { - if(spendings.state.selectedSpending) { + if (spendings.state.selectedSpending) { dispatchRequest({ type: `SET_PARAM`, name: `spending_id`, value: spendings.state.selectedSpendingId }); dispatchRequest({ type: `FETCH` }); @@ -39,10 +38,8 @@ export const ProjectsChart = () => { } }, [spendings.state.selectedSpending]); - useLayoutEffect(() => { - if(request.status == types.RequestStatus.Fetch) { - + if (request.status == types.RequestStatus.Fetch) { dispatchRequest({ type: `SET_STATUS`, value: types.RequestStatus.Loading }); fetch(request.url) .then((response) => response.json()) @@ -80,23 +77,22 @@ const Chart = (props: ChartProps) => { const [selectedProject, setSelectedProject] = useState(``); const [domain, setDomain] = useState<[Date, Date]>([new Date(), new Date()]); const [tooltipState, dispatchTooltip] = useReducer(stores.Tooltip.Reducer, { - ...stores.Tooltip.EmptyState + ...stores.Tooltip.EmptyState, }); useLayoutEffect(() => { - if(!projects.length) - return; + if (!projects.length) return; // aggregate the data according to the aggregation type. We need aggregated plot data to properly calculate the scales const aggregatedPlotData = _.chain(projects) .map((project) => project.plotData) - .map((plotData) => aggregatePlotData(plotData, aggregationType) ) + .map((plotData) => aggregatePlotData(plotData, aggregationType)) .flatten() .value(); const dates = _.map(projects, (project) => project.plotDomain); - const minDate = _.minBy(dates, d => d[0]); - const maxDate = _.maxBy(dates, d => d[1]); + const minDate = _.minBy(dates, (d) => d[0]); + const maxDate = _.maxBy(dates, (d) => d[1]); setDomain([minDate ? minDate[0] : new Date(), maxDate ? maxDate[1] : new Date()]); @@ -106,8 +102,8 @@ const Chart = (props: ChartProps) => { const aggregatePlotData = (plotData: components.Charts.PlotData[], aggregationType: AggregationType): components.Charts.PlotData[] => { let value = 0; return _.chain(plotData) - .map(plotData => { - switch(aggregationType) { + .map((plotData) => { + switch (aggregationType) { case AggregationType.Cumulative: value += plotData.value; return { ...plotData, value } as components.Charts.PlotData; @@ -120,8 +116,9 @@ const Chart = (props: ChartProps) => { .value(); }; - const colorScale = d3.scaleOrdinal() - .domain(props.projects.map((project)=> project.name)) + const colorScale = d3 + .scaleOrdinal() + .domain(props.projects.map((project) => project.name)) .range(d3.schemeTableau10); return ( @@ -137,17 +134,25 @@ const Chart = (props: ChartProps) => { <> {projects.map((project, idx) => { - const projectSelected = (project.name == selectedProject) || (selectedProject == ``); - return ; + const projectSelected = project.name == selectedProject || selectedProject == ``; + return ( + + ); })} - + @@ -155,23 +160,20 @@ const Chart = (props: ChartProps) => { ); }; - const Tooltip = () => { const { state: tooltip } = useContext(stores.Tooltip.Context); - if(tooltip.hidden && !tooltip.focus) - return; + if (tooltip.hidden && !tooltip.focus) return; const adjustedLeft = (left: number) => { if (left < 2 * width) { left += 25; } else { - left -= (width + 25); + left -= width + 25; } return left; }; - if(!tooltip.tooltipMetrics) - return; + if (!tooltip.tooltipMetrics) return; const width = 250; const left = adjustedLeft(tooltip.x); @@ -182,28 +184,29 @@ const Tooltip = () => {
    {moment(firstMetric.day).format(`MMMM Do`)}
    {metrics.map((metric, idx) => { - return
    -
    {metric.name}
    -
    {Formatter.toMoney(metric.value)}
    -
    ; + return ( +
    +
    {metric.name}
    +
    {Formatter.toMoney(metric.value)}
    +
    + ); })}
    ); }; - interface LegendProps { aggregationType: AggregationType; setAggregationType: Dispatch>; @@ -213,7 +216,7 @@ interface LegendProps { } const Legend = (props: LegendProps) => { const selectProject = (project: types.Spendings.Project) => () => { - if(project.name == props.selectedProject) { + if (project.name == props.selectedProject) { props.setSelectedProject(``); } else { props.setSelectedProject(project.name); @@ -226,15 +229,20 @@ const Legend = (props: LegendProps) => { props.setAggregationType(aggregate); }; - const colorScale = d3.scaleOrdinal() - .domain(props.projects.map((project)=> project.name)) + const colorScale = d3 + .scaleOrdinal() + .domain(props.projects.map((project) => project.name)) .range(d3.schemeTableau10); return (
    - @@ -243,16 +251,22 @@ const Legend = (props: LegendProps) => {
    {props.projects.map((project, idx) => { let classes = ``; - if(props.selectedProject == project.name || props.selectedProject == ``) { + if (props.selectedProject == project.name || props.selectedProject == ``) { classes += `o-100`; } else { classes += `o-50`; } - return
    - - {project.name} -
    ; + return ( +
    + + {project.name} +
    + ); })}
    diff --git a/front/assets/js/billing/components/spending_chart.tsx b/front/assets/js/billing/components/spending_chart.tsx index 5cb703e83..d78e0ee6f 100644 --- a/front/assets/js/billing/components/spending_chart.tsx +++ b/front/assets/js/billing/components/spending_chart.tsx @@ -1,4 +1,3 @@ - import { Spendings } from "../types"; import * as stores from "../stores"; import * as types from "../types"; @@ -10,17 +9,15 @@ import { useContext, useLayoutEffect, useReducer, useState } from "preact/hooks" export const SpendingChart = () => { const spendings = useContext(stores.Spendings.Context); const config = useContext(stores.Config.Context); - const [state, dispatch] = useReducer(stores.Prices.Reducer, { ... stores.Prices.EmptyState, url: config.costsUrl } ); - + const [state, dispatch] = useReducer(stores.Prices.Reducer, { ...stores.Prices.EmptyState, url: config.costsUrl }); const spending = spendings.state.selectedSpending; - if(!spending) - return; + if (!spending) return; const groups = spending.groups || []; useLayoutEffect(() => { - if(spending) { + if (spending) { const url = new URL(config.costsUrl, location.origin); url.searchParams.set(`spending_id`, spendings.state.selectedSpendingId); @@ -33,7 +30,8 @@ export const SpendingChart = () => { dispatch({ type: `SET_PRICES`, prices: costs }); dispatch({ type: `SET_STATUS`, value: stores.Prices.Status.Loaded }); - }).catch((e) => { + }) + .catch((e) => { dispatch({ type: `SET_STATUS`, value: stores.Prices.Status.Error }); dispatch({ type: `SET_STATUS_MESSAGE`, value: `${e as string}` }); }); @@ -47,7 +45,7 @@ export const SpendingChart = () => { const setGroup = (group: Spendings.GroupType) => { const index = groupTypes.indexOf(group); - if(index == -1) { + if (index == -1) { setGroupsTypes([...groupTypes, group]); } else { const newGroupTypes = [...groupTypes]; @@ -65,8 +63,7 @@ export const SpendingChart = () => { const lastPriceInGroup = (type: Spendings.GroupType): string => { const prices = state.prices.filter((price) => price.type == type); - if(prices.length == 0) - return toolbox.Formatter.toMoney(0); + if (prices.length == 0) return toolbox.Formatter.toMoney(0); return toolbox.Formatter.toMoney(prices[prices.length - 1].priceUpToDay); }; @@ -77,28 +74,50 @@ export const SpendingChart = () => {
    stacked_bar_chart -
    Spending stats · {spendings.state.selectedSpending?.name}
    +
    + Spending stats · {spendings.state.selectedSpending?.name} +
    - {groups.map((group, idx) => )} + {groups.map((group, idx) => ( + + ))}
    - +
    - + + for {groups.map((group, idx) => ( ))}
    @@ -125,22 +144,22 @@ const Chart = ({ spending, aggregate, groupTypes, costs }: ChartProps) => { useLayoutEffect(() => { let metrics: types.Metric.Interface[] = []; - if(aggregate == `cumulative`) { + if (aggregate == `cumulative`) { metrics = selectedCosts.map((cost: Spendings.DailySpending) => { return { name: cost.type, date: cost.day, - value: cost.priceUpToDay + value: cost.priceUpToDay, } as types.Metric.Interface; }); } - if(aggregate == `normal`) { + if (aggregate == `normal`) { metrics = selectedCosts.map((cost: Spendings.DailySpending) => { return { name: cost.type, date: cost.day, - value: cost.price + value: cost.price, } as types.Metric.Interface; }); } @@ -149,13 +168,9 @@ const Chart = ({ spending, aggregate, groupTypes, costs }: ChartProps) => { const domain = [d3.timeDay.floor(spending.from), d3.timeDay.ceil(spending.to)]; - return (
    - +
    ); }; diff --git a/front/assets/js/billing/components/spending_group.tsx b/front/assets/js/billing/components/spending_group.tsx index b9153931d..c3d394f34 100644 --- a/front/assets/js/billing/components/spending_group.tsx +++ b/front/assets/js/billing/components/spending_group.tsx @@ -1,10 +1,10 @@ - -import { Fragment, VNode } from "preact"; +import type { VNode } from "preact"; +import { Fragment } from "preact"; import { useState, useLayoutEffect } from "preact/hooks"; import * as toolbox from "js/toolbox"; import * as types from "../types"; import * as components from "../components"; -import { Item } from "../types/spendings"; +import type { Item } from "../types/spendings"; interface SpendingGroupProps { group: types.Spendings.Group; @@ -20,12 +20,19 @@ export const SpendingGroup = (props: SpendingGroupProps) => { const GroupItems = () => { if (displayZeroState) { return ; - } - else { + } else { if (props.group.isCapacityBased()) { return ; } else { - return ; + return ( + + ); } } }; @@ -88,16 +95,20 @@ const Items = (props: ItemsProps) => { if (isDesc) { order = [``, ``]; - } else if(isAsc) { + } else if (isAsc) { order = [name, `desc`]; } else { order = [name, `asc`]; } return ( -
    setSortOrder(order)} className="gray pointer" style="user-select: none;"> +
    setSortOrder(order)} + className="gray pointer" + style="user-select: none;" + >
    - {displayName} + {displayName} {isAsc && expand_more} {isDesc && expand_less} {isNone && unfold_more} @@ -116,13 +127,17 @@ const Items = (props: ItemsProps) => {
    Type
    - {!props.hideUnitPrice &&
    - {props.group.priceLabel} -
    } - {!props.hideUsage &&
    - {sortingEnabled && columnFilter(props.group.usageLabel, `usage`, `justify-end`)} - {!sortingEnabled && props.group.usageLabel} -
    } + {!props.hideUnitPrice && ( +
    + {props.group.priceLabel} +
    + )} + {!props.hideUsage && ( +
    + {sortingEnabled && columnFilter(props.group.usageLabel, `usage`, `justify-end`)} + {!sortingEnabled && props.group.usageLabel} +
    + )}
    {sortingEnabled && columnFilter(`Total`, `price`, `justify-end`)} {!sortingEnabled && `Total`} @@ -132,33 +147,40 @@ const Items = (props: ItemsProps) => {
    - {sortedItems.map((item, idx) => - - )} + {sortedItems.map((item, idx) => ( + + ))}
    -
    - {props.footer} -
    - {props.group.showUsage && +
    {props.footer}
    + {props.group.showUsage && ( - {!props.hideUsage && + {!props.hideUsage && (
    {toolbox.Formatter.decimalThousands(props.group.usage)} {showTrendInSummary && summaryItem && }
    - } + )}
    {props.group.price}
    -
    } - {!props.group.showUsage && + + )} + {!props.group.showUsage && (
    {props.group.price}
    - } + )}
    @@ -199,16 +221,20 @@ const CapacityItems = ({ group, footer }: ItemsProps) => { if (isDesc) { order = [``, ``]; - } else if(isAsc) { + } else if (isAsc) { order = [name, `desc`]; } else { order = [name, `asc`]; } return ( -
    setSortOrder(order)} className="gray pointer" style="user-select: none;"> +
    setSortOrder(order)} + className="gray pointer" + style="user-select: none;" + >
    - {displayName} + {displayName} {isAsc && expand_more} {isDesc && expand_less} {isNone && unfold_more} @@ -236,15 +262,18 @@ const CapacityItems = ({ group, footer }: ItemsProps) => {
    - {sortedItems.map((item, idx) => - - )} + {sortedItems.map((item, idx) => ( + + ))}
    -
    - {footer} -
    - {group.showUsage && +
    {footer}
    + {group.showUsage && (
    @@ -256,12 +285,12 @@ const CapacityItems = ({ group, footer }: ItemsProps) => {
    {group.price}
    - } - {!group.showUsage && + )} + {!group.showUsage && (
    {group.price}
    - } + )}
    @@ -270,30 +299,36 @@ const CapacityItems = ({ group, footer }: ItemsProps) => { const ItemsWithZeroState = ({ group }: ItemsProps) => { const zeroStateContent = () => { - switch(group.type) { + switch (group.type) { case types.Spendings.GroupType.Addon: return ( - +

    No active add-ons

    -

    Contact support to learn more about add-ons.

    +

    + Contact support to learn more about add-ons. +

    ); default: return ( - +

    No active {group.name}

    ); } }; - return ( -
    - {zeroStateContent()} -
    - ); + return
    {zeroStateContent()}
    ; }; interface SpendingGroupItemProps { @@ -305,15 +340,13 @@ interface SpendingGroupItemProps { showTotalPriceTrends?: boolean; } - const SpendingGroupItem = (props: SpendingGroupItemProps) => { const { group, item, lastItem, hideUnitPrice, hideUsage } = props; const [tiersExpanded, expandTiers] = useState(false); const bottomLine = !lastItem || (item.tiers.length > 0 && tiersExpanded); const ItemData = () => { - - if(group.isCapacityBased()) { + if (group.isCapacityBased()) { return (
    @@ -325,9 +358,7 @@ const SpendingGroupItem = (props: SpendingGroupItemProps) => {
    -
    - {item.usage} x machines -
    +
    {item.usage} x machines
    ); @@ -343,12 +374,14 @@ const SpendingGroupItem = (props: SpendingGroupItemProps) => {
    {!hideUnitPrice &&
    {item.unitPrice}
    } - {!hideUsage &&
    -
    - {toolbox.Formatter.decimalThousands(item.usage)} - {group.showTrends && } + {!hideUsage && ( +
    +
    + {toolbox.Formatter.decimalThousands(item.usage)} + {group.showTrends && } +
    -
    } + )}
    {item.price} @@ -358,10 +391,9 @@ const SpendingGroupItem = (props: SpendingGroupItemProps) => { ); } - }; - const ItemTierData = ({ tier }: { tier: Item, }) => { + const ItemTierData = ({ tier }: { tier: Item }) => { return (
    @@ -369,11 +401,11 @@ const SpendingGroupItem = (props: SpendingGroupItemProps) => { {tier.description != `` && · {tier.description}}
    {!hideUnitPrice &&
    {tier.unitPrice}
    } - {!hideUsage &&
    -
    - {toolbox.Formatter.decimalThousands(tier.usage)} + {!hideUsage && ( +
    +
    {toolbox.Formatter.decimalThousands(tier.usage)}
    -
    } + )}
    {tier.price}
    ); @@ -392,19 +424,20 @@ const SpendingGroupItem = (props: SpendingGroupItemProps) => {
    - {tiersExpanded && item.tiers.map((tier, idx) => -
    -
    -
    -
    -
    - + {tiersExpanded && + item.tiers.map((tier, idx) => ( +
    +
    +
    +
    +
    + +
    -
    - )} + ))} ); }; diff --git a/front/assets/js/billing/components/spending_plot.tsx b/front/assets/js/billing/components/spending_plot.tsx index 089595961..bd6ed7fe0 100644 --- a/front/assets/js/billing/components/spending_plot.tsx +++ b/front/assets/js/billing/components/spending_plot.tsx @@ -1,4 +1,5 @@ -import { createRef, VNode } from "preact"; +import type { VNode } from "preact"; +import { createRef } from "preact"; import { useEffect, useState, useLayoutEffect } from "preact/hooks"; import _ from "lodash"; import * as d3 from "d3"; @@ -52,7 +53,7 @@ export const Plot = ({ domain, metrics }: PlotProps) => { }, xScale: d3.scaleTime(), yScale: d3.scaleLinear(), - width: 0 + width: 0, }); @@ -109,8 +110,18 @@ export const Plot = ({ domain, metrics }: PlotProps) => { height={state.height} > - - + + {!tooltip.hidden && { }, [translation, xScale]); return ( - + ); }; -export const Tooltip = ({ top, left, content }: { top: number, left: number, content: VNode, }) => { +export const Tooltip = ({ top, left, content }: { top: number, left: number, content: VNode }) => { const adjustedLeft = (left: number) => { if (left < 2 * width) { left += 25; @@ -179,7 +195,7 @@ export const Tooltip = ({ top, left, content }: { top: number, left: number, con "top": top, "left": left, "width": width, - "z-index": `3` + "z-index": `3`, }} > {content} @@ -224,7 +240,7 @@ const Count = ({ yScale, translation, metrics }: CountProps) => { middown, mid, midup, - top + top, ].map(d => Math.floor(d))); @@ -234,7 +250,12 @@ const Count = ({ yScale, translation, metrics }: CountProps) => { }, [yScale, translation, metrics]); return ( - + ); }; @@ -388,7 +409,7 @@ const StackedBar = ({ xScale, yScale, metrics, tooltip, setTooltip }: StackedBar
    {toolbox.Formatter.humanize(subgroupName)}: {toolbox.Formatter.toMoney(subgroupValue)}
    -
    +
    , }); d3.selectAll(`.chart-rect`).style(`opacity`, 0.2); @@ -399,7 +420,7 @@ const StackedBar = ({ xScale, yScale, metrics, tooltip, setTooltip }: StackedBar setTooltip({ ...tooltip, hidden: true, - content: undefined + content: undefined, }); d3.selectAll(`.chart-rect`).style(`opacity`,0.7); diff --git a/front/assets/js/billing/components/spending_select.tsx b/front/assets/js/billing/components/spending_select.tsx index ad2515e85..d320ced1f 100644 --- a/front/assets/js/billing/components/spending_select.tsx +++ b/front/assets/js/billing/components/spending_select.tsx @@ -16,7 +16,11 @@ export const SpendingSelect = () => { return (
    - {state.spendings.map((spending, idx) => ( ))} diff --git a/front/assets/js/billing/components/trend.tsx b/front/assets/js/billing/components/trend.tsx index 85b101584..ba84e3ff9 100644 --- a/front/assets/js/billing/components/trend.tsx +++ b/front/assets/js/billing/components/trend.tsx @@ -1,5 +1,5 @@ -import * as types from "../types"; +import type * as types from "../types"; import * as toolbox from "js/toolbox"; interface Trendable { @@ -13,7 +13,7 @@ enum TooltipType { Price, } -const Icon = ({ item, type }: { item: Trendable, type: TooltipType, }) => { +const Icon = ({ item, type }: { item: Trendable, type: TooltipType }) => { const trend = type == TooltipType.Usage ? item.usageTrend : item.priceTrend; switch (trend) { case `up`: @@ -70,10 +70,10 @@ const Tooltip = (props: TooltipProps) => { return ; }; -export const PriceTooltip = ({ item }: { item: Trendable, }) => { +export const PriceTooltip = ({ item }: { item: Trendable }) => { return ; }; -export const UsageTooltip = ({ item }: { item: Trendable, }) => { +export const UsageTooltip = ({ item }: { item: Trendable }) => { return ; }; diff --git a/front/assets/js/billing/index.tsx b/front/assets/js/billing/index.tsx index d5d160beb..1e12ab834 100644 --- a/front/assets/js/billing/index.tsx +++ b/front/assets/js/billing/index.tsx @@ -6,7 +6,7 @@ import { BrowserRouter } from "react-router-dom"; import * as toolbox from "js/toolbox"; import { useSignal } from "@preact/signals"; -export default function ({ config, dom }: { dom: HTMLElement, config: any, }) { +export default function ({ config, dom }: { dom: HTMLElement, config: any }) { const availablePlans = config.availablePlans.map((plan: any) => types.Plans.Plan.fromJSON(plan) ); diff --git a/front/assets/js/billing/pages/classic_spendings_page.tsx b/front/assets/js/billing/pages/classic_spendings_page.tsx index 11184409f..21f940aa9 100644 --- a/front/assets/js/billing/pages/classic_spendings_page.tsx +++ b/front/assets/js/billing/pages/classic_spendings_page.tsx @@ -16,14 +16,15 @@ export const ClassicSpendingsPage = () => { group={state.selectedSpending.getGroup(types.Spendings.GroupType.MachineCapacity)} footer={
    Monthly price for boxes:
    } /> - Spending for artifacts:
    } />
    ); }; -const PlanInfo = ({ spending }: { spending?: types.Spendings.Spending, }) => { +const PlanInfo = ({ spending }: { spending?: types.Spendings.Spending }) => { const config = useContext(stores.Config.Context); if (!spending) { @@ -44,7 +45,11 @@ const PlanInfo = ({ spending }: { spending?: types.Spendings.Spending, }) => {
    {(plan.requiresCreditCard() || (!plan.isTrial() && plan.isFlat()) || (plan.isTrial() && !plan.isFlat())) && showPaymentMethodLink - && + && {noPaymentMethod && `Set credit card ↗`} {!noPaymentMethod && `Update credit card ↗`} } diff --git a/front/assets/js/billing/pages/compact_spendings_page.tsx b/front/assets/js/billing/pages/compact_spendings_page.tsx index ec90942c0..519a0393f 100644 --- a/front/assets/js/billing/pages/compact_spendings_page.tsx +++ b/front/assets/js/billing/pages/compact_spendings_page.tsx @@ -35,7 +35,7 @@ export const CompactSpendingsPage = () => { ); }; -const MachineInfo = ({ spending }: { spending?: types.Spendings.Spending, }) => { +const MachineInfo = ({ spending }: { spending?: types.Spendings.Spending }) => { if (!spending) { return null; } @@ -79,7 +79,11 @@ const MachineInfo = ({ spending }: { spending?: types.Spendings.Spending, }) => } return ( -
    setSortOrder(order)} className="gray pointer" style="user-select: none;"> +
    setSortOrder(order)} + className="gray pointer" + style="user-select: none;" + >
    {displayName} {isAsc && expand_more} @@ -105,12 +109,16 @@ const MachineInfo = ({ spending }: { spending?: types.Spendings.Spending, }) =>
    {sortedItems.length == 0 &&
    No machines available
    } - {sortedItems.map((machine, idx) => )} + {sortedItems.map((machine, idx) => )} ); }; -const MachineItem = ({ machine, lastItem }: { machine: types.Spendings.Item, lastItem?: boolean, }) => { +const MachineItem = ({ machine, lastItem }: { machine: types.Spendings.Item, lastItem?: boolean }) => { return (
    @@ -130,7 +138,7 @@ const MachineItem = ({ machine, lastItem }: { machine: types.Spendings.Item, las ); }; -const PlanInfo = ({ spending }: { spending?: types.Spendings.Spending, }) => { +const PlanInfo = ({ spending }: { spending?: types.Spendings.Spending }) => { if (!spending) { return null; } diff --git a/front/assets/js/billing/pages/overview_page.tsx b/front/assets/js/billing/pages/overview_page.tsx index bfc1be042..3ffd2f708 100644 --- a/front/assets/js/billing/pages/overview_page.tsx +++ b/front/assets/js/billing/pages/overview_page.tsx @@ -4,7 +4,8 @@ import * as stores from "../stores"; import * as components from "../components"; import * as types from "../types"; import $ from "jquery"; -import { Dispatch, StateUpdater, useContext, useEffect, useLayoutEffect, useState } from "preact/hooks"; +import type { Dispatch, StateUpdater } from "preact/hooks"; +import { useContext, useEffect, useLayoutEffect, useState } from "preact/hooks"; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore import { Notice } from "js/notice"; @@ -64,7 +65,7 @@ export const OverviewPage = () => { ); }; -const PlanOverview = ({ plan }: { plan: types.Spendings.Plan, }) => { +const PlanOverview = ({ plan }: { plan: types.Spendings.Plan }) => { return (
    @@ -104,7 +105,7 @@ enum PaymentDetailModes { EditCreditCard, } -const Payments = ({ plan }: { plan: types.Spendings.Plan, }) => { +const Payments = ({ plan }: { plan: types.Spendings.Plan }) => { const [mode, setMode] = useState(PaymentDetailModes.Display); const [budget, setBudget] = useState(new types.Spendings.Budget()); const config = useContext(stores.Config.Context); @@ -131,14 +132,26 @@ const Payments = ({ plan }: { plan: types.Spendings.Plan, }) => { return (
    - {isPrepaid && mode === PaymentDetailModes.Display && } - {!isPrepaid && mode === PaymentDetailModes.Display && } - {mode === PaymentDetailModes.EditBudget && } + {isPrepaid && mode === PaymentDetailModes.Display && } + {!isPrepaid && mode === PaymentDetailModes.Display && } + {mode === PaymentDetailModes.EditBudget && }
    ); }; -const PrepaidSummary = ({ summary }: { summary: types.Spendings.Summary, }) => { +const PrepaidSummary = ({ summary }: { summary: types.Spendings.Summary }) => { return (
    @@ -173,7 +186,7 @@ const PrepaidSummary = ({ summary }: { summary: types.Spendings.Summary, }) => { ); }; -const Summary = ({ plan, summary }: { summary: types.Spendings.Summary, plan: types.Spendings.Plan, }) => { +const Summary = ({ plan, summary }: { summary: types.Spendings.Summary, plan: types.Spendings.Plan }) => { const showSummaryHelp = summary.hasSubscription() || plan.isTrial(); const WithCreditsTooltip = () => { @@ -240,7 +253,11 @@ const Summary = ({ plan, summary }: { summary: types.Spendings.Summary, plan: ty
    - void setMode(PaymentDetailModes.Display)}> @@ -480,7 +505,11 @@ const PaymentDetails = ({ return ( {showLink && ( - + {withoutPaymentMethod && `Set ↗`} {!withoutPaymentMethod && `Update ↗`} @@ -633,7 +662,7 @@ const PrepaidPaymentDetails = ({ ); }; -const TotalSpendings = ({ summary }: { summary: types.Spendings.Summary, }) => { +const TotalSpendings = ({ summary }: { summary: types.Spendings.Summary }) => { return (
    @@ -654,7 +683,7 @@ const TotalSpendings = ({ summary }: { summary: types.Spendings.Summary, }) => { ); }; -const TotalSpendingsDiscounted = ({ summary }: { summary: types.Spendings.Summary, }) => { +const TotalSpendingsDiscounted = ({ summary }: { summary: types.Spendings.Summary }) => { return (
    @@ -668,7 +697,11 @@ const TotalSpendingsDiscounted = ({ summary }: { summary: types.Spendings.Summar
    @@ -420,14 +446,20 @@ const DisruptionDetails = ({ selectedBranch }: DisruptionDetailsProps) => { dispatchRequest({ type: `FETCH` }); }; - const DisruptionOccurence = ({ item }: { item: types.Tests.DisruptionOccurence, }) => { + const DisruptionOccurence = ({ item }: { item: types.Tests.DisruptionOccurence }) => { const humanizedDate = moment(item.timestamp).from(moment()); return (
    fork_right {item.context} commit - {item.workflowName} + {item.workflowName} · {humanizedDate}, by {item.requester}
    ); @@ -485,7 +517,13 @@ const DisruptionHistory = () => { />
    - + ); }; diff --git a/front/assets/js/flaky_tests/pages/flaky_tests_page.tsx b/front/assets/js/flaky_tests/pages/flaky_tests_page.tsx index 8813d1019..8363e2b57 100644 --- a/front/assets/js/flaky_tests/pages/flaky_tests_page.tsx +++ b/front/assets/js/flaky_tests/pages/flaky_tests_page.tsx @@ -8,7 +8,8 @@ import { Notice } from "js/notice"; import * as components from "../components"; import { RequestStatus, Status } from "../types"; import { FetchData } from "../network/request"; -import { FlakyTestItem, HistoryItem } from "../types/flaky_test_item"; +import type { HistoryItem } from "../types/flaky_test_item"; +import { FlakyTestItem } from "../types/flaky_test_item"; import tippy from "tippy.js"; import { useSearchParams } from "react-router-dom"; diff --git a/front/assets/js/flaky_tests/stores/config.ts b/front/assets/js/flaky_tests/stores/config.ts index 1a192a092..76ad90acf 100644 --- a/front/assets/js/flaky_tests/stores/config.ts +++ b/front/assets/js/flaky_tests/stores/config.ts @@ -25,5 +25,5 @@ export const Context = createContext({ removeFilterURL: ``, createFilterURL: ``, updateFilterURL: ``, - webhookSettingsURL: `` + webhookSettingsURL: ``, }); diff --git a/front/assets/js/flaky_tests/stores/filter.ts b/front/assets/js/flaky_tests/stores/filter.ts index 035c73294..bc85131f9 100644 --- a/front/assets/js/flaky_tests/stores/filter.ts +++ b/front/assets/js/flaky_tests/stores/filter.ts @@ -1,14 +1,14 @@ import { createContext } from "preact"; -import * as tests from "../types/tests"; +import type * as tests from "../types/tests"; import moment from "moment"; export type Action = - | { type: `SET_QUERY`, value: string, } - | { type: `SET_FILTERS`, value: tests.Filter[], } - | { type: `SET_CURRENT_FILTER`, value: tests.Filter, } - | { type: `DELETE_FILTER`, value: string, } - | { type: `CREATE_FILTER`, value: tests.Filter, } - | { type: `UPDATE_FILTER`, value: tests.Filter, } + | { type: `SET_QUERY`, value: string } + | { type: `SET_FILTERS`, value: tests.Filter[] } + | { type: `SET_CURRENT_FILTER`, value: tests.Filter } + | { type: `DELETE_FILTER`, value: string } + | { type: `CREATE_FILTER`, value: tests.Filter } + | { type: `UPDATE_FILTER`, value: tests.Filter } ; export interface State { @@ -30,14 +30,14 @@ const builtInFilters: tests.Filter[] = [ id: `1`, name: `Current month`, value: monthFilter(moment().toDate()), - readOnly: true + readOnly: true, }, { id: `2`, name: `Previous month`, value: monthFilter(moment().subtract(1, `month`).toDate()), - readOnly: true - } + readOnly: true, + }, ]; export const Reducer = (state: State, action: Action): State => { @@ -56,14 +56,14 @@ export const Reducer = (state: State, action: Action): State => { return { ...state, currentFilter: action.value, - query: action.value.value + query: action.value.value, }; case `DELETE_FILTER`: return { ...state, filters: state.filters.filter((filter) => filter.id !== action.value), currentFilter: null, - query: `` + query: ``, }; case `CREATE_FILTER`: @@ -71,7 +71,7 @@ export const Reducer = (state: State, action: Action): State => { ...state, filters: [...state.filters, action.value], currentFilter: action.value, - query: action.value.value + query: action.value.value, }; case `UPDATE_FILTER`: @@ -84,14 +84,14 @@ export const Reducer = (state: State, action: Action): State => { return filter; }), currentFilter: action.value, - query: action.value.value + query: action.value.value, }; } }; export const EmptyState: State = { filters: builtInFilters, - query: `` + query: ``, }; -export const Context = createContext<{ state: State, dispatch: (a: Action) => void, }>({ state: EmptyState, dispatch: () => undefined }); +export const Context = createContext<{ state: State, dispatch: (a: Action) => void }>({ state: EmptyState, dispatch: () => undefined }); diff --git a/front/assets/js/flaky_tests/stores/flaky_test.ts b/front/assets/js/flaky_tests/stores/flaky_test.ts index d360c59a6..6dc1a6ab7 100644 --- a/front/assets/js/flaky_tests/stores/flaky_test.ts +++ b/front/assets/js/flaky_tests/stores/flaky_test.ts @@ -1,27 +1,27 @@ -import { HistoryItem, FlakyTestItem } from "../types/flaky_test_item"; +import type { HistoryItem, FlakyTestItem } from "../types/flaky_test_item"; import { Status } from "../types"; import { createContext } from "preact"; -import { FlakyTestsFilter } from "../types/flaky_tests_filter"; -import { StateUpdater } from "preact/hooks"; +import type { FlakyTestsFilter } from "../types/flaky_tests_filter"; +import type { StateUpdater } from "preact/hooks"; export type Action = - | { type: `SET_FLAKY_URL`, value: string, } - | { type: `SET_FLAKY`, value: FlakyTestItem[], } - | { type: `SET_STATUS`, status: Status, } - | { type: `SET_DISRUPTION_HISTORY`, value: HistoryItem[], } - | { type: `SET_DISRUPTION_CHART_STATUS`, status: Status, } - | { type: `SET_FLAKY_HISTORY`, value: HistoryItem[], } - | { type: `SET_FLAKY_CHART_STATUS`, status: Status, } - | { type: `SET_FLAKY_COUNT`, value: number, } - | { type: `SET_SORT_ORDER`, value: string[], } - | { type: `SET_SEARCH_FILTER`, value: string, } - | { type: `SET_FLAKY_FILTER_LIST`, value: FlakyTestsFilter[], } - | { type: `SET_FILTER_STATUS`, status: Status, } - | { type: `DELETE_FILTER`, value: FlakyTestsFilter, } - | { type: `CREATE_FILTER`, value: FlakyTestsFilter, } - | { type: `UPDATE_FILTER`, value: FlakyTestsFilter[], } - | { type: `LOAD_PAGE`, page: number, } - | { type: `SET_TOTAL_PAGES`, value: number, } + | { type: `SET_FLAKY_URL`, value: string } + | { type: `SET_FLAKY`, value: FlakyTestItem[] } + | { type: `SET_STATUS`, status: Status } + | { type: `SET_DISRUPTION_HISTORY`, value: HistoryItem[] } + | { type: `SET_DISRUPTION_CHART_STATUS`, status: Status } + | { type: `SET_FLAKY_HISTORY`, value: HistoryItem[] } + | { type: `SET_FLAKY_CHART_STATUS`, status: Status } + | { type: `SET_FLAKY_COUNT`, value: number } + | { type: `SET_SORT_ORDER`, value: string[] } + | { type: `SET_SEARCH_FILTER`, value: string } + | { type: `SET_FLAKY_FILTER_LIST`, value: FlakyTestsFilter[] } + | { type: `SET_FILTER_STATUS`, status: Status } + | { type: `DELETE_FILTER`, value: FlakyTestsFilter } + | { type: `CREATE_FILTER`, value: FlakyTestsFilter } + | { type: `UPDATE_FILTER`, value: FlakyTestsFilter[] } + | { type: `LOAD_PAGE`, page: number } + | { type: `SET_TOTAL_PAGES`, value: number } ; export interface State { @@ -164,4 +164,4 @@ export const EmptyState: State = { totalPages: 1, }; -export const Context = createContext<{ state: State, dispatch: (a: Action) => void, query: string, setQuery: StateUpdater, }>({ state: EmptyState, dispatch: () => undefined, query: ``, setQuery: () => undefined }); +export const Context = createContext<{ state: State, dispatch: (a: Action) => void, query: string, setQuery: StateUpdater }>({ state: EmptyState, dispatch: () => undefined, query: ``, setQuery: () => undefined }); diff --git a/front/assets/js/flaky_tests/stores/flaky_test_detail.ts b/front/assets/js/flaky_tests/stores/flaky_test_detail.ts index 3f891d1df..d4f9c0622 100644 --- a/front/assets/js/flaky_tests/stores/flaky_test_detail.ts +++ b/front/assets/js/flaky_tests/stores/flaky_test_detail.ts @@ -1,8 +1,8 @@ import { createContext } from "preact"; -import { Tests } from "../types"; +import type { Tests } from "../types"; export type Action = - | { type: `SET_TEST`, value: Tests.FlakyDetail, } + | { type: `SET_TEST`, value: Tests.FlakyDetail } ; export interface State { @@ -22,4 +22,4 @@ export const EmptyState: State = { test: null, }; -export const Context = createContext<{ state: State, dispatch: (a: Action) => void, }>({ state: EmptyState, dispatch: () => undefined }); +export const Context = createContext<{ state: State, dispatch: (a: Action) => void }>({ state: EmptyState, dispatch: () => undefined }); diff --git a/front/assets/js/flaky_tests/stores/request.ts b/front/assets/js/flaky_tests/stores/request.ts index 6670051d9..2001b38fe 100644 --- a/front/assets/js/flaky_tests/stores/request.ts +++ b/front/assets/js/flaky_tests/stores/request.ts @@ -2,12 +2,12 @@ import { createContext } from "preact"; import * as types from "../types"; export type Action = - | { type: `SET_STATUS`, value: types.RequestStatus, } - | { type: `SET_PARAM`, name: string, value: string, } - | { type: `SET_BODY`, value: string, } - | { type: `SET_METHOD`, value: string, } - | { type: `FETCH`, } - | { type: `CLEAR_PARAMS`, }; + | { type: `SET_STATUS`, value: types.RequestStatus } + | { type: `SET_PARAM`, name: string, value: string } + | { type: `SET_BODY`, value: string } + | { type: `SET_METHOD`, value: string } + | { type: `FETCH` } + | { type: `CLEAR_PARAMS` }; export interface State { url: URL; diff --git a/front/assets/js/flaky_tests/types/index.ts b/front/assets/js/flaky_tests/types/index.ts index debd7e11d..45419c91a 100644 --- a/front/assets/js/flaky_tests/types/index.ts +++ b/front/assets/js/flaky_tests/types/index.ts @@ -7,5 +7,5 @@ export { FlakyTestItem, Status, RequestStatus, - Tests + Tests, }; diff --git a/front/assets/js/get_started/index.tsx b/front/assets/js/get_started/index.tsx index 2de344098..001aef10e 100644 --- a/front/assets/js/get_started/index.tsx +++ b/front/assets/js/get_started/index.tsx @@ -4,7 +4,7 @@ import { App } from "./app"; import * as stores from "./stores"; import { BrowserRouter } from "react-router-dom"; -export default function ({ dom, config }: { dom: HTMLElement, config: any, }) { +export default function ({ dom, config }: { dom: HTMLElement, config: any }) { render( diff --git a/front/assets/js/get_started/pages/onboarding_page.tsx b/front/assets/js/get_started/pages/onboarding_page.tsx index 1a617a482..bc12fe2e9 100644 --- a/front/assets/js/get_started/pages/onboarding_page.tsx +++ b/front/assets/js/get_started/pages/onboarding_page.tsx @@ -110,7 +110,7 @@ export const OnboardingPage = () => { ); }; -const Bullet = styled.div<{ $completed?: boolean, }>` +const Bullet = styled.div<{ $completed?: boolean }>` text-align: center; position: relative; color: gray; diff --git a/front/assets/js/get_started/stores/onboarding.tsx b/front/assets/js/get_started/stores/onboarding.tsx index db6e1c39d..1a2b66be2 100644 --- a/front/assets/js/get_started/stores/onboarding.tsx +++ b/front/assets/js/get_started/stores/onboarding.tsx @@ -2,8 +2,8 @@ import { createContext } from "preact"; import * as types from "../types"; export type Action = - | { type: `SET_LEARN`, value: types.Onboarding.Learn, } - | { type: `SELECT_TASK`, value: string, }; + | { type: `SET_LEARN`, value: types.Onboarding.Learn } + | { type: `SELECT_TASK`, value: string }; export interface State { currentTask?: types.Onboarding.Task; diff --git a/front/assets/js/git_integration/components/box.tsx b/front/assets/js/git_integration/components/box.tsx index 8fb7f9b7f..ced67e722 100644 --- a/front/assets/js/git_integration/components/box.tsx +++ b/front/assets/js/git_integration/components/box.tsx @@ -1,4 +1,4 @@ -import { JSX, VNode } from "preact"; +import type { JSX, VNode } from "preact"; interface BoxProps { boxIcon: JSX.Element; diff --git a/front/assets/js/git_integration/components/card.tsx b/front/assets/js/git_integration/components/card.tsx index c180b4355..30e695607 100644 --- a/front/assets/js/git_integration/components/card.tsx +++ b/front/assets/js/git_integration/components/card.tsx @@ -1,5 +1,5 @@ -import { JSX } from "preact"; -import * as types from "../types"; +import type { JSX } from "preact"; +import type * as types from "../types"; import { NavLink } from "react-router-dom"; import { IntegrationStarter } from "./integration_starter"; import { getProviderIcon } from "../../project_onboarding/new/utils/provider"; diff --git a/front/assets/js/git_integration/components/connection_status.tsx b/front/assets/js/git_integration/components/connection_status.tsx index 1730b7a0a..8adb12f63 100644 --- a/front/assets/js/git_integration/components/connection_status.tsx +++ b/front/assets/js/git_integration/components/connection_status.tsx @@ -24,7 +24,13 @@ const connectionOkSvg = ( xmlns="http://www.w3.org/2000/svg" > - + { const [isEditing, setIsEditing] = useState(false); const [inputValue, setInputValue] = useState(value); diff --git a/front/assets/js/git_integration/components/lock_icon.tsx b/front/assets/js/git_integration/components/lock_icon.tsx index cb191d5fc..7a84c086d 100644 --- a/front/assets/js/git_integration/components/lock_icon.tsx +++ b/front/assets/js/git_integration/components/lock_icon.tsx @@ -1,10 +1,18 @@ -import { JSX } from "preact"; +import type { JSX } from "preact"; export const LockIcon: () => JSX.Element = () => { return ( - + - + diff --git a/front/assets/js/git_integration/components/permissions_field.tsx b/front/assets/js/git_integration/components/permissions_field.tsx index 0888904cb..6d7f387fc 100644 --- a/front/assets/js/git_integration/components/permissions_field.tsx +++ b/front/assets/js/git_integration/components/permissions_field.tsx @@ -29,7 +29,11 @@ export const PermissionsField = ({ permissions, checkboxPermissions = false }: P
      {permissionsList.map((permission, index) => ( -
    • +
    • {permission.name} {!checkboxPermissions && permission.level && ( diff --git a/front/assets/js/git_integration/index.tsx b/front/assets/js/git_integration/index.tsx index 05d4dd5b8..a676ff849 100644 --- a/front/assets/js/git_integration/index.tsx +++ b/front/assets/js/git_integration/index.tsx @@ -3,7 +3,7 @@ import { App } from "./app"; import * as stores from "./stores"; import { BrowserRouter } from "react-router-dom"; -export default function ({ config, dom }: { dom: HTMLElement, config: any, }) { +export default function ({ config, dom }: { dom: HTMLElement, config: any }) { render( diff --git a/front/assets/js/git_integration/pages/home_page.tsx b/front/assets/js/git_integration/pages/home_page.tsx index ab17ff011..344467eea 100644 --- a/front/assets/js/git_integration/pages/home_page.tsx +++ b/front/assets/js/git_integration/pages/home_page.tsx @@ -4,7 +4,7 @@ import { Box, Card } from "../components"; import { useContext } from "preact/hooks"; import * as stores from "../stores"; import { gitSvg, addNewIcon } from "./home_page/icons"; -import { State } from "../stores/config"; +import type { State } from "../stores/config"; import { Integration } from "../types"; import * as utils from "../utils"; diff --git a/front/assets/js/git_integration/pages/index.ts b/front/assets/js/git_integration/pages/index.ts index d120b7156..b7d1641a3 100644 --- a/front/assets/js/git_integration/pages/index.ts +++ b/front/assets/js/git_integration/pages/index.ts @@ -3,5 +3,5 @@ import { HomePage } from './home_page'; export { HomePage, - IntegrationPage + IntegrationPage, }; diff --git a/front/assets/js/git_integration/pages/integration_page.tsx b/front/assets/js/git_integration/pages/integration_page.tsx index 573ac952a..999b2f7f7 100644 --- a/front/assets/js/git_integration/pages/integration_page.tsx +++ b/front/assets/js/git_integration/pages/integration_page.tsx @@ -51,9 +51,17 @@ export const IntegrationPage = () => { case types.Integration.IntegrationType.GithubApp: return ; case types.Integration.IntegrationType.Gitlab: - return ; + return ; case types.Integration.IntegrationType.BitBucket: - return ; + return ; default: return ( diff --git a/front/assets/js/git_integration/pages/integration_page/bitbucket.tsx b/front/assets/js/git_integration/pages/integration_page/bitbucket.tsx index 59bbb485a..557977f62 100644 --- a/front/assets/js/git_integration/pages/integration_page/bitbucket.tsx +++ b/front/assets/js/git_integration/pages/integration_page/bitbucket.tsx @@ -3,7 +3,7 @@ import { useContext } from "preact/hooks"; import { NavLink } from "react-router-dom"; import { useState } from "preact/hooks"; import * as components from "../../components"; -import * as types from "../../types"; +import type * as types from "../../types"; import * as stores from "../../stores"; interface Props { @@ -101,8 +101,16 @@ export const BitbucketIntegration = ({ integration, csrfToken, orgUsername }: Pr method="post" action={integration.deleteUrl} > - - + + { +const EditFields = ({ integration }: { integration: types.Integration.BitbucketIntegration }) => { const [clientId, setClientId] = useState(``); const [clientSecret, setClientSecret] = useState(``); const config = useContext(stores.Config.Context); @@ -141,9 +149,21 @@ const EditFields = ({ integration }: { integration: types.Integration.BitbucketI action={integration.connectUrl} className="mb3" > - - - + + +
      @@ -197,7 +217,7 @@ const EditFields = ({ integration }: { integration: types.Integration.BitbucketI ); }; -const CopyFields = ({ integration }: { integration: types.Integration.BitbucketIntegration, }) => { +const CopyFields = ({ integration }: { integration: types.Integration.BitbucketIntegration }) => { const manifest = integration.manifest as { permissions: string; redirect_urls: string; diff --git a/front/assets/js/git_integration/pages/integration_page/github.tsx b/front/assets/js/git_integration/pages/integration_page/github.tsx index 5071008c6..0cec6b21a 100644 --- a/front/assets/js/git_integration/pages/integration_page/github.tsx +++ b/front/assets/js/git_integration/pages/integration_page/github.tsx @@ -2,7 +2,7 @@ import { Fragment } from "preact"; import { NavLink } from "react-router-dom"; import { useState } from "preact/hooks"; import * as components from "../../components"; -import * as types from "../../types"; +import type * as types from "../../types"; interface Props { integration: types.Integration.GithubIntegration; @@ -41,7 +41,11 @@ export const GithubIntegration = ({ integration, csrfToken }: Props) => { to ensure a working connection.

      - + Configure GitHub App Settings ↗ @@ -88,8 +92,16 @@ export const GithubIntegration = ({ integration, csrfToken }: Props) => { method="post" action={integration.deleteUrl} > - - + + { ); }; -const EditFields = ({ integration }: { integration: types.Integration.GithubIntegration, }) => { +const EditFields = ({ integration }: { integration: types.Integration.GithubIntegration }) => { return ( { +const CopyFields = ({ integration }: { integration: types.Integration.GithubIntegration }) => { const manifest = integration.manifest as { callback_urls: string; setup_url: string; diff --git a/front/assets/js/git_integration/pages/integration_page/gitlab.tsx b/front/assets/js/git_integration/pages/integration_page/gitlab.tsx index 0d9f05458..a61057126 100644 --- a/front/assets/js/git_integration/pages/integration_page/gitlab.tsx +++ b/front/assets/js/git_integration/pages/integration_page/gitlab.tsx @@ -3,7 +3,7 @@ import { useContext } from "preact/hooks"; import { NavLink } from "react-router-dom"; import { useState } from "preact/hooks"; import * as components from "../../components"; -import * as types from "../../types"; +import type * as types from "../../types"; import * as stores from "../../stores"; import * as utils from "../../utils"; @@ -99,8 +99,16 @@ export const GitlabIntegration = ({ integration, csrfToken, orgUsername }: Props method="post" action={integration.deleteUrl} > - - + + { +const EditFields = ({ integration }: { integration: types.Integration.GitlabIntegration }) => { const [clientId, setClientId] = useState(``); const [clientSecret, setClientSecret] = useState(``); const config = useContext(stores.Config.Context); @@ -139,9 +147,21 @@ const EditFields = ({ integration }: { integration: types.Integration.GitlabInte action={integration.connectUrl} className="mb3" > - - - + + +
      @@ -206,7 +226,7 @@ const manifestPermissionsOrder = [ const permissionsOrderMap = utils.createOrderMap(manifestPermissionsOrder); -const CopyFields = ({ integration }: { integration: types.Integration.GitlabIntegration, }) => { +const CopyFields = ({ integration }: { integration: types.Integration.GitlabIntegration }) => { const manifest = integration.manifest as { permissions: string; redirect_urls: string; diff --git a/front/assets/js/git_integration/stores/config.ts b/front/assets/js/git_integration/stores/config.ts index c51a1e174..6cadb77b4 100644 --- a/front/assets/js/git_integration/stores/config.ts +++ b/front/assets/js/git_integration/stores/config.ts @@ -1,5 +1,5 @@ import { createContext } from "preact"; -import { Integration } from "../types"; +import type { Integration } from "../types"; export interface State { baseUrl: string; @@ -17,5 +17,5 @@ export const Context = createContext({ orgId: ``, orgUsername: ``, domain: ``, - csrfTokenCookieKey: `githubAppInstallStatusToken` + csrfTokenCookieKey: `githubAppInstallStatusToken`, }); diff --git a/front/assets/js/insights/app.tsx b/front/assets/js/insights/app.tsx index 8788ead14..2ea54b41a 100644 --- a/front/assets/js/insights/app.tsx +++ b/front/assets/js/insights/app.tsx @@ -28,7 +28,7 @@ export const Config = createContext({ availableDatesUrl: ``, }); -export const App = ({ config }: { config: AppConfig, }) => { +export const App = ({ config }: { config: AppConfig }) => { return ( diff --git a/front/assets/js/insights/components/custom_charts/frequency.tsx b/front/assets/js/insights/components/custom_charts/frequency.tsx index e43ea95c2..e8a23f027 100644 --- a/front/assets/js/insights/components/custom_charts/frequency.tsx +++ b/front/assets/js/insights/components/custom_charts/frequency.tsx @@ -20,13 +20,18 @@ export const Frequency = ({ metrics, branchName, pipelineFileName }: Props) => { loadingState={{ loading: false, errors: [] }} metrics={metrics} charts={[ - + , ]} tooltip={} axisY={} focus={[ , - + , ]} xDomainFrom={moment(dateRangeState.selectedMetricDateRange.from).toDate()} xDomainTo={moment(dateRangeState.selectedMetricDateRange.to).toDate()} @@ -34,14 +39,23 @@ export const Frequency = ({ metrics, branchName, pipelineFileName }: Props) => {
      {/*this icon needs to be loaded dynamically */} - branch icon + branch icon {/*this icon needs to be loaded dynamically */} - pipeline icon + width="16" + height="16" + alt="pipeline icon" + />
      diff --git a/front/assets/js/insights/components/custom_charts/index.ts b/front/assets/js/insights/components/custom_charts/index.ts index 6ad522a34..f67976597 100644 --- a/front/assets/js/insights/components/custom_charts/index.ts +++ b/front/assets/js/insights/components/custom_charts/index.ts @@ -6,5 +6,5 @@ import { Reliability } from './reliability'; export { Performance, Frequency, - Reliability + Reliability, }; \ No newline at end of file diff --git a/front/assets/js/insights/components/custom_charts/performance.tsx b/front/assets/js/insights/components/custom_charts/performance.tsx index a4965a12d..7e46d159c 100644 --- a/front/assets/js/insights/components/custom_charts/performance.tsx +++ b/front/assets/js/insights/components/custom_charts/performance.tsx @@ -1,8 +1,9 @@ import * as plot from '../plot'; -import { cloneElement, Fragment, VNode } from 'preact'; +import type { VNode } from 'preact'; +import { cloneElement, Fragment } from 'preact'; import { useContext, useState } from "preact/hooks"; import { useSearchParams } from "react-router-dom"; -import { DashboardItem } from "../../types/dashboard"; +import type { DashboardItem } from "../../types/dashboard"; import * as stores from "../../stores"; import moment from "moment"; @@ -41,15 +42,19 @@ export const Performance = ({ metrics, item }: Props) => { metrics={metrics} charts={[ showChart(`duration`) ? : , - showChart(`stdDev`) ? : + showChart(`stdDev`) ? : , - showChart(`mean`) ? : + showChart(`mean`) ? : , ]} tooltip={} axisY={} focus={[ , - + , ]} xDomainFrom={moment(dateRangeState.selectedMetricDateRange.from).toDate()} xDomainTo={moment(dateRangeState.selectedMetricDateRange.to).toDate()} @@ -57,14 +62,23 @@ export const Performance = ({ metrics, item }: Props) => {
      {/*this icon needs to be loaded dynamically */} - branch icon + branch icon {/*this icon needs to be loaded dynamically */} - pipeline icon + width="16" + height="16" + alt="pipeline icon" + />
      @@ -95,8 +109,8 @@ export const Performance = ({ metrics, item }: Props) => { const Legend = ({ icon, label, - isActive -}: { icon: VNode, label: VNode, isActive: boolean, }) => { + isActive, +}: { icon: VNode, label: VNode, isActive: boolean }) => { let className = `o-30`; if (isActive) { className = ``; diff --git a/front/assets/js/insights/components/custom_charts/reliability.tsx b/front/assets/js/insights/components/custom_charts/reliability.tsx index 7e3801f94..cb8350ed7 100644 --- a/front/assets/js/insights/components/custom_charts/reliability.tsx +++ b/front/assets/js/insights/components/custom_charts/reliability.tsx @@ -22,11 +22,16 @@ export const Reliability = ({ metrics, branchName, pipelineFileName }: Props) => axisY={} tooltip={} charts={[ - + , ]} focus={[ , - + , ]} xDomainFrom={moment(dateRangeState.selectedMetricDateRange.from).toDate()} xDomainTo={moment(dateRangeState.selectedMetricDateRange.to).toDate()} @@ -34,14 +39,23 @@ export const Reliability = ({ metrics, branchName, pipelineFileName }: Props) =>
      {/*this icon needs to be loaded dynamically */} - branch icon + branch icon {/*this icon needs to be loaded dynamically */} - pipeline icon + width="16" + height="16" + alt="pipeline icon" + />
      diff --git a/front/assets/js/insights/components/custom_dashboards.tsx b/front/assets/js/insights/components/custom_dashboards.tsx index 1c2522d1e..a05ebe203 100644 --- a/front/assets/js/insights/components/custom_dashboards.tsx +++ b/front/assets/js/insights/components/custom_dashboards.tsx @@ -1,14 +1,14 @@ import { useNavigate, useParams } from 'react-router-dom'; import { useContext, useLayoutEffect, useState } from 'preact/hooks'; -import { Dashboard, DashboardItem } from '../types/dashboard'; +import type { Dashboard, DashboardItem } from '../types/dashboard'; import { DashboardItemForm } from './forms/dashboard_item_form'; import * as types from '../types'; import * as util from '../util'; import { useToggle } from '../util'; -import { CreateDashboardItem } from '../types/json_interface'; +import type { CreateDashboardItem } from '../types/json_interface'; import { Config } from '../app'; -import { State as DState } from '../stores/dashboards'; -import { State as DRState } from '../stores/metric_date_range'; +import type { State as DState } from '../stores/dashboards'; +import type { State as DRState } from '../stores/metric_date_range'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore import { Notice } from '../../notice'; @@ -76,7 +76,7 @@ export const CustomDashboards = ({ state, dispatchDashboard, deleteHandler, rena const response = await fetch(`${url}/${dashboardId}/${id}`, { method: `PUT`, headers: util.Headers(), - body: `name=${name}` + body: `name=${name}`, }); if (response.ok) { @@ -99,7 +99,7 @@ export const CustomDashboards = ({ state, dispatchDashboard, deleteHandler, rena const response = await fetch(`${url}/${dashboardId}/${id}/description`, { method: `PUT`, headers: util.Headers(), - body: `description=${description}` + body: `description=${description}`, }); if (response.ok) { @@ -145,7 +145,7 @@ export const CustomDashboards = ({ state, dispatchDashboard, deleteHandler, rena const response = await fetch(`${url}/${dashboardId}`, { method: `POST`, headers: util.Headers(`application/json`), - body: JSON.stringify(item) + body: JSON.stringify(item), }); const data: CreateDashboardItem = await response.json(); const dashboardItem = types.Dashboard.DashboardItem.fromJSON(data.item); @@ -208,29 +208,42 @@ export const CustomDashboards = ({ state, dispatchDashboard, deleteHandler, rena
      Dashboard name
      - +
      - - + + onClick={hideTippy} + >Cancel
      - + type="reset" + >Delete
      - }> + } + >
      - {dateRangeState.dateRanges.map(d => )} @@ -244,7 +257,8 @@ export const CustomDashboards = ({ state, dispatchDashboard, deleteHandler, rena
      diff --git a/front/assets/js/insights/components/dashboard_item_card.tsx b/front/assets/js/insights/components/dashboard_item_card.tsx index 64348eb27..198e9216b 100644 --- a/front/assets/js/insights/components/dashboard_item_card.tsx +++ b/front/assets/js/insights/components/dashboard_item_card.tsx @@ -1,4 +1,4 @@ -import { DashboardItem } from '../types/dashboard'; +import type { DashboardItem } from '../types/dashboard'; import { InsightsType, typeByMetric } from '../types/insights_type'; import * as customCharts from './custom_charts'; import Tippy from '@tippyjs/react'; @@ -83,39 +83,53 @@ export const DashboardItemCard = ({ item, metrics, renameHandler, deleteHandler,
      Metric name
      - +
      Description
      -