forked from github-starred/komodo
topbar ws indicator and userPermissionsOnEntity
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { Component, JSX } from "solid-js";
|
||||
import { combineClasses } from "../../../util/helpers";
|
||||
import { combineClasses, filterOutFromObj } from "../../../util/helpers";
|
||||
import s from "./Layout.module.css";
|
||||
|
||||
const Flex: Component<
|
||||
@@ -28,6 +28,14 @@ const Flex: Component<
|
||||
> = (p) => {
|
||||
return (
|
||||
<div
|
||||
{...filterOutFromObj(p, [
|
||||
"gap",
|
||||
"alignItems",
|
||||
"justifyContent",
|
||||
"placeItems",
|
||||
"style",
|
||||
"class",
|
||||
])}
|
||||
class={combineClasses(s.Flex, p.class)}
|
||||
style={{
|
||||
gap: p.gap,
|
||||
@@ -36,7 +44,6 @@ const Flex: Component<
|
||||
"place-items": p.placeItems,
|
||||
...(p.style as any),
|
||||
}}
|
||||
{...p}
|
||||
>
|
||||
{p.children}
|
||||
</div>
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
import { Component, JSX } from "solid-js";
|
||||
import { combineClasses } from "../../../util/helpers";
|
||||
import { combineClasses, filterOutFromObj } from "../../../util/helpers";
|
||||
import s from "./Layout.module.css";
|
||||
|
||||
const Grid: Component<{
|
||||
gap?: string | number;
|
||||
placeItems?: string;
|
||||
style?: JSX.CSSProperties;
|
||||
class?: string
|
||||
} & JSX.HTMLAttributes<HTMLDivElement>> = (p) => {
|
||||
const Grid: Component<
|
||||
{
|
||||
gap?: string | number;
|
||||
placeItems?: string;
|
||||
style?: JSX.CSSProperties;
|
||||
class?: string;
|
||||
} & JSX.HTMLAttributes<HTMLDivElement>
|
||||
> = (p) => {
|
||||
return (
|
||||
<div
|
||||
{...filterOutFromObj(p, ["gap", "placeItems", "style", "class"])}
|
||||
class={combineClasses(s.Grid, p.class)}
|
||||
style={{
|
||||
gap: p.gap,
|
||||
"place-items": p.placeItems,
|
||||
...(p.style as any),
|
||||
}}
|
||||
{...p}
|
||||
>
|
||||
{p.children}
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { useNavigate } from "@solidjs/router";
|
||||
import { Component, createSignal, JSX, Show } from "solid-js";
|
||||
import { TOPBAR_HEIGHT } from "../..";
|
||||
import { useAppDimensions } from "../../state/DimensionProvider";
|
||||
import { useAppState } from "../../state/StateProvider";
|
||||
import { useUser } from "../../state/UserProvider";
|
||||
import { combineClasses, inPx } from "../../util/helpers";
|
||||
import Circle from "../shared/Circle";
|
||||
@@ -37,17 +39,17 @@ const Topbar: Component = () => {
|
||||
};
|
||||
|
||||
const LeftSide: Component = () => {
|
||||
const { ws } = useAppState();
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<Flex
|
||||
alignItems="center"
|
||||
style={{ padding: "0rem 0.5rem", "place-self": "center start" }}
|
||||
>
|
||||
<button class="grey" onClick={() => {
|
||||
// selected.set("", "home");
|
||||
}}>
|
||||
<button class="grey" onClick={() => navigate("/")}>
|
||||
<Icon type="home" width="1.15rem" />
|
||||
</button>
|
||||
{/* <HoverMenu
|
||||
<HoverMenu
|
||||
target={
|
||||
<Circle
|
||||
size={1}
|
||||
@@ -57,7 +59,7 @@ const LeftSide: Component = () => {
|
||||
}
|
||||
content={ws.isOpen() ? "connected" : "disconnected"}
|
||||
position="right center"
|
||||
/> */}
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
@@ -73,24 +75,6 @@ const RightSide: Component = () => {
|
||||
alignItems="center"
|
||||
style={{ padding: "0rem 0.5rem", "place-self": "center end" }}
|
||||
>
|
||||
{/* <Menu
|
||||
show={menu() === "updates"}
|
||||
close={close}
|
||||
menuStyle={isMobile() ? mobileStyle : undefined}
|
||||
target={
|
||||
<Button
|
||||
class="grey"
|
||||
onClick={() =>
|
||||
menu() === "updates" ? setMenu(undefined) : setMenu("updates")
|
||||
}
|
||||
>
|
||||
<Icon type="notifications" alt="updates" width="1.15rem" />
|
||||
</Button>
|
||||
}
|
||||
content={<Updates />}
|
||||
position="bottom right"
|
||||
backgroundColor={isMobile() ? "rgba(0,0,0,0.6)" : undefined}
|
||||
/> */}
|
||||
<Menu
|
||||
show={menu() === "account"}
|
||||
close={close}
|
||||
|
||||
@@ -10,12 +10,16 @@ import {
|
||||
} from "./hooks";
|
||||
import connectToWs from "./ws";
|
||||
import { useUser } from "./UserProvider";
|
||||
import { PermissionLevel } from "../types";
|
||||
|
||||
export type State = {
|
||||
servers: ReturnType<typeof useServers>;
|
||||
getPermissionOnServer: (id: string) => PermissionLevel;
|
||||
serverStats: ReturnType<typeof useServerStats>;
|
||||
builds: ReturnType<typeof useBuilds>;
|
||||
getPermissionOnBuild: (id: string) => PermissionLevel;
|
||||
deployments: ReturnType<typeof useDeployments>;
|
||||
getPermissionOnDeployment: (id: string) => PermissionLevel;
|
||||
updates: ReturnType<typeof useUpdates>;
|
||||
};
|
||||
|
||||
@@ -27,13 +31,50 @@ const context = createContext<
|
||||
>();
|
||||
|
||||
export const AppStateProvider: ParentComponent = (p) => {
|
||||
const { logout } = useUser();
|
||||
const { user, logout } = useUser();
|
||||
const navigate = useNavigate();
|
||||
const userId = (user()._id as any).$oid as string;
|
||||
const servers = useServers();
|
||||
const builds = useBuilds();
|
||||
const deployments = useDeployments();
|
||||
const state: State = {
|
||||
servers: useServers(),
|
||||
servers,
|
||||
getPermissionOnServer: (id: string) => {
|
||||
const server = servers.get(id)!;
|
||||
const permissions = server.server.permissions![userId] as
|
||||
| PermissionLevel
|
||||
| undefined;
|
||||
if (permissions) {
|
||||
return permissions;
|
||||
} else {
|
||||
return PermissionLevel.None;
|
||||
}
|
||||
},
|
||||
builds,
|
||||
getPermissionOnBuild: (id: string) => {
|
||||
const build = builds.get(id)!;
|
||||
const permissions = build.permissions![userId] as
|
||||
| PermissionLevel
|
||||
| undefined;
|
||||
if (permissions) {
|
||||
return permissions;
|
||||
} else {
|
||||
return PermissionLevel.None;
|
||||
}
|
||||
},
|
||||
deployments,
|
||||
getPermissionOnDeployment: (id: string) => {
|
||||
const deployment = deployments.get(id)!;
|
||||
const permissions = deployment.deployment.permissions![userId] as
|
||||
| PermissionLevel
|
||||
| undefined;
|
||||
if (permissions) {
|
||||
return permissions;
|
||||
} else {
|
||||
return PermissionLevel.None;
|
||||
}
|
||||
},
|
||||
serverStats: useServerStats(),
|
||||
builds: useBuilds(),
|
||||
deployments: useDeployments(),
|
||||
updates: useUpdates(),
|
||||
};
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ export function useDeployments() {
|
||||
}
|
||||
|
||||
export function useUpdates(target?: UpdateTarget) {
|
||||
const updates = useArray(() => client.list_updates(0, target));
|
||||
const updates = useArrayWithId(() => client.list_updates(0, target), ["_id", "$oid"]);
|
||||
const [noMore, setNoMore] = createSignal(false);
|
||||
const loadMore = async () => {
|
||||
const offset = updates.collection()?.length;
|
||||
@@ -94,10 +94,10 @@ export function useArray<T>(query: () => Promise<T[]>) {
|
||||
query().then(set);
|
||||
});
|
||||
const add = (item: T) => {
|
||||
set((items: any) => (items ? [item, ...items] : [item]));
|
||||
set((items: T[] | undefined) => (items ? [item, ...items] : [item]));
|
||||
};
|
||||
const addManyToEnd = (items: T[]) => {
|
||||
set((curr: any) => (curr ? [...curr, ...items] : items));
|
||||
set((curr: T[] | undefined) => (curr ? [...curr, ...items] : items));
|
||||
};
|
||||
const loaded = () => (collection() ? true : false);
|
||||
return {
|
||||
@@ -108,6 +108,44 @@ export function useArray<T>(query: () => Promise<T[]>) {
|
||||
};
|
||||
}
|
||||
|
||||
export function useArrayWithId<T>(query: () => Promise<T[]>, idPath: string[]) {
|
||||
const [collection, set] = createSignal<T[]>();
|
||||
createEffect(() => {
|
||||
query().then(set);
|
||||
});
|
||||
const addOrUpdate = (item: T) => {
|
||||
set((items: T[] | undefined) => {
|
||||
if (items) {
|
||||
const newId = getNestedEntry(item, idPath);
|
||||
const existingIndex = items.findIndex(i => getNestedEntry(i, idPath) === newId);
|
||||
if (existingIndex < 0) {
|
||||
return [item, ...items]
|
||||
} else {
|
||||
return items.map((e, index) => {
|
||||
if (index === existingIndex) {
|
||||
return item
|
||||
} else {
|
||||
return e
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return [item];
|
||||
}
|
||||
});
|
||||
};
|
||||
const addManyToEnd = (items: T[]) => {
|
||||
set((curr: T[] | undefined) => (curr ? [...curr, ...items] : items));
|
||||
};
|
||||
const loaded = () => (collection() ? true : false);
|
||||
return {
|
||||
collection,
|
||||
addOrUpdate,
|
||||
addManyToEnd,
|
||||
loaded,
|
||||
};
|
||||
}
|
||||
|
||||
export function useCollection<T>(query: () => Promise<Collection<T>>, idPath: string[]) {
|
||||
const [collection, { mutate }] = createResource(query);
|
||||
const add = (item: T) => {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { client, pushNotification, WS_URL } from "..";
|
||||
import { State } from "./StateProvider";
|
||||
import { createSignal } from "solid-js";
|
||||
import ReconnectingWebSocket from "reconnecting-websocket";
|
||||
import { Operation, Update, UpdateStatus } from "../types";
|
||||
import { Operation, Update, UpdateStatus, UpdateTarget } from "../types";
|
||||
|
||||
function connectToWs(state: State) {
|
||||
const ws = new ReconnectingWebSocket(WS_URL);
|
||||
@@ -17,7 +17,7 @@ function connectToWs(state: State) {
|
||||
|
||||
ws.addEventListener("message", ({ data }) => {
|
||||
if (data === "LOGGED_IN") {
|
||||
// console.log("logged in to ws");
|
||||
console.log("logged in to ws");
|
||||
return;
|
||||
}
|
||||
const update = JSON.parse(data) as Update;
|
||||
@@ -40,10 +40,7 @@ function connectToWs(state: State) {
|
||||
});
|
||||
|
||||
return {
|
||||
subscribe: (
|
||||
operations: string[],
|
||||
callback: (update: Update) => void
|
||||
) => {
|
||||
subscribe: (operations: string[], callback: (update: Update) => void) => {
|
||||
const listener = ({ data }: { data: string }) => {
|
||||
if (data === "PONG") {
|
||||
return;
|
||||
@@ -67,14 +64,27 @@ async function handleMessage(
|
||||
{ deployments, builds, servers, updates }: State,
|
||||
update: Update
|
||||
) {
|
||||
updates.add(update);
|
||||
updates.addOrUpdate(update);
|
||||
let name = "";
|
||||
if (update.target.type === "Deployment") {
|
||||
const deployment = deployments.get(update.target.id);
|
||||
name = deployment ? deployment.deployment.name : "";
|
||||
} else if (update.target.type === "Build") {
|
||||
const build = builds.get(update.target.id);
|
||||
name = build ? build.name : "";
|
||||
} else if (update.target.type === "Server") {
|
||||
const server = servers.get(update.target.id);
|
||||
name = server ? server.server.name : "";
|
||||
}
|
||||
pushNotification(
|
||||
update.status === UpdateStatus.InProgress
|
||||
? "ok"
|
||||
: update.success
|
||||
? "good"
|
||||
: "bad",
|
||||
`${update.operation} (${update.status})`
|
||||
`${update.operation.replaceAll("_", " ")} ${name ? `on ${name} ` : ""}(${
|
||||
update.status
|
||||
})`
|
||||
);
|
||||
|
||||
// deployment
|
||||
|
||||
Reference in New Issue
Block a user