brunner56's picture
implement app
0bfe2e3
import React, { useState } from 'react';
import styles from './AddonsList.module.css';
import { AddonDetail, Config } from '@aiostreams/types';
import CredentialInput from './CredentialInput';
import MultiSelect from './MutliSelect';
interface AddonsListProps {
choosableAddons: string[];
addonDetails: AddonDetail[];
addons: Config['addons'];
setAddons: (addons: Config['addons']) => void;
}
const AddonsList: React.FC<AddonsListProps> = ({
choosableAddons,
addonDetails,
addons,
setAddons,
}) => {
const [selectedAddon, setSelectedAddon] = useState<string>('');
const addAddon = () => {
if (selectedAddon) {
setAddons([...addons, { id: selectedAddon, options: {} }]);
setSelectedAddon('');
}
};
const removeAddon = (index: number) => {
const newAddons = [...addons];
newAddons.splice(index, 1);
setAddons(newAddons);
};
const updateOption = (
addonIndex: number,
optionKey: string,
value?: string
) => {
const newAddons = [...addons];
newAddons[addonIndex].options[optionKey] = value;
setAddons(newAddons);
};
const moveAddon = (index: number, direction: 'up' | 'down') => {
const newAddons = [...addons];
const [movedAddon] = newAddons.splice(index, 1);
newAddons.splice(direction === 'up' ? index - 1 : index + 1, 0, movedAddon);
setAddons(newAddons);
};
return (
<div className={styles.container}>
<div className={styles.addonSelector}>
<select
value={selectedAddon}
onChange={(e) => setSelectedAddon(e.target.value)}
>
<option value="">Select an addon</option>
{choosableAddons.map((addon) => {
const addonDetail = addonDetails.find(
(detail) => detail.id === addon
);
if (addonDetail) {
return (
<option key={addon} value={addon}>
{addonDetail.name}
</option>
);
}
return null;
})}
</select>
<button onClick={addAddon}>Add Addon</button>
</div>
{addons.map((addon, index) => {
const details = addonDetails.find((detail) => detail.id === addon.id);
return (
<div key={index} className={styles.card}>
<div className={styles.cardHeader}>
<span style={{ fontSize: '1.2em', fontWeight: 'bold' }}>
{details?.name}
</span>
<div className={styles.actions}>
{index > 0 && (
<button
className={styles.actionButton}
onClick={() => moveAddon(index, 'up')}
>
<svg
fill="#ffffff"
version="1.1"
id="Capa_1"
xmlns="http://www.w3.org/2000/svg"
xmlnsXlink="http://www.w3.org/1999/xlink"
width="24px"
height="24px"
viewBox="0 0 96.154 96.154"
xmlSpace="preserve"
stroke="#ffffff"
transform="matrix(1, 0, 0, -1, 0, 0)"
>
<g id="SVGRepo_bgCarrier" strokeWidth="0"></g>
<g
id="SVGRepo_tracerCarrier"
strokeLinecap="round"
strokeLinejoin="round"
></g>
<g id="SVGRepo_iconCarrier">
{' '}
<g>
{' '}
<path d="M0.561,20.971l45.951,57.605c0.76,0.951,2.367,0.951,3.127,0l45.956-57.609c0.547-0.689,0.709-1.716,0.414-2.61 c-0.061-0.187-0.129-0.33-0.186-0.437c-0.351-0.65-1.025-1.056-1.765-1.056H2.093c-0.736,0-1.414,0.405-1.762,1.056 c-0.059,0.109-0.127,0.253-0.184,0.426C-0.15,19.251,0.011,20.28,0.561,20.971z"></path>{' '}
</g>{' '}
</g>
</svg>
</button>
)}
{index < addons.length - 1 && (
<button
className={styles.actionButton}
onClick={() => moveAddon(index, 'down')}
>
<svg
fill="#ffffff"
version="1.1"
id="Capa_1"
xmlns="http://www.w3.org/2000/svg"
width="24px"
height="24px"
viewBox="0 0 96.154 96.154"
stroke="#ffffff"
>
<g id="SVGRepo_bgCarrier" strokeWidth="0"></g>
<g
id="SVGRepo_tracerCarrier"
strokeLinecap="round"
strokeLinejoin="round"
></g>
<g id="SVGRepo_iconCarrier">
{' '}
<g>
{' '}
<path d="M0.561,20.971l45.951,57.605c0.76,0.951,2.367,0.951,3.127,0l45.956-57.609c0.547-0.689,0.709-1.716,0.414-2.61 c-0.061-0.187-0.129-0.33-0.186-0.437c-0.351-0.65-1.025-1.056-1.765-1.056H2.093c-0.736,0-1.414,0.405-1.762,1.056 c-0.059,0.109-0.127,0.253-0.184,0.426C-0.15,19.251,0.011,20.28,0.561,20.971z"></path>{' '}
</g>{' '}
</g>
</svg>
</button>
)}
<button
onClick={() => removeAddon(index)}
className={styles.actionButton}
>
</button>
</div>
</div>
<div className={styles.cardBody}>
{details?.options
?.filter((option) => option.type !== 'deprecated')
?.map((option) => (
<div key={option.id} className={styles.option}>
<label>
{option.label}
{option.required && (
<span className={styles.required}>
<small>
<em>*Required Field</em>
</small>
</span>
)}
{option.type === 'checkbox' && (
<input
type="checkbox"
checked={addon.options[option.id] === 'true'}
onChange={(e) =>
updateOption(
index,
option.id,
e.target.checked ? 'true' : undefined
)
}
className={styles.checkbox}
/>
)}
</label>
{option.description && <small>{option.description}</small>}
{option.type === 'text' &&
(option.secret ? (
<CredentialInput
credential={addon.options[option.id] || ''}
setCredential={(value) =>
updateOption(
index,
option.id,
value ? value : undefined
)
}
/>
) : (
<input
type="text"
value={(addon.options[option.id] as string) || ''}
onChange={(e) =>
updateOption(
index,
option.id,
e.target.value ? e.target.value : undefined
)
}
className={styles.textInput}
/>
))}
{option.type === 'select' && (
<select
value={addon.options[option.id] || ''}
onChange={(e) =>
updateOption(
index,
option.id,
e.target.value ? e.target.value : undefined
)
}
className={styles.textInput}
>
<option value="">None</option>
{option.options.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</select>
)}
{option.type === 'number' && (
<input
type="number"
value={addon.options[option.id] || ''}
onChange={(e) =>
updateOption(
index,
option.id,
e.target.value ? e.target.value : undefined
)
}
className={styles.textInput}
/>
)}
{option.type === 'multiSelect' && (
<MultiSelect
options={option.options}
setValues={(values) =>
updateOption(index, option.id, values.join(','))
}
values={addon.options[option.id]?.split(',') || []}
/>
)}
</div>
))}
</div>
</div>
);
})}
</div>
);
};
export default AddonsList;