Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement mesh wide config stepper #459

Draft
wants to merge 36 commits into
base: f/v3-candidate
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
324a459
chore(meshconfig): implement WizardWrapper
selankon Sep 25, 2024
d01d81f
chore(meshconfig): implement useMeshWideConfigState
selankon Sep 25, 2024
9c9e746
chore(meshconfig): implement NodesListWrapper
selankon Oct 2, 2024
c318c50
chore(meshconfig): implement NodeInfoListItem
selankon Oct 3, 2024
2dc4303
chore(meshconfig): fix mesh types
selankon Oct 3, 2024
a6a95cf
chore(meshconfig): mock stepper types
selankon Oct 9, 2024
c754874
chore(meshconfig): implement lime config json parser
selankon Oct 10, 2024
179ff79
chore(meshconfig): implement entry edition
selankon Oct 10, 2024
d77ce87
chore(meshconfig): implement delete entry
selankon Oct 10, 2024
d975999
chore(meshconfig): support list forms
selankon Oct 15, 2024
641920d
chore(meshconfig): implement add new section
selankon Oct 15, 2024
9570f3c
chore(meshconfig): implement add new config section
selankon Oct 15, 2024
93280d4
chore(meshconfig): implement add new list item
selankon Oct 15, 2024
c451161
chore(meshconfig): fix rebase
selankon Oct 25, 2024
662becd
chore(meshconfig): implement add new configuration section
selankon Oct 25, 2024
c0dda22
chore(meshconfig): bulk bugfix
selankon Oct 28, 2024
bb7e94d
chore(meshconfig): fix form
selankon Oct 29, 2024
3ddf980
chore(meshconfig): fix form layout
selankon Oct 29, 2024
41c2947
chore(meshconfig): fix form
selankon Oct 29, 2024
3778abd
chore(meshconfig): implement is dirty
selankon Oct 30, 2024
ee252a5
chore(meshconfig): implement submit
selankon Oct 30, 2024
5a28eaa
chore(mesh-config): fix query keys
selankon Nov 4, 2024
e4ef645
chore(mesh-config): implement api calls
selankon Nov 4, 2024
cac8315
chore(mesh-config): create standarized api call
selankon Nov 5, 2024
fdbcba7
chore(mesh-config): reimplement parse community file
selankon Nov 5, 2024
4fdcc02
chore(mesh-config): mock base states
selankon Nov 8, 2024
4962eee
chore(mesh-config): refactor query keys
selankon Nov 8, 2024
4d7abec
chore(mesh-config): implement abort
selankon Nov 8, 2024
a40ac03
chore(mesh-config): implement mutate new config
selankon Nov 8, 2024
f92e163
chore(mesh-config): improve mesh info messages
selankon Nov 8, 2024
a847722
chore(mesh-config): implemented schedule safe rebot
selankon Nov 8, 2024
5b63c1e
chore(mesh-config): implemented confirm
selankon Nov 8, 2024
841091e
chore(mesh-config): some bulkfix
selankon Nov 8, 2024
eadd237
chore(mesh-config): move common files
selankon Nov 12, 2024
3ce32ce
chore(mesh-config): implement stepper states
selankon Nov 12, 2024
ba3b62c
chore(mesh-config): implement applying
selankon Nov 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 14 additions & 10 deletions plugins/lime-plugin-mesh-wide-config/src/components/Components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,23 +51,27 @@ export const EditOrDelete = ({
onEdit,
onDelete,
}: {
onEdit: (e) => void;
onDelete: (e) => void;
onEdit?: (e) => void;
onDelete?: (e) => void;
}) => {
const runCb = (e, cb) => {
e.stopPropagation();
cb();
};
return (
<div className={"flex flex-row gap-3"}>
<EditIcon
className={"cursor-pointer"}
onClick={(e) => runCb(e, onEdit)}
/>
<BinIcon
className={"cursor-pointer"}
onClick={(e) => runCb(e, onDelete)}
/>
{!!onEdit && (
<EditIcon
className={"cursor-pointer"}
onClick={(e) => runCb(e, onEdit)}
/>
)}
{!!onDelete && (
<BinIcon
className={"cursor-pointer"}
onClick={(e) => runCb(e, onDelete)}
/>
)}
</div>
);
};
121 changes: 0 additions & 121 deletions plugins/lime-plugin-mesh-wide-config/src/components/ConfigSection.tsx

This file was deleted.

185 changes: 185 additions & 0 deletions plugins/lime-plugin-mesh-wide-config/src/components/FormEdit.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
import { Trans, t } from "@lingui/macro";
import { useEffect, useState } from "preact/hooks";
import { Controller, useFormContext } from "react-hook-form";
import { v4 as uuidv4 } from "uuid";

import { useDisclosure } from "components/Modal/useDisclosure";
import { Button, ButtonProps } from "components/buttons/button";
import InputField from "components/inputs/InputField";
import { useToast } from "components/toast/toastProvider";

import { EditOrDelete } from "plugins/lime-plugin-mesh-wide-config/src/components/Components";
import {
AddNewSectionFormProps,
AddNewSectionModal,
} from "plugins/lime-plugin-mesh-wide-config/src/components/modals";
import { IMeshWideConfig } from "plugins/lime-plugin-mesh-wide-config/src/meshConfigTypes";

export const EditableField = ({
isList,
name,
}: {
isList: boolean;
name: string;
}) => {
const { control, setValue, watch, getValues } = useFormContext();

const value = watch(name);
// Hack to force re-render when the list changes
const [uniqueKeys, setUniqueKeys] = useState(
isList && value?.length ? value.map(() => uuidv4()) : []
);

const syncKeysWithValues = () => {
// Ensure uniqueKeys matches the length of value array
setUniqueKeys((keys) => [
...keys,
...Array(value.length - keys.length)
.fill(null)
.map(() => uuidv4()),
]);
};

const removeListItem = (index) => {
const updatedValues = value.filter((_, i) => i !== index);
setValue(name, updatedValues);
setUniqueKeys((keys) => keys.filter((_, i) => i !== index));
};

const addListItem = () => {
setValue(name, [...value, ""]);
setUniqueKeys((keys) => [...keys, uuidv4()]);
};

// Ensure the list has at least one item at the start
useEffect(() => {
if (isList && value.length === 0) {
setValue(name, [""]);
setUniqueKeys([uuidv4()]); // Reset keys for new list
} else if (isList) {
// Sync keys with values length on every render
syncKeysWithValues();
}
}, [isList, value, name, setValue]);

if (isList) {
return (
<div key={name} className={"flex flex-col gap-6"}>
{uniqueKeys.map((item, index) => (
<Controller
key={uniqueKeys[index]} // Use the unique key
control={control}
name={`${name}[${index}]`}
rules={{
minLength: {
value: 1,
message: t`Minimum length is 1`,
},
required: t`This field cannot be empty`,
}}
render={({ field, fieldState: { error } }) => {
return (
<div
className={
"flex flex-row justify-center align-items-center gap-4"
}
>
<InputField
id={`${name}[${index}]`}
className="w-100"
error={error?.message}
{...field}
/>
<EditOrDelete
onDelete={() => removeListItem(index)}
/>
</div>
);
}}
/>
))}
<AddElementButton onClick={addListItem} />
</div>
);
}

return (
<Controller
name={name}
control={control}
rules={{
minLength: {
value: 1,
message: t`Minimum length is 1`,
},
required: t`This field cannot be empty`,
}}
render={({ field, fieldState: { error } }) => (
<InputField
id={name}
label={<Trans>Value</Trans>}
className="w-100"
error={error?.message}
{...field}
/>
)}
/>
);
};

export const AddNewConfigSection = ({
sectionName,
}: {
sectionName?: string;
}) => {
const { watch, setValue } = useFormContext<IMeshWideConfig>();

const { open, onOpen, onClose } = useDisclosure();
const { showToast } = useToast();

const section = watch(sectionName);

const onSuccess = (data: AddNewSectionFormProps) => {
if (!sectionName) {
setValue(data.name, {});
} else {
let value: string | string[] = data.value;
if (data.isList) {
value = data.values;
}
setValue(sectionName, {
...section,
[data.name]: value,
});
}
onClose();
showToast({
text: <Trans>Added section {data.name}</Trans>,
});
};

return (
<>
<AddElementButton onClick={onOpen} />
<AddNewSectionModal
sectionName={sectionName}
isOpen={open}
onSuccess={onSuccess}
onClose={onClose}
/>
</>
);
};

export const AddElementButton = (props: ButtonProps) => {
return (
<div className="flex justify-center">
<Button
{...props}
className="flex items-center justify-center w-12 h-12 rounded-full border-2 border-gray-400 text-gray-400 hover:bg-gray-100 font-bold cursor-pointer"
>
+
</Button>
</div>
);
};
Loading