@mui/material#AccordionSummary TypeScript Examples
The following examples show how to use
@mui/material#AccordionSummary.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: index.tsx From genshin-optimizer with MIT License | 6 votes |
function FormulaCalc({ sectionKey, displayNs }: { displayNs: DisplaySub<NodeDisplay>, sectionKey: string }) {
const { data } = useContext(DataContext)
const header = usePromise(getDisplayHeader(data, sectionKey), [data, sectionKey])
if (!header) return null
if (Object.entries(displayNs).every(([_, node]) => node.isEmpty)) return null
const { title, icon, action } = header
return <CardDark sx={{ mb: 1 }}>
<CardHeader avatar={icon && <ImgIcon size={2} sx={{ m: -1 }} src={icon} />} title={title} action={action} titleTypographyProps={{ variant: "subtitle1" }} />
<Divider />
<CardContent>
{Object.entries(displayNs).map(([key, node]) =>
!node.isEmpty && <Accordion sx={{ bgcolor: "contentLight.main" }} key={key}>
<AccordionSummary expandIcon={<ExpandMore />}>
<Typography><ColorText color={node.info.variant}>{KeyMap.get(node.info.key ?? "")}</ColorText> <strong>{valueString(node.value, node.unit)}</strong></Typography>
</AccordionSummary>
<AccordionDetails>
{node.formulas.map((subform, i) => <Typography key={i}>{subform}</Typography>)}
</AccordionDetails>
</Accordion>)}
</CardContent>
</CardDark>
}
Example #2
Source File: SidebarLink.tsx From Cromwell with MIT License | 5 votes |
SidebarLink = (props: {
data: TSidebarLink,
toggleSubMenu: (panel: string) => (event: React.ChangeEvent, isExpanded: boolean) => void,
expanded: string | false;
forceUpdate: () => void;
activeId: string;
userInfo: TUser | undefined;
}) => {
const isExpanded = props.expanded === props.data.id;
if (props.data?.roles && props.userInfo?.role) {
if (!props.data.roles.includes(props.userInfo.role)) {
return null;
}
}
let head = (
<MenuItem className={styles.linkHead}>
<div className={styles.linkHeadContent}>
<div className={styles.sidebarlinkIcon}>{props.data.icon}</div>
<p>{props.data.title}</p>
</div>
{props.data.subLinks && (
<ExpandMoreIcon style={{ transform: isExpanded ? 'rotate(180deg)' : '' }}
className={styles.ExpandMoreIcon} htmlColor='#999' />
)}
</MenuItem>
);
if (props.data.route) {
head = <Link to={props.data.route}
onClick={e => {
e.stopPropagation();
// props.setActiveId(props.data.id);
}}
>{head}</Link>
}
if (props.data.subLinks) return (
<ExpansionPanel
key={props.data.id}
expanded={isExpanded}
onChange={props.toggleSubMenu(props.data.id)}
className={styles.SidebarLink}>
<AccordionSummary
className={styles.ExpansionPanelSummary}
aria-controls={`subLinks-${props.data.title}-content`}
>{head}
</AccordionSummary>
<ExpansionPanelDetails>
<div className={styles.subLinksContainer}>
{props.data.subLinks.map(subLink => (
<SidebarLink data={subLink}
key={subLink.id}
expanded={props.expanded} toggleSubMenu={props.toggleSubMenu}
forceUpdate={props.forceUpdate}
activeId={props.activeId}
userInfo={props.userInfo}
/>
))}
</div>
</ExpansionPanelDetails>
</ExpansionPanel>
);
return (
<div className={`${styles.SidebarLink} ${props.activeId === props.data.id ? styles.SidebarLinkActive : ''}`}
key={props.data.id}
>{head}
</div>
)
}
Example #3
Source File: itemAccordion.tsx From Search-Next with GNU General Public License v3.0 | 5 votes |
ItemAccordion: React.FC<ItemAccordionProps> = ({
title,
desc,
action,
expanded,
onChange,
children,
disableDetailPadding = false,
}) => {
return (
<Accordion
expanded={expanded}
onChange={onChange}
className={classNames(
'rounded border shadow-none bg-white my-0',
css`
&::before {
background-color: transparent !important;
}
`,
)}
>
<AccordionSummary
className=" transition hover:bg-gray-100"
expandIcon={<ExpandMore />}
>
<div className="flex items-center justify-between w-full mr-2">
<div>
{title && <p className="mb-0 text-sm">{title}</p>}
{desc && <p className="mb-0 text-xs text-gray-700">{desc}</p>}
</div>
<div className="flex items-center">{action}</div>
</div>
</AccordionSummary>
<AccordionDetails className={classNames({ 'p-0': disableDetailPadding })}>
{children}
</AccordionDetails>
</Accordion>
);
}
Example #4
Source File: AddLifecycleModal.tsx From console with GNU Affero General Public License v3.0 | 4 votes |
AddLifecycleModal = ({
open,
closeModalAndRefresh,
classes,
bucketName,
}: IReplicationModal) => {
const dispatch = useDispatch();
const distributedSetup = useSelector(selDistSet);
const [loadingTiers, setLoadingTiers] = useState<boolean>(true);
const [tiersList, setTiersList] = useState<ITiersDropDown[]>([]);
const [addLoading, setAddLoading] = useState(false);
const [isVersioned, setIsVersioned] = useState<boolean>(false);
const [prefix, setPrefix] = useState("");
const [tags, setTags] = useState<string>("");
const [storageClass, setStorageClass] = useState("");
const [ilmType, setIlmType] = useState<string>("expiry");
const [targetVersion, setTargetVersion] = useState<"current" | "noncurrent">(
"current"
);
const [lifecycleDays, setLifecycleDays] = useState<string>("");
const [isFormValid, setIsFormValid] = useState<boolean>(false);
const [expiredObjectDM, setExpiredObjectDM] = useState<boolean>(false);
const [loadingVersioning, setLoadingVersioning] = useState<boolean>(true);
useEffect(() => {
if (loadingTiers) {
api
.invoke("GET", `/api/v1/admin/tiers`)
.then((res: ITierResponse) => {
const tiersList: ITierElement[] | null = get(res, "items", []);
if (tiersList !== null && tiersList.length >= 1) {
const objList = tiersList.map((tier: ITierElement) => {
const tierType = tier.type;
const value = get(tier, `${tierType}.name`, "");
return { label: value, value: value };
});
setTiersList(objList);
if (objList.length > 0) {
setStorageClass(objList[0].value);
}
}
setLoadingTiers(false);
})
.catch((err: ErrorResponseHandler) => {
setLoadingTiers(false);
});
}
}, [loadingTiers]);
useEffect(() => {
let valid = true;
if (ilmType !== "expiry") {
if (storageClass === "") {
valid = false;
}
}
setIsFormValid(valid);
}, [ilmType, lifecycleDays, storageClass]);
useEffect(() => {
if (loadingVersioning && distributedSetup) {
api
.invoke("GET", `/api/v1/buckets/${bucketName}/versioning`)
.then((res: BucketVersioning) => {
setIsVersioned(res.is_versioned);
setLoadingVersioning(false);
})
.catch((err: ErrorResponseHandler) => {
dispatch(setModalErrorSnackMessage(err));
setLoadingVersioning(false);
});
}
}, [loadingVersioning, dispatch, bucketName, distributedSetup]);
const addRecord = () => {
let rules = {};
if (ilmType === "expiry") {
let expiry: { [key: string]: number } = {};
if (targetVersion === "current") {
expiry["expiry_days"] = parseInt(lifecycleDays);
} else {
expiry["noncurrentversion_expiration_days"] = parseInt(lifecycleDays);
}
rules = {
...expiry,
};
} else {
let transition: { [key: string]: number | string } = {};
if (targetVersion === "current") {
transition["transition_days"] = parseInt(lifecycleDays);
transition["storage_class"] = storageClass;
} else {
transition["noncurrentversion_transition_days"] =
parseInt(lifecycleDays);
transition["noncurrentversion_transition_storage_class"] = storageClass;
}
rules = {
...transition,
};
}
const lifecycleInsert = {
type: ilmType,
prefix,
tags,
expired_object_delete_marker: expiredObjectDM,
...rules,
};
api
.invoke(
"POST",
`/api/v1/buckets/${bucketName}/lifecycle`,
lifecycleInsert
)
.then(() => {
setAddLoading(false);
closeModalAndRefresh(true);
})
.catch((err: ErrorResponseHandler) => {
setAddLoading(false);
dispatch(setModalErrorSnackMessage(err));
});
};
return (
<ModalWrapper
modalOpen={open}
onClose={() => {
closeModalAndRefresh(false);
}}
title="Add Lifecycle Rule"
titleIcon={<LifecycleConfigIcon />}
>
{loadingTiers && (
<Grid container className={classes.loadingBox}>
<Grid item xs={12}>
<LinearProgress />
</Grid>
</Grid>
)}
{!loadingTiers && (
<form
noValidate
autoComplete="off"
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setAddLoading(true);
addRecord();
}}
>
<Grid container>
<Grid item xs={12} className={classes.formScrollable}>
<Grid item xs={12}>
<Grid container spacing={1}>
<Grid item xs={12}>
<RadioGroupSelector
currentSelection={ilmType}
id="ilm_type"
name="ilm_type"
label="Type of lifecycle"
onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
setIlmType(e.target.value as string);
}}
selectorOptions={[
{ value: "expiry", label: "Expiry" },
{ value: "transition", label: "Transition" },
]}
/>
</Grid>
{isVersioned && (
<Grid item xs={12}>
<SelectWrapper
value={targetVersion}
id="object_version"
name="object_version"
label="Object Version"
onChange={(e) => {
setTargetVersion(
e.target.value as "current" | "noncurrent"
);
}}
options={[
{ value: "current", label: "Current Version" },
{ value: "noncurrent", label: "Non-Current Version" },
]}
/>
</Grid>
)}
<Grid item xs={12}>
<InputBoxWrapper
id="expiry_days"
name="expiry_days"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.validity.valid) {
setLifecycleDays(e.target.value);
}
}}
pattern={"[0-9]*"}
label="After"
value={lifecycleDays}
overlayObject={
<InputUnitMenu
id={"expire-current-unit"}
unitSelected={"days"}
unitsList={[{ label: "Days", value: "days" }]}
disabled={true}
/>
}
/>
</Grid>
{ilmType === "expiry" ? (
<Fragment></Fragment>
) : (
<Fragment>
<Grid item xs={12}>
<SelectWrapper
label="To Tier"
id="storage_class"
name="storage_class"
value={storageClass}
onChange={(e: SelectChangeEvent<string>) => {
setStorageClass(e.target.value as string);
}}
options={tiersList}
/>
</Grid>
</Fragment>
)}
<Grid item xs={12} className={classes.formFieldRowFilter}>
<Accordion>
<AccordionSummary>
<Typography>Filters</Typography>
</AccordionSummary>
<AccordionDetails>
<Grid item xs={12}>
<InputBoxWrapper
id="prefix"
name="prefix"
onChange={(
e: React.ChangeEvent<HTMLInputElement>
) => {
setPrefix(e.target.value);
}}
label="Prefix"
value={prefix}
/>
</Grid>
<Grid item xs={12}>
<QueryMultiSelector
name="tags"
label="Tags"
elements={""}
onChange={(vl: string) => {
setTags(vl);
}}
keyPlaceholder="Tag Key"
valuePlaceholder="Tag Value"
withBorder
/>
</Grid>
</AccordionDetails>
</Accordion>
</Grid>
{ilmType === "expiry" && targetVersion === "noncurrent" && (
<Grid item xs={12} className={classes.formFieldRowFilter}>
<Accordion>
<AccordionSummary>
<Typography>Advanced</Typography>
</AccordionSummary>
<AccordionDetails>
<Grid item xs={12}>
<FormSwitchWrapper
value="expired_delete_marker"
id="expired_delete_marker"
name="expired_delete_marker"
checked={expiredObjectDM}
onChange={(
event: React.ChangeEvent<HTMLInputElement>
) => {
setExpiredObjectDM(event.target.checked);
}}
label={"Expire Delete Marker"}
description={
"Remove the reference to the object if no versions are left"
}
/>
</Grid>
</AccordionDetails>
</Accordion>
</Grid>
)}
</Grid>
</Grid>
</Grid>
<Grid item xs={12} className={classes.modalButtonBar}>
<Button
type="button"
variant="outlined"
color="primary"
disabled={addLoading}
onClick={() => {
closeModalAndRefresh(false);
}}
>
Cancel
</Button>
<Button
type="submit"
variant="contained"
color="primary"
disabled={addLoading || !isFormValid}
>
Save
</Button>
</Grid>
{addLoading && (
<Grid item xs={12}>
<LinearProgress />
</Grid>
)}
</Grid>
</form>
)}
</ModalWrapper>
);
}
Example #5
Source File: EditLifecycleConfiguration.tsx From console with GNU Affero General Public License v3.0 | 4 votes |
EditLifecycleConfiguration = ({
classes,
closeModalAndRefresh,
selectedBucket,
lifecycleRule,
open,
}: IAddUserContentProps) => {
const dispatch = useDispatch();
const [loadingTiers, setLoadingTiers] = useState<boolean>(true);
const [addLoading, setAddLoading] = useState<boolean>(false);
const [tags, setTags] = useState<string>("");
const [enabled, setEnabled] = useState<boolean>(false);
const [tiersList, setTiersList] = useState<ITiersDropDown[]>([]);
const [prefix, setPrefix] = useState("");
const [storageClass, setStorageClass] = useState("");
const [NCTransitionSC, setNCTransitionSC] = useState("");
const [expiredObjectDM, setExpiredObjectDM] = useState<boolean>(false);
const [NCExpirationDays, setNCExpirationDays] = useState<string>("0");
const [NCTransitionDays, setNCTransitionDays] = useState<string>("0");
const [ilmType, setIlmType] = useState<string>("expiry");
const [expiryDays, setExpiryDays] = useState<string>("0");
const [transitionDays, setTransitionDays] = useState<string>("0");
const [isFormValid, setIsFormValid] = useState<boolean>(false);
useEffect(() => {
if (loadingTiers) {
api
.invoke("GET", `/api/v1/admin/tiers`)
.then((res: ITierResponse) => {
const tiersList: ITierElement[] | null = get(res, "items", []);
if (tiersList !== null && tiersList.length >= 1) {
const objList = tiersList.map((tier: ITierElement) => {
const tierType = tier.type;
const value = get(tier, `${tierType}.name`, "");
return { label: value, value: value };
});
setTiersList(objList);
if (objList.length > 0) {
setStorageClass(objList[0].value);
}
}
setLoadingTiers(false);
})
.catch((err: ErrorResponseHandler) => {
setLoadingTiers(false);
});
}
}, [loadingTiers]);
useEffect(() => {
let valid = true;
if (ilmType !== "expiry") {
if (storageClass === "") {
valid = false;
}
}
setIsFormValid(valid);
}, [ilmType, expiryDays, transitionDays, storageClass]);
useEffect(() => {
if (lifecycleRule.status === "Enabled") {
setEnabled(true);
}
let transitionMode = false;
if (lifecycleRule.transition) {
if (
lifecycleRule.transition.days &&
lifecycleRule.transition.days !== 0
) {
setTransitionDays(lifecycleRule.transition.days.toString());
setIlmType("transition");
transitionMode = true;
}
if (
lifecycleRule.transition.noncurrent_transition_days &&
lifecycleRule.transition.noncurrent_transition_days !== 0
) {
setNCTransitionDays(
lifecycleRule.transition.noncurrent_transition_days.toString()
);
setIlmType("transition");
transitionMode = true;
}
// Fallback to old rules by date
if (
lifecycleRule.transition.date &&
lifecycleRule.transition.date !== "0001-01-01T00:00:00Z"
) {
setIlmType("transition");
transitionMode = true;
}
}
if (lifecycleRule.expiration) {
if (
lifecycleRule.expiration.days &&
lifecycleRule.expiration.days !== 0
) {
setExpiryDays(lifecycleRule.expiration.days.toString());
setIlmType("expiry");
transitionMode = false;
}
if (
lifecycleRule.expiration.noncurrent_expiration_days &&
lifecycleRule.expiration.noncurrent_expiration_days !== 0
) {
setNCExpirationDays(
lifecycleRule.expiration.noncurrent_expiration_days.toString()
);
setIlmType("expiry");
transitionMode = false;
}
// Fallback to old rules by date
if (
lifecycleRule.expiration.date &&
lifecycleRule.expiration.date !== "0001-01-01T00:00:00Z"
) {
setIlmType("expiry");
transitionMode = false;
}
}
// Transition fields
if (transitionMode) {
setStorageClass(lifecycleRule.transition?.storage_class || "");
setNCTransitionDays(
lifecycleRule.transition?.noncurrent_transition_days?.toString() || "0"
);
setNCTransitionSC(
lifecycleRule.transition?.noncurrent_storage_class || ""
);
} else {
// Expiry fields
setNCExpirationDays(
lifecycleRule.expiration?.noncurrent_expiration_days?.toString() || "0"
);
}
setExpiredObjectDM(!!lifecycleRule.expiration?.delete_marker);
setPrefix(lifecycleRule.prefix || "");
if (lifecycleRule.tags) {
const tgs = lifecycleRule.tags.reduce(
(stringLab: string, currItem: any, index: number) => {
return `${stringLab}${index !== 0 ? "&" : ""}${currItem.key}=${
currItem.value
}`;
},
""
);
setTags(tgs);
}
}, [lifecycleRule]);
const saveRecord = (event: React.FormEvent) => {
event.preventDefault();
if (addLoading) {
return;
}
setAddLoading(true);
if (selectedBucket !== null && lifecycleRule !== null) {
let rules = {};
if (ilmType === "expiry") {
let expiry: { [key: string]: number } = {};
if (
lifecycleRule.expiration?.days &&
lifecycleRule.expiration?.days > 0
) {
expiry["expiry_days"] = parseInt(expiryDays);
}
if (lifecycleRule.expiration?.noncurrent_expiration_days) {
expiry["noncurrentversion_expiration_days"] =
parseInt(NCExpirationDays);
}
rules = {
...expiry,
};
} else {
let transition: { [key: string]: number | string } = {};
if (
lifecycleRule.expiration?.days &&
lifecycleRule.expiration?.days > 0
) {
transition["transition_days"] = parseInt(expiryDays);
transition["storage_class"] = storageClass;
}
if (lifecycleRule.expiration?.noncurrent_expiration_days) {
transition["noncurrentversion_transition_days"] =
parseInt(NCExpirationDays);
transition["noncurrentversion_transition_storage_class"] =
NCTransitionSC;
}
rules = {
...transition,
};
}
const lifecycleUpdate = {
type: ilmType,
disable: !enabled,
prefix,
tags,
expired_object_delete_marker: expiredObjectDM,
...rules,
};
api
.invoke(
"PUT",
`/api/v1/buckets/${selectedBucket}/lifecycle/${lifecycleRule.id}`,
lifecycleUpdate
)
.then((res) => {
setAddLoading(false);
closeModalAndRefresh(true);
})
.catch((err: ErrorResponseHandler) => {
setAddLoading(false);
dispatch(setModalErrorSnackMessage(err));
});
}
};
return (
<ModalWrapper
onClose={() => {
closeModalAndRefresh(false);
}}
modalOpen={open}
title={"Edit Lifecycle Configuration"}
titleIcon={<LifecycleConfigIcon />}
>
<form
noValidate
autoComplete="off"
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
saveRecord(e);
}}
>
<Grid container>
<Grid item xs={12} className={classes.formScrollable}>
<Grid container spacing={1}>
<Grid item xs={12}>
<InputBoxWrapper
id="id"
name="id"
label="Id"
value={lifecycleRule.id}
onChange={() => {}}
disabled
/>
</Grid>
<Grid item xs={12}>
<FormSwitchWrapper
label="Status"
indicatorLabels={["Enabled", "Disabled"]}
checked={enabled}
value={"user_enabled"}
id="rule_status"
name="rule_status"
onChange={(e) => {
setEnabled(e.target.checked);
}}
/>
</Grid>
<Grid item xs={12}>
<RadioGroupSelector
currentSelection={ilmType}
id="rule_type"
name="rule_type"
label="Rule Type"
selectorOptions={[
{ value: "expiry", label: "Expiry" },
{ value: "transition", label: "Transition" },
]}
onChange={() => {}}
disableOptions
/>
</Grid>
{ilmType === "expiry" && lifecycleRule.expiration?.days && (
<Grid item xs={12}>
<InputBoxWrapper
type="number"
id="expiry_days"
name="expiry_days"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setExpiryDays(e.target.value);
}}
label="Expiry Days"
value={expiryDays}
min="0"
/>
</Grid>
)}
{ilmType === "expiry" &&
lifecycleRule.expiration?.noncurrent_expiration_days && (
<Grid item xs={12}>
<InputBoxWrapper
type="number"
id="noncurrentversion_expiration_days"
name="noncurrentversion_expiration_days"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setNCExpirationDays(e.target.value);
}}
label="Non-current Expiration Days"
value={NCExpirationDays}
min="0"
/>
</Grid>
)}
{ilmType === "transition" && lifecycleRule.transition?.days && (
<Fragment>
<Grid item xs={12}>
<InputBoxWrapper
type="number"
id="transition_days"
name="transition_days"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setTransitionDays(e.target.value);
}}
label="Transition Days"
value={transitionDays}
min="0"
/>
</Grid>
<Grid item xs={12}>
<SelectWrapper
label="Storage Class"
id="storage_class"
name="storage_class"
value={storageClass}
onChange={(e: SelectChangeEvent<string>) => {
setStorageClass(e.target.value as string);
}}
options={tiersList}
/>
</Grid>
</Fragment>
)}
{ilmType === "transition" &&
lifecycleRule.transition?.noncurrent_transition_days && (
<Fragment>
<Grid item xs={12}>
<InputBoxWrapper
type="number"
id="noncurrentversion_transition_days"
name="noncurrentversion_transition_days"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setNCTransitionDays(e.target.value);
}}
label="Non-current Transition Days"
value={NCTransitionDays}
min="0"
/>
</Grid>
<Grid item xs={12}>
<InputBoxWrapper
id="noncurrentversion_t_SC"
name="noncurrentversion_t_SC"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setNCTransitionSC(e.target.value);
}}
placeholder="Set Non-current Version Transition Storage Class"
label="Non-current Version Transition Storage Class"
value={NCTransitionSC}
/>
</Grid>
</Fragment>
)}
<Grid item xs={12} className={classes.formFieldRowAccordion}>
<Accordion>
<AccordionSummary>
<Typography>Filters</Typography>
</AccordionSummary>
<AccordionDetails>
<Grid item xs={12}>
<InputBoxWrapper
id="prefix"
name="prefix"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setPrefix(e.target.value);
}}
label="Prefix"
value={prefix}
/>
</Grid>
<Grid item xs={12}>
<QueryMultiSelector
name="tags"
label="Tags"
elements={tags}
onChange={(vl: string) => {
setTags(vl);
}}
keyPlaceholder="Tag Key"
valuePlaceholder="Tag Value"
withBorder
/>
</Grid>
</AccordionDetails>
</Accordion>
</Grid>
{ilmType === "expiry" &&
lifecycleRule.expiration?.noncurrent_expiration_days && (
<Grid item xs={12} className={classes.formFieldRowAccordion}>
<Accordion>
<AccordionSummary>
<Typography>Advanced</Typography>
</AccordionSummary>
<AccordionDetails>
<Grid item xs={12}>
<FormSwitchWrapper
value="expired_delete_marker"
id="expired_delete_marker"
name="expired_delete_marker"
checked={expiredObjectDM}
onChange={(
event: React.ChangeEvent<HTMLInputElement>
) => {
setExpiredObjectDM(event.target.checked);
}}
label={"Expired Object Delete Marker"}
/>
</Grid>
</AccordionDetails>
</Accordion>
</Grid>
)}
</Grid>
</Grid>
<Grid item xs={12} className={classes.modalButtonBar}>
<Button
type="button"
variant="outlined"
color="primary"
disabled={addLoading}
onClick={() => {
closeModalAndRefresh(false);
}}
>
Cancel
</Button>
<Button
type="submit"
variant="contained"
color="primary"
disabled={addLoading || !isFormValid}
>
Save
</Button>
</Grid>
{addLoading && (
<Grid item xs={12}>
<LinearProgress />
</Grid>
)}
</Grid>
</form>
</ModalWrapper>
);
}
Example #6
Source File: BlockEditor.tsx From NekoMaid with MIT License | 4 votes |
BlockEditor: React.FC = () => {
const theme = useTheme()
const plugin = usePlugin()
const his = useHistory()
const loc = useLocation()
const globalData = useGlobalData()
const drawerWidth = useDrawerWidth()
const [block, setBlock] = useState<Block>()
const [types, setTypes] = useState<string[]>([])
const [worlds, setWorlds] = useState<string[]>([])
const params = { world: '', x: 0, y: 0, z: 0 }
if (loc.pathname.startsWith('/NekoMaid/block/')) {
const arr = loc.pathname.split('/')
if (arr.length > 6) {
params.world = arr[3]
params.x = +arr[4]
params.y = +arr[5]
params.z = +arr[6]
} else his.push('/NekoMaid/block')
}
useEffect(() => {
const off = plugin.emit('item:blocks', (types: string[], worlds: string[]) => {
setTypes(types)
setWorlds(worlds)
})
.on('block:select', (world, x, y, z) => his.push(`/NekoMaid/block/${world}/${x}/${y}/${z}`))
return () => void off()
}, [])
const update = () => {
if (params.world) {
plugin.emit('block:fetch', (block: Block) => {
if (!block) {
failed()
his.push('/NekoMaid/block')
return
}
if (globalData.hasNBTAPI && block.nbt) block.nbt = stringify(parse(block.nbt), { pretty: true })
setBlock(block)
}, params.world, params.x, params.y, params.z)
}
}
const updateWithAction = (res: boolean) => {
action(res)
update()
}
useEffect(update, [params.world, params.x, params.y, params.z])
return <Box sx={{ minHeight: '100%', py: 3 }}>
<Toolbar />
<Container maxWidth={false}>
<Grid container spacing={3} sx={{ width: { sm: `calc(100vw - ${drawerWidth}px - ${theme.spacing(3)})` } }}>
<Grid item lg={6} md={12} xl={6} xs={12}>
<Card sx={{ '& .CodeMirror-dialog, .CodeMirror-scrollbar-filler': { backgroundColor: theme.palette.background.paper + '!important' } }}>
<CardHeader
title={lang.blockEditor.title}
sx={{ position: 'relative' }}
action={<Box sx={cardActionStyles}>
<IconButton
size='small'
disabled={!block || (!block.data && !block.nbt)}
onClick={() => block && plugin.emit('block:save', (res: boolean) => {
action(res)
update()
}, params.world, params.x, params.y, params.z, block.nbt || null, block.data || null)}
><Save /></IconButton>
<IconButton
size='small'
disabled={!block}
onClick={() => {
update()
success()
}}
><Refresh /></IconButton>
</Box>}
/>
<Divider />
{block
? <>
<CardContent sx={{ display: 'flex', width: '100%', justifyContent: 'center' }}>
<ItemViewer item={{ type: block.type }} />
<Autocomplete
options={types}
sx={{ maxWidth: 300, marginLeft: 1, flexGrow: 1 }}
value={block.type}
onChange={(_, it) => it && plugin.emit('block:type', (res: boolean) => {
action(res)
update()
}, params.world, params.x, params.y, params.z, (block.type = it))}
getOptionLabel={it => {
const locatedName = getName(it.toLowerCase())
return (locatedName ? locatedName + ' ' : '') + it
}}
renderInput={(params) => <TextField {...params} label={lang.itemEditor.itemType} size='small' variant='standard' />}
/>
</CardContent>
{block.data != null && <Accordion sx={{ '&::before': { opacity: '1!important' } }} disableGutters>
<AccordionSummary expandIcon={<ExpandMore />}><Typography>{lang.data}</Typography></AccordionSummary>
<AccordionDetails sx={{ padding: 0, '& .CodeMirror': { width: '100%', height: 350 } }}>
<UnControlled
value={block.data}
options={{
mode: 'javascript',
phrases: lang.codeMirrorPhrases,
theme: theme.palette.mode === 'dark' ? 'material' : 'one-light'
}}
onChange={(_: any, __: any, data: string) => (block.data = data)}
/>
</AccordionDetails>
</Accordion>}
{block.nbt != null && <Accordion sx={{ '&::before': { opacity: '1!important', display: '!important' } }} disableGutters>
<AccordionSummary expandIcon={<ExpandMore />}><Typography>NBT</Typography></AccordionSummary>
<AccordionDetails sx={{ padding: 0, '& .CodeMirror': { width: '100%', height: 350 } }}>
<UnControlled
value={block.nbt}
options={{
mode: 'javascript',
phrases: lang.codeMirrorPhrases,
theme: theme.palette.mode === 'dark' ? 'material' : 'one-light'
}}
onChange={(_: any, __: any, data: string) => (block.nbt = data)}
/>
</AccordionDetails>
</Accordion>}
</>
: <CardContent>{worlds.length ? <BlockSelector worlds={worlds} /> : <Empty />}</CardContent>}
</Card>
</Grid>
{block?.inventory?.length
? <Grid item lg={6} md={12} xl={6} xs={12}>
<Card>
<CardHeader
title={minecraft[('container.' + block.inventoryType || '').toLowerCase()] || lang.blockEditor.container}
sx={{ position: 'relative' }}
/>
<Divider />
<CardContent sx={{ whiteSpace: 'nowrap', overflowX: 'auto', textAlign: 'center' }}>
{block.inventory.map((it, i) => <React.Fragment key={i}><ItemViewer
item={it}
data={{ type: InvType.BLOCK, solt: i, ...params }}
onDrag={() => plugin.emit('block:setItem', update, params.world, params.x, params.y, params.z, i, null, -1)}
onDrop={(item, obj) => plugin.emit('block:setItem', update, params.world, params.x, params.y, params.z, i,
JSON.stringify(item), compare(obj, params) ? obj.solt : -1)}
onEdit={item => item !== false && plugin.emit('block:setItem', updateWithAction, params.world, params.x, params.y,
params.z, i, item && JSON.stringify(item), -1)}
/>{!((i + 1) % 9) && <br />}</React.Fragment>)}
</CardContent>
</Card>
</Grid>
: undefined}
</Grid>
</Container>
</Box>
}
Example #7
Source File: Dashboard.tsx From NekoMaid with MIT License | 4 votes |
Dashboard: React.FC = () => {
const plugin = usePlugin()
const { version, hasGeoIP } = useGlobalData()
const [status, setStatus] = useState<Status[]>([])
const [current, setCurrent] = useState<CurrentStatus | undefined>()
useEffect(() => {
const offSetStatus = plugin.once('dashboard:info', setStatus)
const offCurrent = plugin.on('dashboard:current', (data: CurrentStatus) => setCurrent(old => {
if (old && isEqual(old.players, data.players)) data.players = old.players
return data
}))
plugin.switchPage('dashboard')
return () => {
offSetStatus()
offCurrent()
}
}, [])
const playerCount = current?.players?.length || 0
const prev = status[status.length - 1]?.players || 0
const percent = (prev ? playerCount / prev - 1 : playerCount) * 100
const tpsColor = !current || current.tps >= 18 ? green : current.tps >= 15 ? yellow : red
return <Box sx={{ minHeight: '100%', py: 3 }}>
<Toolbar />
<Container maxWidth={false}>
<Grid container spacing={3}>
<Grid item lg={3} sm={6} xl={3} xs={12}>
<TopCard
title={lang.dashboard.version}
content={current ? version : <Skeleton animation='wave' width={150} />}
icon={<Handyman />}
color={orange[600]}
>
<Box sx={{ pt: 2, display: 'flex', alignItems: 'flex-end' }}>
{!current || current.behinds < 0
? <Refresh htmlColor={blue[900]} />
: current?.behinds === 0
? <Check htmlColor={green[900]} />
: <Update htmlColor={yellow[900]} />}
<Typography color='textSecondary' variant='caption'> {!current || current.behinds === -3
? lang.dashboard.updateChecking
: current.behinds < 0
? <Link underline='hover' color='inherit' sx={{ cursor: 'pointer' }} onClick={() => {
toast(lang.dashboard.updateChecking)
plugin.emit('dashboard:checkUpdate')
}}>{lang.dashboard.updateFailed}</Link>
: current.behinds === 0 ? lang.dashboard.updated : lang.dashboard.behinds(current.behinds)}</Typography>
</Box>
</TopCard>
</Grid>
<Grid item lg={3} sm={6} xl={3} xs={12}>
<TopCard
title={lang.dashboard.onlinePlayers}
content={current ? playerCount : <Skeleton animation='wave' width={150} />}
icon={<People />}
color={deepPurple[600]}
>
<Box sx={{ pt: 2, display: 'flex', alignItems: 'flex-end' }}>
{percent === 0 ? <Remove color='primary' /> : percent < 0 ? <ArrowDownward color='error' /> : <ArrowUpward color='success' />}
<Typography
sx={{ color: (percent === 0 ? blue : percent < 0 ? red : green)[900], mr: 1 }}
variant='body2'
>{Math.abs(percent).toFixed(0)}%</Typography>
<Typography color='textSecondary' variant='caption'>{lang.dashboard.lastHour}</Typography>
</Box>
</TopCard>
</Grid>
<Grid item lg={3} sm={6} xl={3} xs={12}>
<TopCard
title='TPS'
content={current ? (current.tps === -1 ? '?' : current.tps.toFixed(2)) : <Skeleton animation='wave' width={150} />}
icon={!current || current.tps >= 18 || current.tps === -1
? <SentimentVerySatisfied />
: current.tps >= 15 ? <SentimentSatisfied /> : <SentimentDissatisfied />}
color={tpsColor[600]}
>
<Box sx={{ pt: 2.1, display: 'flex', alignItems: 'flex-end' }}>
<Typography
sx={{ color: tpsColor[900], mr: 1 }}
variant='body2'
>{!current || current.mspt === -1 ? '?' : current.mspt.toFixed(2) + 'ms'}</Typography>
<Typography color='textSecondary' variant='caption'>{lang.dashboard.mspt}</Typography>
</Box>
</TopCard>
</Grid>
<Grid item lg={3} sm={6} xl={3} xs={12}>
<TopCard
title={lang.dashboard.uptime}
content={current ? <Uptime time={current.time} /> : <Skeleton animation='wave' width={150} />}
icon={<AccessTime />}
color={blue[600]}
>
<Box sx={{ pt: 2.7, display: 'flex', alignItems: 'center' }}>
<Typography color='textSecondary' variant='caption' sx={{ marginRight: 1 }}>{lang.dashboard.memory}</Typography>
<Tooltip title={current?.totalMemory ? prettyBytes(current.memory) + ' / ' + prettyBytes(current.totalMemory) : ''}>
<LinearProgress
variant='determinate'
value={current?.totalMemory ? current.memory / current.totalMemory * 100 : 0}
sx={{ flex: '1' }}
/>
</Tooltip>
</Box>
</TopCard>
</Grid>
<Grid item lg={8} md={12} xl={9} xs={12}>{useMemo(() => <Charts data={status} />, [status])}</Grid>
<Grid item lg={4} md={12} xl={3} xs={12}><Players players={current?.players} /></Grid>
{hasGeoIP && current?.players && typeof current.players[0] !== 'string' && <Grid item xs={12}>
<Accordion TransitionProps={{ unmountOnExit: true }} disableGutters>
<AccordionSummary expandIcon={<ExpandMore />}>
<Typography>{lang.dashboard.playersDistribution}</Typography>
</AccordionSummary>
<Divider />
<WorldMap players={current.players as Player[]} />
</Accordion>
</Grid>}
</Grid>
</Container>
</Box>
}
Example #8
Source File: EntityEditor.tsx From NekoMaid with MIT License | 4 votes |
EntityEditor: React.FC = () => {
const theme = useTheme()
const plugin = usePlugin()
const his = useHistory()
const loc = useLocation()
const globalData = useGlobalData()
const drawerWidth = useDrawerWidth()
const [customName, setCustomName] = useState('')
const [entity, setEntity] = useState<Entity>()
let id: string | null = null
if (loc.pathname.startsWith('/NekoMaid/entity/')) {
const arr = loc.pathname.split('/')
if (arr.length > 3) id = arr[3]
}
useEffect(() => {
const off = plugin.on('entity:select', id => his.push('/NekoMaid/entity/' + id))
return () => void off()
}, [])
const update = () => {
if (id) {
plugin.emit('entity:fetch', (entity: Entity) => {
if (!entity) {
failed()
his.push('/NekoMaid/entity')
return
}
if (globalData.hasNBTAPI && entity.nbt) entity.nbt = stringify(parse(entity.nbt), { pretty: true })
setCustomName(entity.customName || '')
setEntity(entity)
}, id)
}
}
const updateWithAction = (res: boolean) => {
action(res)
update()
}
useEffect(update, [id])
return <Box sx={{ minHeight: '100%', py: 3 }}>
<Toolbar />
<Container maxWidth={false}>
<Grid container spacing={3} sx={{ width: { sm: `calc(100vw - ${drawerWidth}px - ${theme.spacing(3)})` } }}>
<Grid item lg={6} md={12} xl={6} xs={12}>
<Card>
<CardHeader
title={(entity && minecraft['entity.minecraft.' + entity.type.toLowerCase()]) || lang.entityEditor.title}
sx={{ position: 'relative' }}
action={<Box sx={cardActionStyles}>
<IconButton
size='small'
disabled={!entity}
onClick={() => entity && plugin.emit('entity:save', (res: boolean) => {
action(res)
update()
}, id, entity.nbt || null, customName || null)}
><Save /></IconButton>
<IconButton
size='small'
disabled={!entity}
onClick={() => {
update()
success()
}}
><Refresh /></IconButton>
</Box>}
/>
<Divider />
{entity
? <>
<CardContent>
<Grid container>
<Grid item lg={6} md={6} xl={6} xs={12}>
<TextField
size='small'
label={lang.entityEditor.customName}
value={customName}
sx={{ width: '90%' }}
onChange={e => setCustomName(e.target.value)}
/>
</Grid>
{values.map(it => <Grid item lg={6} md={6} xl={6} xs={12} key={it}>
<FormControlLabel
control={<Switch checked={(entity as any)[it]} />}
label={(lang.entityEditor as any)[it]}
onChange={(e: any) => plugin.emit('entity:set', (res: boolean) => {
action(res)
update()
}, id, it, e.target.checked)}
/>
</Grid>)}
</Grid>
</CardContent>
{entity.nbt != null && <Accordion sx={{ '&::before': { opacity: '1!important' } }} disableGutters>
<AccordionSummary expandIcon={<ExpandMore />}><Typography>NBT</Typography></AccordionSummary>
<AccordionDetails sx={{
padding: 0,
'& .CodeMirror': { width: '100%', height: 350 },
'& .CodeMirror-dialog, .CodeMirror-scrollbar-filler': { backgroundColor: theme.palette.background.paper + '!important' }
}}>
<UnControlled
value={entity.nbt}
options={{
mode: 'javascript',
phrases: lang.codeMirrorPhrases,
theme: theme.palette.mode === 'dark' ? 'material' : 'one-light'
}}
onChange={(_: any, __: any, data: string) => (entity.nbt = data)}
/>
</AccordionDetails>
</Accordion>}
</>
: <CardContent><EntitySelector /></CardContent>}
</Card>
</Grid>
{entity?.inventory?.length
? <Grid item lg={6} md={12} xl={6} xs={12}>
<Card>
<CardHeader
title={lang.entityEditor.container}
sx={{ position: 'relative' }}
/>
<Divider />
<CardContent sx={{ whiteSpace: 'nowrap', overflowX: 'auto', textAlign: 'center' }}>
{entity.inventory.map((it, i) => <React.Fragment key={i}><ItemViewer
item={it}
data={{ type: InvType.ENTITY, solt: i, id }}
onDrag={() => plugin.emit('entity:setItem', update, id, i, null, -1)}
onDrop={(item, obj) => plugin.emit('entity:setItem', update, id, i, JSON.stringify(item),
obj?.type === InvType.ENTITY && obj.id === id ? obj.solt : -1)}
onEdit={item => item !== false && plugin.emit('entity:setItem', updateWithAction, id, i, item && JSON.stringify(item), -1)}
/>{!((i + 1) % 9) && <br />}</React.Fragment>)}
</CardContent>
</Card>
</Grid>
: undefined}
</Grid>
</Container>
</Box>
}
Example #9
Source File: TableFieldNode.tsx From SeeQR with MIT License | 4 votes |
function TableField({ data }: TableFieldProps) {
const {
schemaStateCopy,
setSchemaState,
backendObj,
}: TableFieldDataObjectType = data;
const {
is_nullable,
constraint_type,
column_name,
data_type,
character_maximum_length,
foreign_column,
foreign_table,
}: ERTableColumnData = data.columnData;
const tableColumn: string = `${data.tableName}-${column_name}`;
const isNull: string = is_nullable;
let setTimeoutVariable;
// handles functionality of the drop down delete button
const handleDropColumn = (): void => {
// iterate through schema copy
for (let i = 0; i < schemaStateCopy.tableList.length; i += 1) {
// edit schema table for this current table
if (schemaStateCopy.tableList[i].table_name === data.tableName) {
let columnIndex: number;
// iterate through columns
for (
let j: number = 0;
j < schemaStateCopy.tableList[i].columns.length;
j += 1
) {
if (
schemaStateCopy.tableList[i].columns[j].column_name === column_name
) {
columnIndex = j;
// create alterTablesObject with AlterTablesObjecttype
const alterTablesObj: AlterTablesObjType = {
is_insertable_into: null,
table_catalog: schemaStateCopy.tableList[i].table_catalog,
table_name: schemaStateCopy.tableList[i].table_name,
new_table_name: null,
table_schema: schemaStateCopy.tableList[i].table_schema,
addColumns: [],
dropColumns: [],
alterColumns: [],
};
// create a deleteColumnsType object
const dropColumnObj: DropColumnsObjType = {
column_name: schemaStateCopy.tableList[i].columns[j].column_name,
};
// add deleteColumns obj to the alterTablesObj
alterTablesObj.dropColumns.push(dropColumnObj);
// update the backendObj
backendObj.current.updates.alterTables.push(alterTablesObj);
// alter schema state to remove the column
schemaStateCopy.tableList[i].columns.splice(columnIndex, 1);
// set the state
setSchemaState(schemaStateCopy);
return;
}
}
}
}
};
// handles functionality of the drop down update button
const handleUpdateColumn = (): void => {
// create an alterColumns object
const alterColumnsObj: AlterColumnsObjType = {
column_name,
character_maximum_length: null,
new_column_name: null,
add_constraint: [],
current_data_type: data_type,
data_type: null,
is_nullable: null,
drop_constraint: [],
rename_constraint: null,
table_schema: null,
table_name: null,
constraint_type: null
};
for (let i = 0; i < schemaStateCopy.tableList.length; i += 1) {
if (schemaStateCopy.tableList[i].table_name === data.tableName) {
// iterate through columns
for (
let j: number = 0;
j < schemaStateCopy.tableList[i].columns.length;
j += 1
) {
if (
schemaStateCopy.tableList[i].columns[j].column_name === column_name
) {
const alterTablesObj: AlterTablesObjType = {
is_insertable_into: null,
table_catalog: schemaStateCopy.tableList[i].table_catalog,
table_name: data.tableName,
new_table_name: null,
table_schema: schemaStateCopy.tableList[i].table_schema,
addColumns: [],
dropColumns: [],
alterColumns: [],
};
// handle column_name change
const columnNameInput = document.getElementById(
`type-input-column_name-${tableColumn}`
) as HTMLSelectElement;
if (column_name !== columnNameInput.value) {
alterColumnsObj.new_column_name = columnNameInput.value;
schemaStateCopy.tableList[i].columns[j].column_name =
columnNameInput.value;
schemaStateCopy.tableList[i].columns[j].new_column_name =
columnNameInput.value;
if (constraint_type === 'PRIMARY KEY') alterColumnsObj.rename_constraint = `pk_${alterTablesObj.table_name}${column_name}`;
if (constraint_type === 'FOREIGN KEY') alterColumnsObj.rename_constraint = `fk_${alterTablesObj.table_name}${column_name}`;
if (constraint_type === 'UNIQUE') alterColumnsObj.rename_constraint = `unique_${alterTablesObj.table_name}${column_name}`;
}
// handle isNullable change
const isNullable = document.getElementById(
`allow-null-chkbox-${tableColumn}`
) as HTMLInputElement;
const isNullableString: 'YES' | 'NO' = isNullable.checked ? 'YES' : 'NO';
schemaStateCopy.tableList[i].columns[j].is_nullable = isNullableString;
alterColumnsObj.is_nullable =
isNull !== isNullableString ? isNullableString : null;
// handle max_character_length change
const columnMaxCharacterLengthInput = document.getElementById(
`type-input-char_max_size-${tableColumn}`
) as HTMLSelectElement;
if (columnMaxCharacterLengthInput.value) {
if (
character_maximum_length !==
parseInt(columnMaxCharacterLengthInput.value, 10)
) {
alterColumnsObj.character_maximum_length = parseInt(
columnMaxCharacterLengthInput.value,
10
);
schemaStateCopy.tableList[i].columns[
j
].character_maximum_length = parseInt(
columnMaxCharacterLengthInput.value,
10
);
}
}
// handle data_type change
const dataTypeInput = document.getElementById(
`type-dd-${tableColumn}`
) as HTMLSelectElement;
if (
(data_type === 'character varying' ? 'varchar' : data_type) !==
dataTypeInput.value
) {
alterColumnsObj.data_type = dataTypeInput.value;
schemaStateCopy.tableList[i].columns[j].data_type =
dataTypeInput.value;
}
// handle add/Drop Constraint type
// create an empty AddConstraintObj
const addConstraintObj: AddConstraintObjType = {
constraint_type: null,
constraint_name: '',
foreign_table: null,
foreign_column: null,
};
/* handle primary key */
// get the primary key checkmark value
const pkCheckBox = document.getElementById(
`primary-key-chkbox-${tableColumn}`
) as HTMLInputElement;
// if constraint type is PK in state but checkbox is unchecked, drop the constraint
if (
constraint_type === 'PRIMARY KEY' &&
pkCheckBox.checked === false
) {
// modify state to remove constraint
schemaStateCopy.tableList[i].columns[j].constraint_type = null;
// add the PK constraint name to the drop constraint array
alterColumnsObj.drop_constraint.push(
`PK_${data.tableName + column_name}`
);
} // if constraint type is not in state but checkbox is checked, add the constraint
else if (
constraint_type !== 'PRIMARY KEY' &&
pkCheckBox.checked === true
) {
// modify state to remove constraint
schemaStateCopy.tableList[i].columns[j].constraint_type = 'PRIMARY KEY';
// create a copy in case multiple constraints are added
const addConstraintObjCopy: AddConstraintObjType = { ...addConstraintObj };
// name the constraint PK_<tableNamecolumn_name>
addConstraintObjCopy.constraint_name = `pk_${data.tableName + column_name
}`;
// assign the constraint_type to 'PRIMARY KEY'
addConstraintObjCopy.constraint_type = 'PRIMARY KEY';
// add the constraint obj to the alter columns obj
alterColumnsObj.add_constraint.push(addConstraintObjCopy);
}
// handle foreign key
const fkCheckBox = document.getElementById(
`foreign-key-chkbox-${tableColumn}`
) as HTMLInputElement;
// if constraint type is FK in state but checkbox is unchecked, drop the constraint
if (
constraint_type === 'FOREIGN KEY' &&
fkCheckBox.checked === false
) {
// modify state to remove constraint
schemaStateCopy.tableList[i].columns[j].constraint_type = null;
// add the fk constraint name to the drop constraint array
alterColumnsObj.drop_constraint.push(
`FK_${data.tableName + column_name}`
);
} else if (
constraint_type !== 'FOREIGN KEY' &&
fkCheckBox.checked === true
) {
// modify state to add constraint
schemaStateCopy.tableList[i].columns[j].constraint_type = 'FOREIGN KEY';
const addConstraintObjCopy = { ...addConstraintObj };
// name the constraint FK_<tableNameColumn_name>
addConstraintObjCopy.constraint_name = `fk_${data.tableName + column_name
}`;
// assign the constraint type to 'FOREIGN KEY'
addConstraintObjCopy.constraint_type = 'FOREIGN KEY';
// get the value of the drop down for foreign table
const foreignTableDD = document.getElementById(
`foreign-key-table-dd-${tableColumn}`
) as HTMLSelectElement;
// assign the constraintobjcopy to foreign table value
addConstraintObjCopy.foreign_table = foreignTableDD.value;
// get the value of the drop down for foreign column
const foreignColumnDD = document.getElementById(
`foreign-key-field-dd-${tableColumn}`
) as HTMLSelectElement;
// assign the constraintobjcopy to foreign column value
addConstraintObjCopy.foreign_column = foreignColumnDD.value;
// add the constraint obj to the alter columns obj
alterColumnsObj.add_constraint.push(addConstraintObjCopy);
}
// handle unique constraint
const uniqueCheckBox = document.getElementById(`unique-chkbox-${tableColumn}`) as HTMLInputElement;
if (constraint_type === 'UNIQUE' && uniqueCheckBox.checked === false) {
// modify state to remove constraint
schemaStateCopy.tableList[i].columns[j].constraint_type = null;
// add the unique constraint name to the drop constraint array
alterColumnsObj.drop_constraint.push(
`unique_${data.tableName + column_name}`
);
}
else if (constraint_type !== 'UNIQUE' && uniqueCheckBox.checked === true) {
// modify state to add constraint
schemaStateCopy.tableList[i].columns[j].constraint_type = 'UNIQUE';
// create a copy in case multiple constraints are added
const addConstraintObjCopy: AddConstraintObjType = { ...addConstraintObj };
// name the constraint PK_<tableNamecolumn_name>
addConstraintObjCopy.constraint_name = `unique_${data.tableName + column_name
}`;
// assign the constraint_type to 'UNIQUE'
addConstraintObjCopy.constraint_type = 'UNIQUE';
// add the constraint obj to the alter columns obj add_constraint array
alterColumnsObj.add_constraint.push(addConstraintObjCopy);
}
// add the alterTablesObj
alterTablesObj.alterColumns.push(alterColumnsObj);
// update the backendObj
backendObj.current.updates.alterTables.push(alterTablesObj);
setSchemaState(schemaStateCopy);
return;
}
}
}
}
};
// autopopulates the fk field options from state
const createFieldOptions = (): string[] => {
const options: string[] = [];
// if foreign_table is NOT provided return column names of first table in otherTables
if (foreign_table == null && data.otherTables.length > 0) {
options.push(...data.otherTables[0].column_names);
}
// if foreign_table is provided return associated column_names
data.otherTables.forEach((table) => {
if (table.table_name === foreign_table) {
options.push(...table.column_names);
}
});
return options;
};
// disable the dropdown menus for fk table and field when fk checkbox is not checked
const disableForeignKeyMenuHandler = (isChecked) => {
const tableID: string = `foreign-key-table-dd-${tableColumn}`;
const fieldID: string = `foreign-key-field-dd-${tableColumn}`;
const tableDD = document.getElementById(tableID) as HTMLSelectElement;
const fieldDD = document.getElementById(fieldID) as HTMLSelectElement;
tableDD.disabled = !isChecked;
fieldDD.disabled = !isChecked;
};
// disable allow null checkbox when the column is either a foreign key or primary key
const disableAllowNullHandler = () => {
const pkID: string = `primary-key-chkbox-${tableColumn}`;
const pkCheckBox = document.getElementById(pkID) as HTMLInputElement;
const isPkChecked: boolean = pkCheckBox.checked;
const fkID: string = `foreign-key-chkbox-${tableColumn}`;
const fkCheckBox = document.getElementById(fkID) as HTMLInputElement;
const isFkChecked: boolean = fkCheckBox.checked;
const allowNullID: string = `allow-null-chkbox-${tableColumn}`;
const allowNullCheckBox = document.getElementById(
allowNullID
) as HTMLSelectElement;
allowNullCheckBox.disabled = isFkChecked || isPkChecked;
};
// create a state for the foreign key drop down options
const [fkOptions, setFkOptions] = useState<string[]>(createFieldOptions());
const [isAccordionExpanded, setAccordionExpanded] = useState(false);
// This function handles the click functionality of clicking the accordion
const handleAccordionClick = (): void => {
setAccordionExpanded(!isAccordionExpanded);
};
// This function closes the accordion expansion on mouse leave
const handleMouseLeave = (): void => {
setTimeoutVariable = setTimeout(() => {
setAccordionExpanded(false);
}, 1000);
};
// This function clears the timeout if the mouse reenters
// within the timeout time
const handleMouseEnter = (): void => {
if (setTimeoutVariable) {
clearTimeout(setTimeoutVariable);
}
};
return (
<div>
{constraint_type === 'PRIMARY KEY' ? (
<Handle
type="target"
position={Position.Left}
style={{ background: '#fff' }}
/>
) : (
<Handle type="source" position={Position.Right} />
)}
<Accordion
expanded={isAccordionExpanded}
onMouseLeave={handleMouseLeave}
onMouseEnter={handleMouseEnter}
sx={{ width: 350 }}
>
<AccordionSummary
expandIcon={<ExpandMoreIcon onClick={handleAccordionClick} />}
>
<div className="field-summary-wrapper">
<p id="column-name">{column_name}</p>
<p id="data-type">
{data_type === 'character varying' ? 'varchar' : data_type}
</p>
</div>
</AccordionSummary>
<AccordionDetails>
<TableFieldInput
idName={`type-input-column_name-${tableColumn}`}
label="Name"
defaultValue={column_name}
/>
<TableFieldDropDown
label="Type"
idName={`type-dd-${tableColumn}`}
defaultValue={data_type}
otherTables={data.otherTables}
options={['varchar', 'bigint', 'integer', 'date']}
schemaStateCopy={schemaStateCopy}
setSchemaState={setSchemaState}
/>
<TableFieldInput
idName={`type-input-char_max_size-${tableColumn}`}
label="Size"
defaultValue={character_maximum_length}
/>
<br />
<TableFieldCheckBox
label="Foreign Key"
idName={`foreign-key-chkbox-${tableColumn}`}
isChecked={foreign_table != null}
onChange={[disableForeignKeyMenuHandler, disableAllowNullHandler]}
/>
<TableFieldDropDown
label="Table"
idName={`foreign-key-table-dd-${tableColumn}`}
isDisabled={foreign_table == null}
defaultValue={foreign_table}
options={data.otherTables.map((table) => table.table_name)}
setFkOptions={setFkOptions}
otherTables={data.otherTables}
schemaStateCopy={schemaStateCopy}
setSchemaState={setSchemaState}
/>
<TableFieldDropDown
label="Field"
idName={`foreign-key-field-dd-${tableColumn}`}
isDisabled={foreign_table == null}
defaultValue={foreign_column}
options={fkOptions}
otherTables={data.otherTables}
schemaStateCopy={schemaStateCopy}
setSchemaState={setSchemaState}
/>
<br />
<TableFieldCheckBox
idName={`primary-key-chkbox-${tableColumn}`}
label="Primary Key"
isChecked={constraint_type === 'PRIMARY KEY'}
onChange={disableAllowNullHandler}
/>
<TableFieldCheckBox
idName={`allow-null-chkbox-${tableColumn}`}
label="Allow Null"
isChecked={isNull === 'YES'}
/>
<TableFieldCheckBox
idName={`unique-chkbox-${tableColumn}`}
label="Unique"
isChecked={constraint_type === 'UNIQUE'}
/>
<br />
<div>
<StyledButton id="update-btn" onClick={handleUpdateColumn}>
SAVE
</StyledButton>
<StyledButton id="delete-btn" onClick={handleDropColumn}>
DELETE
</StyledButton>
</div>
</AccordionDetails>
</Accordion>
</div>
);
}