mirror of
https://github.com/moghtech/komodo.git
synced 2026-07-31 20:10:19 -05:00
add build page
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
import { useParams } from "@solidjs/router";
|
||||
import { createContext, createEffect, onCleanup, ParentComponent, useContext } from "solid-js";
|
||||
import { createStore } from "solid-js/store";
|
||||
import { client } from "../..";
|
||||
import { useAppState } from "../../state/StateProvider";
|
||||
import { BuildActionState, Operation, UpdateStatus } from "../../types";
|
||||
|
||||
type State = {
|
||||
|
||||
} & BuildActionState;
|
||||
|
||||
const context = createContext<State>();
|
||||
|
||||
export const ActionStateProvider: ParentComponent<{}> = (p) => {
|
||||
const { ws } = useAppState();
|
||||
const params = useParams();
|
||||
const [actions, setActions] = createStore<BuildActionState>({
|
||||
building: false,
|
||||
recloning: false,
|
||||
updating: false,
|
||||
});
|
||||
createEffect(() => {
|
||||
client.get_build_action_state(params.id).then(setActions);
|
||||
});
|
||||
onCleanup(
|
||||
ws.subscribe([Operation.BuildBuild], (update) => {
|
||||
if (update.target.id === params.id) {
|
||||
setActions("building", update.status !== UpdateStatus.Complete);
|
||||
}
|
||||
})
|
||||
);
|
||||
onCleanup(
|
||||
ws.subscribe([Operation.RecloneBuild], (update) => {
|
||||
if (update.target.id === params.id) {
|
||||
setActions("recloning", update.status !== UpdateStatus.Complete);
|
||||
}
|
||||
})
|
||||
);
|
||||
// onCleanup(
|
||||
// ws.subscribe([DELETE_BUILD], ({ complete, buildID }) => {
|
||||
// if (buildID === selected.id()) {
|
||||
// setActions("deleting", !complete);
|
||||
// }
|
||||
// })
|
||||
// );
|
||||
return (
|
||||
<context.Provider value={actions}>{p.children}</context.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useActionStates() {
|
||||
return useContext(context) as State;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import { Component, Show } from "solid-js";
|
||||
import { useAppState } from "../../state/StateProvider";
|
||||
import { useUser } from "../../state/UserProvider";
|
||||
import ConfirmButton from "../shared/ConfirmButton";
|
||||
import Icon from "../shared/Icon";
|
||||
import Flex from "../shared/layout/Flex";
|
||||
import Grid from "../shared/layout/Grid";
|
||||
import Loading from "../shared/loading/Loading";
|
||||
import { useActionStates } from "./ActionStateProvider";
|
||||
import { client } from "../..";
|
||||
import { combineClasses, getId } from "../../util/helpers";
|
||||
import { useParams } from "@solidjs/router";
|
||||
import { PermissionLevel } from "../../types";
|
||||
|
||||
const Actions: Component<{}> = (p) => {
|
||||
const { user } = useUser();
|
||||
const params = useParams() as { id: string };
|
||||
const { builds, ws } = useAppState();
|
||||
const build = () => builds.get(params.id)!;
|
||||
const actions = useActionStates();
|
||||
const userCanExecute = () =>
|
||||
user().admin ||
|
||||
build().permissions[getId(user())] === PermissionLevel.Execute ||
|
||||
build().permissions[getId(user())] === PermissionLevel.Execute;
|
||||
return (
|
||||
<Show when={userCanExecute()}>
|
||||
<Grid class={combineClasses("card shadow")}>
|
||||
<h1>actions</h1>
|
||||
<Flex class={combineClasses("action shadow")}>
|
||||
build{" "}
|
||||
<Show
|
||||
when={!actions.building}
|
||||
fallback={
|
||||
<button class="green">
|
||||
<Loading type="spinner" />
|
||||
</button>
|
||||
}
|
||||
>
|
||||
<ConfirmButton
|
||||
color="green"
|
||||
onConfirm={() => {
|
||||
client.build(params.id);
|
||||
}}
|
||||
>
|
||||
<Icon type="build" />
|
||||
</ConfirmButton>
|
||||
</Show>
|
||||
</Flex>
|
||||
<Flex class={combineClasses("action shadow")}>
|
||||
reclone{" "}
|
||||
<Show
|
||||
when={!actions.recloning}
|
||||
fallback={
|
||||
<button class="orange">
|
||||
<Loading type="spinner" />
|
||||
</button>
|
||||
}
|
||||
>
|
||||
<ConfirmButton
|
||||
color="orange"
|
||||
onConfirm={() => {
|
||||
client.reclone_build(params.id)
|
||||
}}
|
||||
>
|
||||
<Icon type="reset" />
|
||||
</ConfirmButton>
|
||||
</Show>
|
||||
</Flex>
|
||||
</Grid>
|
||||
</Show>
|
||||
);
|
||||
};
|
||||
|
||||
export default Actions;
|
||||
@@ -1,7 +1,45 @@
|
||||
import { Component } from "solid-js";
|
||||
import { useParams } from "@solidjs/router";
|
||||
import { Component, Show } from "solid-js";
|
||||
import { useAppDimensions } from "../../state/DimensionProvider";
|
||||
import { useAppState } from "../../state/StateProvider";
|
||||
import { useUser } from "../../state/UserProvider";
|
||||
import { PermissionLevel } from "../../types";
|
||||
import { combineClasses, getId } from "../../util/helpers";
|
||||
import NotFound from "../NotFound";
|
||||
import Grid from "../shared/layout/Grid";
|
||||
import Actions from "./Actions";
|
||||
import { ActionStateProvider } from "./ActionStateProvider";
|
||||
import Header from "./Header";
|
||||
import BuildTabs from "./tabs/Tabs";
|
||||
import Updates from "./Updates";
|
||||
|
||||
const Build: Component<{}> = (p) => {
|
||||
return <div></div>;
|
||||
const { builds } = useAppState();
|
||||
const params = useParams();
|
||||
const build = () => builds.get(params.id)!;
|
||||
const { isSemiMobile } = useAppDimensions();
|
||||
const { user } = useUser();
|
||||
const userCanUpdate = () =>
|
||||
user().admin ||
|
||||
build().permissions[getId(user())] === PermissionLevel.Update;
|
||||
return (
|
||||
<Show when={build()} fallback={<NotFound type="build" />}>
|
||||
<ActionStateProvider>
|
||||
<Grid class={combineClasses("content")}>
|
||||
{/* left / actions */}
|
||||
<Grid class="left-content">
|
||||
<Header />
|
||||
<Actions />
|
||||
<Show when={!isSemiMobile() && userCanUpdate()}>
|
||||
<Updates />
|
||||
</Show>
|
||||
</Grid>
|
||||
{/* right / tabs */}
|
||||
<BuildTabs />
|
||||
</Grid>
|
||||
</ActionStateProvider>
|
||||
</Show>
|
||||
);
|
||||
};
|
||||
|
||||
export default Build;
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import { Component, Show } from "solid-js";
|
||||
import { useAppState } from "../../state/StateProvider";
|
||||
import { useUser } from "../../state/UserProvider";
|
||||
import ConfirmButton from "../shared/ConfirmButton";
|
||||
import Icon from "../shared/Icon";
|
||||
import Flex from "../shared/layout/Flex";
|
||||
import Grid from "../shared/layout/Grid";
|
||||
import { useActionStates } from "./ActionStateProvider";
|
||||
import { combineClasses, getId } from "../../util/helpers";
|
||||
import { useAppDimensions } from "../../state/DimensionProvider";
|
||||
import Updates from "./Updates";
|
||||
import { useLocalStorageToggle } from "../../util/hooks";
|
||||
import { useParams } from "@solidjs/router";
|
||||
import { PermissionLevel } from "../../types";
|
||||
import { client } from "../..";
|
||||
|
||||
const Header: Component<{}> = (p) => {
|
||||
const { builds, ws } = useAppState();
|
||||
const params = useParams();
|
||||
const build = () => builds.get(params.id)!;
|
||||
const actions = useActionStates();
|
||||
const { user } = useUser();
|
||||
const { isMobile } = useAppDimensions();
|
||||
const [showUpdates, toggleShowUpdates] =
|
||||
useLocalStorageToggle("show-updates");
|
||||
const userCanUpdate = () =>
|
||||
user().admin ||
|
||||
build().permissions[getId(user())] === PermissionLevel.Update;
|
||||
return (
|
||||
<>
|
||||
<Flex
|
||||
class={combineClasses("card shadow")}
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
style={{
|
||||
position: "relative",
|
||||
cursor: isMobile() && userCanUpdate() ? "pointer" : undefined,
|
||||
}}
|
||||
onClick={() => {
|
||||
if (isMobile() && userCanUpdate()) toggleShowUpdates();
|
||||
}}
|
||||
>
|
||||
<Grid gap="0.1rem">
|
||||
<h1>{build().name}</h1>
|
||||
<div style={{ opacity: 0.8 }}>build</div>
|
||||
</Grid>
|
||||
<Show when={userCanUpdate()}>
|
||||
<ConfirmButton
|
||||
onConfirm={() => {
|
||||
client.delete_build(params.id);
|
||||
}}
|
||||
color="red"
|
||||
>
|
||||
<Icon type="trash" />
|
||||
</ConfirmButton>
|
||||
</Show>
|
||||
<Show when={isMobile() && userCanUpdate()}>
|
||||
<Flex gap="0.5rem" alignItems="center" class="show-updates-indicator">
|
||||
updates{" "}
|
||||
<Icon
|
||||
type={showUpdates() ? "chevron-up" : "chevron-down"}
|
||||
width="0.9rem"
|
||||
/>
|
||||
</Flex>
|
||||
</Show>
|
||||
</Flex>
|
||||
<Show when={isMobile() && userCanUpdate() && showUpdates()}>
|
||||
<Updates />
|
||||
</Show>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
||||
@@ -0,0 +1,60 @@
|
||||
import { Component, createSignal, For, onCleanup, Show } from "solid-js";
|
||||
import { useArray } from "../../state/hooks";
|
||||
import { useAppState } from "../../state/StateProvider";
|
||||
import Update from "../update/Update";
|
||||
import Grid from "../shared/layout/Grid";
|
||||
import { combineClasses } from "../../util/helpers";
|
||||
import { client } from "../..";
|
||||
import { useParams } from "@solidjs/router";
|
||||
|
||||
const Updates: Component<{}> = (p) => {
|
||||
const { ws } = useAppState();
|
||||
const params = useParams();
|
||||
const selectedUpdates = useArray(() =>
|
||||
client.list_updates(0, { type: "Build", id: params.id })
|
||||
);
|
||||
const unsub = ws.subscribe([], (update) => {
|
||||
if (update.target.id === params.id) {
|
||||
selectedUpdates.add(update);
|
||||
}
|
||||
});
|
||||
onCleanup(unsub);
|
||||
const [noMoreUpdates, setNoMore] = createSignal(false);
|
||||
const loadMore = async () => {
|
||||
const offset = selectedUpdates.collection()?.length;
|
||||
if (offset) {
|
||||
const updates = await client.list_updates(offset, {
|
||||
type: "Build",
|
||||
id: params.id,
|
||||
});
|
||||
selectedUpdates.addManyToEnd(updates);
|
||||
if (updates.length !== 10) {
|
||||
setNoMore(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
return (
|
||||
<Show
|
||||
when={
|
||||
selectedUpdates.loaded() &&
|
||||
(selectedUpdates.collection()?.length || 0) > 0
|
||||
}
|
||||
>
|
||||
<Grid class={combineClasses("card shadow")}>
|
||||
<h1>updates</h1>
|
||||
<Grid class="updates-container scroller">
|
||||
<For each={selectedUpdates.collection()}>
|
||||
{(update) => <Update update={update} />}
|
||||
</For>
|
||||
<Show when={!noMoreUpdates()}>
|
||||
<button class="grey" style={{ width: "100%" }} onClick={loadMore}>
|
||||
load more
|
||||
</button>
|
||||
</Show>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Show>
|
||||
);
|
||||
};
|
||||
|
||||
export default Updates;
|
||||
@@ -0,0 +1,111 @@
|
||||
import { Component, createEffect, createSignal, For, Show } from "solid-js";
|
||||
import { pushNotification } from "../../..";
|
||||
import { useUser } from "../../../state/UserProvider";
|
||||
import { User } from "../../../types";
|
||||
import { combineClasses } from "../../../util/helpers";
|
||||
import ConfirmButton from "../../shared/ConfirmButton";
|
||||
import Input from "../../shared/Input";
|
||||
import Flex from "../../shared/layout/Flex";
|
||||
import Grid from "../../shared/layout/Grid";
|
||||
import Menu from "../../shared/menu/Menu";
|
||||
import { useConfig } from "./Provider";
|
||||
|
||||
const Owners: Component<{}> = (p) => {
|
||||
// const { build } = useConfig();
|
||||
// const { user } = useUser();
|
||||
// const [userSearch, setUserSearch] = createSignal("");
|
||||
// const [users, setUsers] = createSignal<User[]>([]);
|
||||
// createEffect(() => {
|
||||
// if (userSearch().length > 0) {
|
||||
// getUsers(userSearch(), true).then((users) => {
|
||||
// setUsers(users.filter((user) => !build.owners.includes(user.username)));
|
||||
// });
|
||||
// } else {
|
||||
// setUsers([]);
|
||||
// }
|
||||
// });
|
||||
// return (
|
||||
// <Show when={build.loaded}>
|
||||
// <Grid class="config">
|
||||
// <Grid class="config-items scroller" style={{ height: "100%" }}>
|
||||
// <Grid
|
||||
// class={combineClasses("config-item shadow", themeClass())}
|
||||
// gap="0.5rem"
|
||||
// >
|
||||
// <Menu
|
||||
// show={userSearch() ? true : false}
|
||||
// close={() => setUserSearch("")}
|
||||
// target={
|
||||
// <Input
|
||||
// placeholder="add user"
|
||||
// value={userSearch()}
|
||||
// onEdit={setUserSearch}
|
||||
// style={{ width: "12rem" }}
|
||||
// />
|
||||
// }
|
||||
// content={
|
||||
// <>
|
||||
// <For each={users()}>
|
||||
// {(user) => (
|
||||
// <ConfirmButton
|
||||
// color="grey"
|
||||
// style={{
|
||||
// width: "100%",
|
||||
// "justify-content": "flex-start",
|
||||
// }}
|
||||
// onConfirm={async () => {
|
||||
// await addOwnerToBuild(build._id!, user.username);
|
||||
// pushNotification("good", "owner added to build");
|
||||
// setUserSearch("");
|
||||
// }}
|
||||
// confirm="add user"
|
||||
// >
|
||||
// {user.username}
|
||||
// </ConfirmButton>
|
||||
// )}
|
||||
// </For>
|
||||
// <Show when={users().length === 0}>no matching users</Show>
|
||||
// </>
|
||||
// }
|
||||
// menuStyle={{ width: "12rem" }}
|
||||
// />
|
||||
// <For each={build.owners}>
|
||||
// {(owner) => (
|
||||
// <Flex
|
||||
// alignItems="center"
|
||||
// justifyContent="space-between"
|
||||
// class={combineClasses("grey-no-hover", themeClass())}
|
||||
// style={{
|
||||
// padding: "0.5rem",
|
||||
// }}
|
||||
// >
|
||||
// <div class="big-text">
|
||||
// {owner}
|
||||
// {owner === username() && " ( you )"}
|
||||
// </div>
|
||||
// <Show when={permissions() > 1}>
|
||||
// <ConfirmButton
|
||||
// color="red"
|
||||
// onConfirm={async () => {
|
||||
// await removeOwnerFromBuild(build._id!, owner);
|
||||
// pushNotification(
|
||||
// "good",
|
||||
// "user removed from collaborators"
|
||||
// );
|
||||
// }}
|
||||
// >
|
||||
// remove
|
||||
// </ConfirmButton>
|
||||
// </Show>
|
||||
// </Flex>
|
||||
// )}
|
||||
// </For>
|
||||
// </Grid>
|
||||
// </Grid>
|
||||
// </Grid>
|
||||
// </Show>
|
||||
// );
|
||||
return <div></div>
|
||||
};
|
||||
|
||||
export default Owners;
|
||||
@@ -0,0 +1,107 @@
|
||||
import { useParams } from "@solidjs/router";
|
||||
import {
|
||||
createContext,
|
||||
createEffect,
|
||||
onCleanup,
|
||||
ParentComponent,
|
||||
useContext,
|
||||
} from "solid-js";
|
||||
import { createStore, SetStoreFunction } from "solid-js/store";
|
||||
import { client } from "../../..";
|
||||
import { useAppState } from "../../../state/StateProvider";
|
||||
import { useUser } from "../../../state/UserProvider";
|
||||
import { Build, Operation, PermissionLevel } from "../../../types";
|
||||
import { getId } from "../../../util/helpers";
|
||||
|
||||
type ConfigBuild = Build & {
|
||||
loaded: boolean;
|
||||
updated: boolean;
|
||||
saving: boolean;
|
||||
};
|
||||
|
||||
type State = {
|
||||
build: ConfigBuild;
|
||||
setBuild: SetStoreFunction<ConfigBuild>;
|
||||
reset: () => void;
|
||||
save: () => void;
|
||||
userCanUpdate: () => boolean;
|
||||
};
|
||||
|
||||
const context = createContext<State>();
|
||||
|
||||
export const ConfigProvider: ParentComponent<{}> = (p) => {
|
||||
const { ws, builds } = useAppState();
|
||||
const params = useParams();
|
||||
const { user } = useUser();
|
||||
const [build, set] = createStore({
|
||||
...builds.get(params.id)!,
|
||||
loaded: false,
|
||||
updated: false,
|
||||
saving: false,
|
||||
});
|
||||
const setBuild: SetStoreFunction<ConfigBuild> = (...args: any) => {
|
||||
// @ts-ignore
|
||||
set(...args);
|
||||
set("updated", true);
|
||||
};
|
||||
|
||||
const load = () => {
|
||||
// console.log("load build");
|
||||
client.get_build(params.id).then((build) => {
|
||||
set({
|
||||
...build,
|
||||
repo: build.repo,
|
||||
branch: build.branch,
|
||||
on_clone: build.on_clone,
|
||||
pre_build: build.pre_build,
|
||||
docker_build_args: build.docker_build_args,
|
||||
docker_account: build.docker_account,
|
||||
github_account: build.github_account,
|
||||
loaded: true,
|
||||
updated: false,
|
||||
saving: false,
|
||||
});
|
||||
});
|
||||
};
|
||||
createEffect(load);
|
||||
|
||||
const save = () => {
|
||||
setBuild("saving", true);
|
||||
client.update_build(build)
|
||||
};
|
||||
|
||||
onCleanup(
|
||||
ws.subscribe([Operation.UpdateBuild], (update) => {
|
||||
if (update.target.id === params.id) {
|
||||
load();
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
onCleanup(
|
||||
ws.subscribe(
|
||||
[Operation.ModifyUserPermissions],
|
||||
async (update) => {
|
||||
if (update.target.id === params.id) {
|
||||
const build = await client.get_build(params.id);
|
||||
set("permissions", build.permissions);
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
const userCanUpdate = () => user().admin || build.permissions[getId(user())] === PermissionLevel.Update;
|
||||
|
||||
const state = {
|
||||
build,
|
||||
setBuild,
|
||||
reset: load,
|
||||
save,
|
||||
userCanUpdate,
|
||||
};
|
||||
return <context.Provider value={state}>{p.children}</context.Provider>;
|
||||
};
|
||||
|
||||
export function useConfig() {
|
||||
return useContext(context) as State;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import { useParams } from "@solidjs/router";
|
||||
import { Component, Show } from "solid-js";
|
||||
import { useAppState } from "../../../state/StateProvider";
|
||||
import { useUser } from "../../../state/UserProvider";
|
||||
import { PermissionLevel } from "../../../types";
|
||||
import { getId } from "../../../util/helpers";
|
||||
import Tabs, { Tab } from "../../shared/tabs/Tabs";
|
||||
import BuildConfig from "./build-config/BuildConfig";
|
||||
import GitConfig from "./git-config/GitConfig";
|
||||
import Owners from "./Owners";
|
||||
import { ConfigProvider } from "./Provider";
|
||||
|
||||
const BuildTabs: Component<{}> = (p) => {
|
||||
const { builds } = useAppState();
|
||||
const params = useParams();
|
||||
const { user } = useUser();
|
||||
const build = () => builds.get(params.id)!;
|
||||
const userCanUpdate = () =>
|
||||
user().admin ||
|
||||
build().permissions[getId(user())] === PermissionLevel.Update;
|
||||
return (
|
||||
<Show when={build()}>
|
||||
<ConfigProvider>
|
||||
<Tabs
|
||||
containerClass="card shadow"
|
||||
tabs={
|
||||
[
|
||||
{
|
||||
title: "repo",
|
||||
element: () => <GitConfig />,
|
||||
},
|
||||
{
|
||||
title: "build",
|
||||
element: () => <BuildConfig />,
|
||||
},
|
||||
userCanUpdate() && {
|
||||
title: "collaborators",
|
||||
element: () => <Owners />,
|
||||
},
|
||||
].filter((e) => e) as Tab[]
|
||||
}
|
||||
localStorageKey="build-tab"
|
||||
/>
|
||||
</ConfigProvider>
|
||||
</Show>
|
||||
);
|
||||
};
|
||||
|
||||
export default BuildTabs;
|
||||
@@ -0,0 +1,46 @@
|
||||
import { Component, Show } from "solid-js";
|
||||
import ConfirmButton from "../../../shared/ConfirmButton";
|
||||
import Icon from "../../../shared/Icon";
|
||||
import Flex from "../../../shared/layout/Flex";
|
||||
import Grid from "../../../shared/layout/Grid";
|
||||
import CliBuild from "./CliBuild";
|
||||
import Docker from "./Docker";
|
||||
import { useConfig } from "../Provider";
|
||||
import Loading from "../../../shared/loading/Loading";
|
||||
|
||||
const BuildConfig: Component<{}> = (p) => {
|
||||
const { build, reset, save, userCanUpdate } = useConfig();
|
||||
return (
|
||||
<Show when={build.loaded}>
|
||||
<Grid class="config">
|
||||
<Grid class="config-items scroller">
|
||||
<Docker />
|
||||
<CliBuild />
|
||||
</Grid>
|
||||
<Show when={userCanUpdate() && build.updated}>
|
||||
<Show
|
||||
when={!build.saving}
|
||||
fallback={
|
||||
<button class="green">
|
||||
updating <Loading type="spinner" />
|
||||
</button>
|
||||
}
|
||||
>
|
||||
<Flex style={{ "place-self": "center", padding: "1rem" }}>
|
||||
<button onClick={reset}>
|
||||
reset
|
||||
<Icon type="reset" />
|
||||
</button>
|
||||
<ConfirmButton onConfirm={save} color="green">
|
||||
save
|
||||
<Icon type="floppy-disk" />
|
||||
</ConfirmButton>
|
||||
</Flex>
|
||||
</Show>
|
||||
</Show>
|
||||
</Grid>
|
||||
</Show>
|
||||
);
|
||||
};
|
||||
|
||||
export default BuildConfig;
|
||||
@@ -0,0 +1,44 @@
|
||||
import { Component } from "solid-js";
|
||||
import { combineClasses } from "../../../../util/helpers";
|
||||
import Input from "../../../shared/Input";
|
||||
import Flex from "../../../shared/layout/Flex";
|
||||
import Grid from "../../../shared/layout/Grid";
|
||||
import { useConfig } from "../Provider";
|
||||
|
||||
const CliBuild: Component<{}> = (p) => {
|
||||
const { build, setBuild, userCanUpdate } = useConfig();
|
||||
return (
|
||||
<Grid class={combineClasses("config-item shadow")}>
|
||||
<h1>pre build</h1>
|
||||
{/* <div style={{ opacity: 0.7 }}>build with a custom command</div> */}
|
||||
<Flex
|
||||
justifyContent={userCanUpdate() ? "space-between" : undefined}
|
||||
alignItems="center"
|
||||
style={{ "flex-wrap": "wrap" }}
|
||||
>
|
||||
<h2>build path: </h2>
|
||||
<Input
|
||||
placeholder="from root of repo"
|
||||
value={build.pre_build?.path || (userCanUpdate() ? "" : "/")}
|
||||
onEdit={(path) => setBuild("pre_build", { path })}
|
||||
disabled={!userCanUpdate()}
|
||||
/>
|
||||
</Flex>
|
||||
<Flex
|
||||
justifyContent={userCanUpdate() ? "space-between" : undefined}
|
||||
alignItems="center"
|
||||
style={{ "flex-wrap": "wrap" }}
|
||||
>
|
||||
<h2>command: </h2>
|
||||
<Input
|
||||
placeholder="ie. yarn build"
|
||||
value={build.pre_build?.command || ""}
|
||||
onEdit={(command) => setBuild("pre_build", { command })}
|
||||
disabled={!userCanUpdate()}
|
||||
/>
|
||||
</Flex>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default CliBuild;
|
||||
@@ -0,0 +1,77 @@
|
||||
import { Component, createEffect, createSignal, Show } from "solid-js";
|
||||
import { client } from "../../../..";
|
||||
import { useAppState } from "../../../../state/StateProvider";
|
||||
import { combineClasses } from "../../../../util/helpers";
|
||||
import Input from "../../../shared/Input";
|
||||
import Flex from "../../../shared/layout/Flex";
|
||||
import Grid from "../../../shared/layout/Grid";
|
||||
import Selector from "../../../shared/menu/Selector";
|
||||
import { useConfig } from "../Provider";
|
||||
|
||||
const Docker: Component<{}> = (p) => {
|
||||
const { build, setBuild, userCanUpdate } = useConfig();
|
||||
const [dockerAccounts, setDockerAccounts] = createSignal<string[]>();
|
||||
createEffect(() => {
|
||||
client.get_server_docker_accounts(build.server_id).then(setDockerAccounts);
|
||||
});
|
||||
return (
|
||||
<Grid class={combineClasses("config-item shadow")}>
|
||||
<h1>docker build</h1> {/* checkbox here? */}
|
||||
<Flex
|
||||
justifyContent={userCanUpdate() ? "space-between" : undefined}
|
||||
alignItems="center"
|
||||
style={{ "flex-wrap": "wrap" }}
|
||||
>
|
||||
<h2>build path: </h2>
|
||||
<Input
|
||||
placeholder="from root of repo"
|
||||
value={build.docker_build_args?.build_path || ""}
|
||||
onEdit={(build_path) => setBuild("docker_build_args", { build_path })}
|
||||
disabled={!userCanUpdate()}
|
||||
/>
|
||||
</Flex>
|
||||
<Flex
|
||||
justifyContent={userCanUpdate() ? "space-between" : undefined}
|
||||
alignItems="center"
|
||||
style={{ "flex-wrap": "wrap" }}
|
||||
>
|
||||
<h2>dockerfile path: </h2>
|
||||
<Input
|
||||
placeholder="from root of build path"
|
||||
value={
|
||||
build.docker_build_args?.dockerfile_path ||
|
||||
(userCanUpdate() ? "" : "Dockerfile")
|
||||
}
|
||||
onEdit={(dockerfile_path) =>
|
||||
setBuild("docker_build_args", { dockerfile_path })
|
||||
}
|
||||
disabled={!userCanUpdate()}
|
||||
/>
|
||||
</Flex>
|
||||
<Show when={dockerAccounts() && dockerAccounts()!.length > 0}>
|
||||
<Flex
|
||||
justifyContent={userCanUpdate() ? "space-between" : undefined}
|
||||
alignItems="center"
|
||||
style={{ "flex-wrap": "wrap" }}
|
||||
>
|
||||
<h2>dockerhub account: </h2>
|
||||
<Selector
|
||||
targetClass="blue"
|
||||
selected={build.docker_account || "none"}
|
||||
items={["none", ...dockerAccounts()!]}
|
||||
onSelect={(account) => {
|
||||
setBuild(
|
||||
"docker_account",
|
||||
account === "none" ? undefined : account
|
||||
);
|
||||
}}
|
||||
position="bottom right"
|
||||
disabled={!userCanUpdate()}
|
||||
/>
|
||||
</Flex>
|
||||
</Show>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default Docker;
|
||||
@@ -0,0 +1,71 @@
|
||||
import { Component, createEffect, createSignal, Show } from "solid-js";
|
||||
import Grid from "../../../shared/layout/Grid";
|
||||
import { useConfig } from "../Provider";
|
||||
import Flex from "../../../shared/layout/Flex";
|
||||
import Input from "../../../shared/Input";
|
||||
import Selector from "../../../shared/menu/Selector";
|
||||
import { combineClasses } from "../../../../util/helpers";
|
||||
import { client } from "../../../..";
|
||||
|
||||
const Git: Component<{}> = (p) => {
|
||||
const { build, setBuild, userCanUpdate } = useConfig();
|
||||
const [githubAccounts, setGithubAccounts] = createSignal<string[]>();
|
||||
createEffect(() => {
|
||||
client.get_server_github_accounts(build.server_id).then(setGithubAccounts)
|
||||
});
|
||||
return (
|
||||
<Grid class={combineClasses("config-item shadow")}>
|
||||
<h1>github config</h1>
|
||||
<Flex
|
||||
justifyContent={userCanUpdate() ? "space-between" : undefined}
|
||||
alignItems="center"
|
||||
style={{ "flex-wrap": "wrap" }}
|
||||
>
|
||||
<h2>repo: </h2>
|
||||
<Input
|
||||
placeholder="ie. solidjs/solid"
|
||||
value={build.repo || ""}
|
||||
onEdit={(value) => setBuild("repo", value)}
|
||||
disabled={!userCanUpdate()}
|
||||
/>
|
||||
</Flex>
|
||||
<Flex
|
||||
justifyContent={userCanUpdate() ? "space-between" : undefined}
|
||||
alignItems="center"
|
||||
style={{ "flex-wrap": "wrap" }}
|
||||
>
|
||||
<h2>branch: </h2>
|
||||
<Input
|
||||
placeholder="defaults to main"
|
||||
value={build.branch || (userCanUpdate() ? "" : "main")}
|
||||
onEdit={(value) => setBuild("branch", value)}
|
||||
disabled={!userCanUpdate()}
|
||||
/>
|
||||
</Flex>
|
||||
<Show when={githubAccounts() && githubAccounts()!.length > 0}>
|
||||
<Flex
|
||||
justifyContent={userCanUpdate() ? "space-between" : undefined}
|
||||
alignItems="center"
|
||||
style={{ "flex-wrap": "wrap" }}
|
||||
>
|
||||
<h2>github account: </h2>
|
||||
<Selector
|
||||
targetClass="blue"
|
||||
selected={build.github_account || "none"}
|
||||
items={["none", ...githubAccounts()!]}
|
||||
onSelect={(account) => {
|
||||
setBuild(
|
||||
"github_account",
|
||||
account === "none" ? undefined : account
|
||||
);
|
||||
}}
|
||||
position="bottom right"
|
||||
disabled={!userCanUpdate()}
|
||||
/>
|
||||
</Flex>
|
||||
</Show>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default Git;
|
||||
@@ -0,0 +1,69 @@
|
||||
import { Component, Show } from "solid-js";
|
||||
import { pushNotification, URL } from "../../../..";
|
||||
import { combineClasses, copyToClipboard } from "../../../../util/helpers";
|
||||
import ConfirmButton from "../../../shared/ConfirmButton";
|
||||
import Icon from "../../../shared/Icon";
|
||||
import Flex from "../../../shared/layout/Flex";
|
||||
import Grid from "../../../shared/layout/Grid";
|
||||
import Loading from "../../../shared/loading/Loading";
|
||||
import { useConfig } from "../Provider";
|
||||
import Git from "./Git";
|
||||
import OnClone from "./OnClone";
|
||||
|
||||
const GitConfig: Component<{}> = (p) => {
|
||||
const { build, reset, save, userCanUpdate } = useConfig();
|
||||
const listenerUrl = () => `${URL}/api/listener/build/${build._id}`;
|
||||
return (
|
||||
<Show when={build.loaded}>
|
||||
<Grid class="config">
|
||||
<Grid class="config-items scroller">
|
||||
<Git />
|
||||
<OnClone />
|
||||
<Show when={userCanUpdate()}>
|
||||
<Grid class={combineClasses("config-item shadow")}>
|
||||
<h1>webhook url</h1>
|
||||
<Flex justifyContent="space-between" alignItems="center">
|
||||
<div class="ellipsis" style={{ width: "250px" }}>
|
||||
{listenerUrl()}
|
||||
</div>
|
||||
<ConfirmButton
|
||||
color="blue"
|
||||
onFirstClick={() => {
|
||||
copyToClipboard(listenerUrl());
|
||||
pushNotification("good", "copied url to clipboard");
|
||||
}}
|
||||
confirm={<Icon type="check" />}
|
||||
>
|
||||
<Icon type="clipboard" />
|
||||
</ConfirmButton>
|
||||
</Flex>
|
||||
</Grid>
|
||||
</Show>
|
||||
</Grid>
|
||||
<Show when={userCanUpdate() && build.updated}>
|
||||
<Show
|
||||
when={!build.saving}
|
||||
fallback={
|
||||
<button class="green">
|
||||
updating <Loading type="spinner" />
|
||||
</button>
|
||||
}
|
||||
>
|
||||
<Flex style={{ "place-self": "center", padding: "1rem" }}>
|
||||
<button onClick={reset}>
|
||||
reset
|
||||
<Icon type="reset" />
|
||||
</button>
|
||||
<ConfirmButton onConfirm={save} color="green">
|
||||
save
|
||||
<Icon type="floppy-disk" />
|
||||
</ConfirmButton>
|
||||
</Flex>
|
||||
</Show>
|
||||
</Show>
|
||||
</Grid>
|
||||
</Show>
|
||||
);
|
||||
};
|
||||
|
||||
export default GitConfig;
|
||||
@@ -0,0 +1,63 @@
|
||||
import { Component } from "solid-js";
|
||||
import { combineClasses } from "../../../../util/helpers";
|
||||
import Input from "../../../shared/Input";
|
||||
import Grid from "../../../shared/layout/Grid";
|
||||
import { useConfig } from "../Provider";
|
||||
import Flex from "../../../shared/layout/Flex";
|
||||
|
||||
const OnClone: Component = () => {
|
||||
const { build, setBuild, userCanUpdate } = useConfig();
|
||||
return (
|
||||
<Grid class={combineClasses("config-item shadow")}>
|
||||
<h1>on clone</h1>
|
||||
<Flex
|
||||
alignItems="center"
|
||||
justifyContent={userCanUpdate() ? "space-between" : undefined}
|
||||
style={{ "flex-wrap": "wrap" }}
|
||||
>
|
||||
<h2>path:</h2>
|
||||
<Input
|
||||
placeholder="relative to repo"
|
||||
value={build.on_clone?.path || ""}
|
||||
onEdit={(path) => {
|
||||
if (
|
||||
path.length === 0 &&
|
||||
(!build.on_clone ||
|
||||
!build.on_clone.command ||
|
||||
build.on_clone.command.length === 0)
|
||||
) {
|
||||
setBuild("on_clone", undefined);
|
||||
}
|
||||
setBuild("on_clone", { path });
|
||||
}}
|
||||
disabled={!userCanUpdate()}
|
||||
/>
|
||||
</Flex>
|
||||
<Flex
|
||||
alignItems="center"
|
||||
justifyContent={userCanUpdate() ? "space-between" : undefined}
|
||||
style={{ "flex-wrap": "wrap" }}
|
||||
>
|
||||
<h2>command:</h2>
|
||||
<Input
|
||||
placeholder="command"
|
||||
value={build.on_clone?.command || ""}
|
||||
onEdit={(command) => {
|
||||
if (
|
||||
command.length === 0 &&
|
||||
(!build.on_clone ||
|
||||
!build.on_clone.path ||
|
||||
build.on_clone.path.length === 0)
|
||||
) {
|
||||
setBuild("on_clone", undefined);
|
||||
}
|
||||
setBuild("on_clone", { command });
|
||||
}}
|
||||
disabled={!userCanUpdate()}
|
||||
/>
|
||||
</Flex>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default OnClone;
|
||||
@@ -109,4 +109,8 @@ export function serverStatusClass(
|
||||
} else if (status === ServerStatus.NotOk) {
|
||||
return "exited"
|
||||
}
|
||||
}
|
||||
|
||||
export function copyToClipboard(text: string) {
|
||||
navigator.clipboard.writeText(text);
|
||||
}
|
||||
Reference in New Issue
Block a user