/ packages / ui / src / components / molecules / ProfileSelector.tsx
ProfileSelector.tsx
  1  import { Box, Button, ButtonGroup, Card, CardActions, CardHeader, Container, Stack } from "@mui/material";
  2  import { useComputed, useSignal, useSignalEffect } from "@preact/signals-react";
  3  import { useService } from '../../context';
  4  import { uuid } from 'ipmc-core';
  5  import { IConfigurationService, IConfigurationServiceSymbol, IDialogService, IDialogServiceSymbol, IFileExportService, IFileExportServiceSymbol, IPopupService, IPopupServiceSymbol, IProfile } from 'ipmc-interfaces';
  6  import React from "react";
  7  import { useTranslation } from '../../hooks/useTranslation';
  8  import { ProfileEditor } from "./ProfileEditor";
  9  
 10  export function ProfileSelector(props: { profile?: IProfile, switchProfile: (name: string) => void; }) {
 11  	const _t = useTranslation();
 12  	const fileExportService = useService<IFileExportService>(IFileExportServiceSymbol);
 13  	const popupService = useService<IPopupService>(IPopupServiceSymbol);
 14  	const dialogService = useService<IDialogService>(IDialogServiceSymbol);
 15  	const configService = useService<IConfigurationService>(IConfigurationServiceSymbol);
 16  
 17  	const profiles = useSignal<(IProfile)[]>([]);
 18  
 19  	useSignalEffect(() => {
 20  		loadProfiles();
 21  	});
 22  
 23  	async function loadProfiles(): Promise<void> {
 24  		profiles.value = await Promise.all((await configService.getProfiles()).map(async (p) => ({
 25  			...(await configService.getProfile(p)),
 26  			id: p,
 27  		})));
 28  	}
 29  
 30  	const content = useComputed(() => profiles.value.map(p => (
 31  		<Card key={p.id}>
 32  			<CardHeader title={p.name} subheader={p.id} />
 33  			<CardActions>
 34  				<ButtonGroup fullWidth={true}>
 35  					<Button
 36  						color={"error"}
 37  						onClick={() => {
 38  							dialogService.boolDialog({
 39  								title: _t('ConfirmProfileDeletion')
 40  							})
 41  								.then(r => {
 42  									if (r) {
 43  										configService.removeProfile(p.id);
 44  										loadProfiles();
 45  									}
 46  								});
 47  						}}
 48  					>{_t('Delete')}</Button>
 49  					<Button
 50  						onClick={() => {
 51  							fileExportService.exportJson(p, `${p.name}.profile.json`);
 52  						}}
 53  					>{_t('Export')}</Button>
 54  					<Button
 55  						onClick={() => {
 56  							popupService.show({
 57  								content: (close) => (
 58  									<ProfileEditor
 59  										profile={p}
 60  										onCancel={close}
 61  										onSave={() => {
 62  											close();
 63  											loadProfiles();
 64  										}}
 65  									/>
 66  								)
 67  							});
 68  						}}
 69  					>{_t('Edit')}</Button>
 70  					<Button
 71  						variant={'contained'}
 72  						onClick={() => props.switchProfile(p.id)}
 73  					>{_t('Start')}</Button>
 74  				</ButtonGroup>
 75  			</CardActions>
 76  		</Card>
 77  	)));
 78  
 79  	return (
 80  		<Container>
 81  			<Stack spacing={1}>
 82  				{content}
 83  				<Box>
 84  					<Button onClick={() => {
 85  						popupService.show({
 86  							content: (close) => (
 87  								<ProfileEditor
 88  									profile={{
 89  										id: uuid(),
 90  										type: 'internal',
 91  										name: '',
 92  										libraries: [],
 93  									}}
 94  									onCancel={close}
 95  									onSave={() => {
 96  										close();
 97  										loadProfiles();
 98  									}}
 99  								/>
100  							)
101  						});
102  					}}>{_t('AddProfile')}</Button>
103  					<Button onClick={() => {
104  						dialogService.fileDialog({
105  							title: _t('ChooseImportFile'),
106  							accept: 'application/json',
107  						})
108  							.then(r => {
109  								const id = uuid();
110  								const file = r[0];
111  								const fileReader = new FileReader();
112  								fileReader.onloadend = () => {
113  									configService.setProfile(id, { ...JSON.parse(fileReader.result as string), id: id });
114  									loadProfiles();
115  								};
116  								fileReader.readAsText(file);
117  							});
118  					}}>{_t('ImportProfile')}</Button>
119  				</Box>
120  			</Stack>
121  		</Container>
122  	);
123  }