feat: change ui to include cred fields
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { GenericModal } from "../ui/GenericModal";
|
import { GenericModal } from "../ui/GenericModal";
|
||||||
import { TextField, Typography, Box, Button } from "@mui/material";
|
import { TextField, Typography, Box, Button, IconButton, InputAdornment } from "@mui/material";
|
||||||
|
import { Visibility, VisibilityOff } from '@mui/icons-material';
|
||||||
import { modalStyle } from "../recorder/AddWhereCondModal";
|
import { modalStyle } from "../recorder/AddWhereCondModal";
|
||||||
import { useGlobalInfoStore } from '../../context/globalInfo';
|
import { useGlobalInfoStore } from '../../context/globalInfo';
|
||||||
import { getStoredRecording, updateRecording } from '../../api/storage';
|
import { getStoredRecording, updateRecording } from '../../api/storage';
|
||||||
@@ -25,6 +26,14 @@ interface RobotEditOptions {
|
|||||||
limit?: number;
|
limit?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Credentials {
|
||||||
|
[key: string]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CredentialVisibility {
|
||||||
|
[key: string]: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
interface ScheduleConfig {
|
interface ScheduleConfig {
|
||||||
runEvery: number;
|
runEvery: number;
|
||||||
runEveryUnit: 'MINUTES' | 'HOURS' | 'DAYS' | 'WEEKS' | 'MONTHS';
|
runEveryUnit: 'MINUTES' | 'HOURS' | 'DAYS' | 'WEEKS' | 'MONTHS';
|
||||||
@@ -48,6 +57,7 @@ export interface RobotSettings {
|
|||||||
google_access_token?: string | null;
|
google_access_token?: string | null;
|
||||||
google_refresh_token?: string | null;
|
google_refresh_token?: string | null;
|
||||||
schedule?: ScheduleConfig | null;
|
schedule?: ScheduleConfig | null;
|
||||||
|
isLogin?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RobotSettingsProps {
|
interface RobotSettingsProps {
|
||||||
@@ -60,7 +70,17 @@ interface RobotSettingsProps {
|
|||||||
export const RobotEditModal = ({ isOpen, handleStart, handleClose, initialSettings }: RobotSettingsProps) => {
|
export const RobotEditModal = ({ isOpen, handleStart, handleClose, initialSettings }: RobotSettingsProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [robot, setRobot] = useState<RobotSettings | null>(null);
|
const [robot, setRobot] = useState<RobotSettings | null>(null);
|
||||||
|
const [credentials, setCredentials] = useState<Credentials>({});
|
||||||
const { recordingId, notify } = useGlobalInfoStore();
|
const { recordingId, notify } = useGlobalInfoStore();
|
||||||
|
const [credentialSelectors, setCredentialSelectors] = useState<string[]>([]);
|
||||||
|
const [showPasswords, setShowPasswords] = useState<CredentialVisibility>({});
|
||||||
|
|
||||||
|
const handleClickShowPassword = (selector: string) => {
|
||||||
|
setShowPasswords(prev => ({
|
||||||
|
...prev,
|
||||||
|
[selector]: !prev[selector]
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isOpen) {
|
if (isOpen) {
|
||||||
@@ -68,6 +88,39 @@ export const RobotEditModal = ({ isOpen, handleStart, handleClose, initialSettin
|
|||||||
}
|
}
|
||||||
}, [isOpen]);
|
}, [isOpen]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (robot?.recording?.workflow) {
|
||||||
|
const selectors = findCredentialSelectors(robot.recording.workflow);
|
||||||
|
setCredentialSelectors(selectors);
|
||||||
|
|
||||||
|
// Initialize credentials state
|
||||||
|
const initialCredentials: Record<string, string> = {};
|
||||||
|
selectors.forEach(selector => {
|
||||||
|
initialCredentials[selector] = '';
|
||||||
|
});
|
||||||
|
setCredentials(initialCredentials);
|
||||||
|
}
|
||||||
|
}, [robot]);
|
||||||
|
|
||||||
|
const findCredentialSelectors = (workflow: WhereWhatPair[]): string[] => {
|
||||||
|
const selectors = new Set<string>();
|
||||||
|
|
||||||
|
workflow?.forEach(step => {
|
||||||
|
step.what?.forEach(action => {
|
||||||
|
if (
|
||||||
|
(action.action === 'type' || action.action === 'press') &&
|
||||||
|
action.args &&
|
||||||
|
action.args[0] &&
|
||||||
|
typeof action.args[0] === 'string'
|
||||||
|
) {
|
||||||
|
selectors.add(action.args[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return Array.from(selectors);
|
||||||
|
};
|
||||||
|
|
||||||
const getRobot = async () => {
|
const getRobot = async () => {
|
||||||
if (recordingId) {
|
if (recordingId) {
|
||||||
const robot = await getStoredRecording(recordingId);
|
const robot = await getStoredRecording(recordingId);
|
||||||
@@ -83,6 +136,13 @@ export const RobotEditModal = ({ isOpen, handleStart, handleClose, initialSettin
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleCredentialChange = (selector: string, value: string) => {
|
||||||
|
setCredentials(prev => ({
|
||||||
|
...prev,
|
||||||
|
[selector]: value
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
const handleLimitChange = (newLimit: number) => {
|
const handleLimitChange = (newLimit: number) => {
|
||||||
setRobot((prev) => {
|
setRobot((prev) => {
|
||||||
if (!prev) return prev;
|
if (!prev) return prev;
|
||||||
@@ -111,6 +171,7 @@ export const RobotEditModal = ({ isOpen, handleStart, handleClose, initialSettin
|
|||||||
const payload = {
|
const payload = {
|
||||||
name: robot.recording_meta.name,
|
name: robot.recording_meta.name,
|
||||||
limit: robot.recording.workflow[0]?.what[0]?.args?.[0]?.limit,
|
limit: robot.recording.workflow[0]?.what[0]?.args?.[0]?.limit,
|
||||||
|
credentials: credentials,
|
||||||
};
|
};
|
||||||
|
|
||||||
const success = await updateRecording(robot.recording_meta.id, payload);
|
const success = await updateRecording(robot.recording_meta.id, payload);
|
||||||
@@ -170,6 +231,38 @@ export const RobotEditModal = ({ isOpen, handleStart, handleClose, initialSettin
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{(robot.isLogin && credentialSelectors.length > 0) && (
|
||||||
|
<>
|
||||||
|
<Typography variant="h6" style={{ marginBottom: '20px' }}>
|
||||||
|
{t('Login Credentials')}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
{credentialSelectors.map((selector) => (
|
||||||
|
<TextField
|
||||||
|
key={selector}
|
||||||
|
type={showPasswords[selector] ? 'text' : 'password'}
|
||||||
|
label={`Credential for ${selector}`}
|
||||||
|
value={credentials[selector] || ''}
|
||||||
|
onChange={(e) => handleCredentialChange(selector, e.target.value)}
|
||||||
|
style={{ marginBottom: '20px' }}
|
||||||
|
InputProps={{
|
||||||
|
endAdornment: (
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<IconButton
|
||||||
|
aria-label="toggle password visibility"
|
||||||
|
onClick={() => handleClickShowPassword(selector)}
|
||||||
|
edge="end"
|
||||||
|
>
|
||||||
|
{showPasswords[selector] ? <Visibility /> : <VisibilityOff />}
|
||||||
|
</IconButton>
|
||||||
|
</InputAdornment>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
<Box mt={2} display="flex" justifyContent="flex-end">
|
<Box mt={2} display="flex" justifyContent="flex-end">
|
||||||
<Button variant="contained" color="primary" onClick={handleSave}>
|
<Button variant="contained" color="primary" onClick={handleSave}>
|
||||||
{t('robot_edit.save')}
|
{t('robot_edit.save')}
|
||||||
|
|||||||
Reference in New Issue
Block a user