Skip to content

Commit

Permalink
delete resources by id
Browse files Browse the repository at this point in the history
  • Loading branch information
FredericHeem committed Dec 16, 2023
1 parent 6787091 commit 421716f
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 102 deletions.
10 changes: 6 additions & 4 deletions bau-ui/tabs/tabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,12 @@ export default function (context, options = {}) {
const search = new URLSearchParams(window.location.search);
const tabName = search.get(tabsKey) ?? tabDefs[0].name;

const nextTab = tabByName(tabName);
tabCurrentState.val.exit?.call();
tabCurrentState.val = nextTab;
nextTab?.enter?.call();
if (tabName != tabCurrentState.val.name) {
const nextTab = tabByName(tabName);
tabCurrentState.val.exit?.call();
tabCurrentState.val = nextTab;
nextTab?.enter?.call();
}
};

hashchange();
Expand Down
265 changes: 174 additions & 91 deletions examples/gccd/src/components/resourcesTree.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,35 @@
import rubico from "rubico";
const { pipe, map, tap } = rubico;
import rubicox from "rubico/x";
const { pluck, prepend, callProp } = rubicox;
import { type Context } from "@grucloud/bau-ui/context";
import checkbox from "@grucloud/bau-ui/checkbox";
import treeView from "@grucloud/bau-ui/treeView";
import button from "@grucloud/bau-ui/button";

import useQuery from "../utils/useQuery";
import tableSkeleton from "./tableSkeleton";
import runLogsModal from "./run/runLogsModal";

export default function (context: Context) {
const { bau, css } = context;
const { div, pre, a, label } = bau.tags;
const { bau, css, window, stores, config } = context;
const { form, article, header, pre, a, p, label } = bau.tags;

const className = css`
overflow-x: scroll;
display: flex;
flex-direction: column;
justify-content: space-between;
& article {
overflow-x: scroll;
}
`;

const Checkbox = checkbox(context, { color: "neutral", variant: "outline" });

const TableSkeleton = tableSkeleton(context);

const query = useQuery(context);

const getResources = query(
async (stateUrl: any) => {
try {
const response = await fetch(stateUrl);
if (response.ok) {
const res = await response.json();
return res.result?.lives?.results[0].results;
}
throw response;
} catch (error) {
throw error;
}
},
{ initialState: [] }
);
const ButtonDelete = button(context, {
variant: "solid",
color: "danger",
});

const toTree = pipe([
tap((params: any) => {
Expand All @@ -43,8 +38,8 @@ export default function (context: Context) {
map(({ resources = [], groupType }: any) =>
pipe([
() => resources,
map(({ name, live, dependencies }: any) => ({
data: { name },
map(({ name, id, live, dependencies }: any) => ({
data: { name, id, type: "resource" },
children: [
{
data: {
Expand All @@ -62,7 +57,10 @@ export default function (context: Context) {
},
],
})),
(children: any) => ({ data: { name: groupType }, children }),
(children: any) => ({
data: { name: groupType, type: "group" },
children,
}),
])()
),
tap((params: any) => {
Expand All @@ -75,80 +73,155 @@ export default function (context: Context) {
}),
]);

const getCheckboxId = ({ id, name }: any) => id ?? name;
const getCheckboxEl = (data: any): HTMLInputElement =>
window.document.getElementById(getCheckboxId(data)) as HTMLInputElement;
const getAllChecked = (event: any) => {
const formEl = event.target.closest("form");
const checkboxesChecked = formEl.querySelectorAll(
'input[type="checkbox"][data-type="resource"]:checked'
);
return checkboxesChecked;
};

const walkTree =
({ onNode }: any) =>
(item: any) => {
onNode(item);
const { children = [] } = item;
children.map(walkTree({ onNode }));
};
return function ResourcesTree({ data }: any) {
// const { org_id, project_id, workspace_id } = data.val;
console.assert(data);
// console.assert(org_id);
// console.assert(project_id);
// console.assert(workspace_id);
const RunLogsModal = runLogsModal(context);

const selectedCount = bau.state(0);

const query = useQuery(context);

const onsubmit = async (event: any) => {
event.preventDefault();
const { org_id, project_id, workspace_id } = data.val;
const formEl = event.target.closest("form");
const ids = pluck("id")([...getAllChecked(event)]);

const isParentIndeterminate = ({ parent }: any) => {
if (parent) {
const { children } = parent;
const parentCheckboxEl = getCheckboxEl(parent.data);
if (parentCheckboxEl) {
const allUnchecked = children.every((child: any) => {
const { checked, indeterminate } = getCheckboxEl(child.data);
return !checked && !indeterminate;
});
parentCheckboxEl.indeterminate =
!allUnchecked &&
children.some((child: any) => !getCheckboxEl(child.data).checked);
parentCheckboxEl.checked = children.every(
(child: any) => getCheckboxEl(child.data).checked
);
const { run_id, container_id } = await stores.run.createQuery.run(
{ org_id, project_id, workspace_id },
{
kind: "destroy",
engine: config.engine,
args: pipe([
() => ids,
map(prepend("--id ")),
callProp("join", " "),
])(),
}
);
const search = new URLSearchParams(window.location.search);
search.set("run_id", run_id);
if (container_id) {
search.set("container_id", container_id);
}
isParentIndeterminate({ parent: parent.parent });
}
};
window.history.pushState("", "", `?${search}`);

const onclickCheckbox =
({ item, parent }: any) =>
(event: any) => {
isParentIndeterminate({ parent });
walkTree({
onNode: (node: any) => {
const checkboxEl = getCheckboxEl(node.data);
if (checkboxEl) {
checkboxEl.checked = event.target.checked;
checkboxEl.indeterminate = false;
}
},
})(item);
event.stopPropagation();
const modalEl = RunLogsModal({
org_id,
project_id,
workspace_id,
run_id,
container_id,
});
formEl.append(modalEl);
modalEl.showModal();
};

const renderMenuItem = ({ item, parent, depth }: any) => {
const { id, name, content } = item.data;
const checkboxId = id ?? name;
return label(
{
class: css`
display: flex;
flex-direction: row;
align-items: center;
padding-right: 1rem;
`,
onclick: (event: any) => event.stopPropagation(),
const getResources = query(
async (stateUrl: any) => {
try {
const response = await fetch(stateUrl);
if (response.ok) {
const res = await response.json();
return res.result?.lives?.results[0].results;
}
throw Error(response.statusText);
} catch (error) {
throw error;
}
},
depth <= 3 &&
Checkbox({
onclick: onclickCheckbox({ item, parent }),
name: checkboxId,
id: checkboxId,
}),
content ? pre(content) : a({}, name)
{ initialState: [] }
);
};

const TreeView = treeView(context, { renderMenuItem, variant: "plain" });
const getCheckboxId = ({ id, name }: any) => id ?? name;
const getCheckboxEl = (data: any): HTMLInputElement =>
window.document.getElementById(getCheckboxId(data)) as HTMLInputElement;

const walkTree =
({ onNode }: any) =>
(item: any) => {
onNode(item);
const { children = [] } = item;
children.map(walkTree({ onNode }));
};

const isParentIndeterminate = ({ parent }: any) => {
if (parent) {
const { children } = parent;
const parentCheckboxEl = getCheckboxEl(parent.data);
if (parentCheckboxEl) {
const allUnchecked = children.every((child: any) => {
const { checked, indeterminate } = getCheckboxEl(child.data);
return !checked && !indeterminate;
});
parentCheckboxEl.indeterminate =
!allUnchecked &&
children.some((child: any) => !getCheckboxEl(child.data).checked);
parentCheckboxEl.checked = children.every(
(child: any) => getCheckboxEl(child.data).checked
);
}
isParentIndeterminate({ parent: parent.parent });
}
};

const onclickCheckbox =
({ item, parent }: any) =>
(event: any) => {
event.stopPropagation();
isParentIndeterminate({ parent });
walkTree({
onNode: (node: any) => {
const checkboxEl = getCheckboxEl(node.data);
if (checkboxEl) {
checkboxEl.checked = event.target.checked;
checkboxEl.indeterminate = false;
}
},
})(item);

const checkboxesChecked = getAllChecked(event);
selectedCount.val = checkboxesChecked.length;
};

const renderMenuItem = ({ item, parent, depth }: any) => {
const { id, name, content, type } = item.data;
const checkboxId = id ?? name;
return label(
{
class: css`
display: flex;
flex-direction: row;
align-items: center;
padding-right: 1rem;
`,
onclick: (event: any) => event.stopPropagation(),
},
depth <= 3 &&
Checkbox({
onclick: onclickCheckbox({ item, parent }),
name: checkboxId,
id: checkboxId,
"data-type": type,
}),
content ? pre(content) : a({}, name)
);
};

const TreeView = treeView(context, { renderMenuItem, variant: "plain" });

return function ResourcesTree({ data }: any) {
bau.derive(() => {
const { stateUrl } = data.val;
if (
Expand All @@ -160,14 +233,24 @@ export default function (context: Context) {
}
});

return div(
return form(
{
class: className,
onsubmit,
},
() =>
header(
p(
ButtonDelete(
{ type: "submit" },
() => `Delete ${selectedCount.val} Resource(s)`
)
)
),
article(() =>
getResources.loading.val
? TableSkeleton({ columnsSize: 2, rowSize: 20 })
: TreeView({ tree: toTree(getResources.data.val) })
)
);
};
}
12 changes: 8 additions & 4 deletions examples/gccd/src/pages/run/runCreatePage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,13 @@ export default function (context: Context) {
});

return function RunCreatePage({ org_id, project_id, workspace_id }: any) {
console.assert(org_id);
console.assert(project_id);
console.assert(workspace_id);

const onsubmit = async (event: any) => {
event.preventDefault();

const formEl = event.target.closest("form");
const { reason, kind } = event.target.elements;
const { run_id, container_id } = await stores.run.createQuery.run(
{ org_id, project_id, workspace_id },
Expand All @@ -50,15 +54,15 @@ export default function (context: Context) {
}

window.history.pushState("", "", `?${search}`);
const modelEl = RunLogsModal({
const modalEl = RunLogsModal({
org_id,
project_id,
workspace_id,
run_id,
container_id,
});
event.target.closest("form").append(modelEl);
modelEl.showModal();
formEl.append(modalEl);
modalEl.showModal();
};

return Page(
Expand Down
Loading

0 comments on commit 421716f

Please sign in to comment.