fix2
This commit is contained in:
@@ -1,42 +1 @@
|
||||
#root {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 6em;
|
||||
padding: 1.5em;
|
||||
will-change: filter;
|
||||
transition: filter 300ms;
|
||||
}
|
||||
.logo:hover {
|
||||
filter: drop-shadow(0 0 2em #646cffaa);
|
||||
}
|
||||
.logo.react:hover {
|
||||
filter: drop-shadow(0 0 2em #61dafbaa);
|
||||
}
|
||||
|
||||
@keyframes logo-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
a:nth-of-type(2) .logo {
|
||||
animation: logo-spin infinite 20s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 2em;
|
||||
}
|
||||
|
||||
.read-the-docs {
|
||||
color: #888;
|
||||
}
|
||||
/* App-specific styles can be added here in the future. */
|
@@ -30,6 +30,7 @@ const MeetingDetailPage = () => {
|
||||
const [isEditingSummary, setIsEditingSummary] = useState(false);
|
||||
const [editData, setEditData] = useState({});
|
||||
const [summaryTask, setSummaryTask] = useState(null);
|
||||
const [previewTask, setPreviewTask] = useState(null); // State for the preview task
|
||||
|
||||
const [actionItems, setActionItems] = useState([]);
|
||||
const [users, setUsers] = useState([]);
|
||||
@@ -39,7 +40,6 @@ const MeetingDetailPage = () => {
|
||||
const [isAddActionItemOpen, setIsAddActionItemOpen] = useState(false);
|
||||
const [newActionItem, setNewActionItem] = useState({ action: '', owner_id: '', due_date: '', item: '' });
|
||||
const [previewedItems, setPreviewedItems] = useState([]);
|
||||
const [isPreviewLoading, setIsPreviewLoading] = useState(false);
|
||||
|
||||
const fetchMeetingData = useCallback(async () => {
|
||||
try {
|
||||
@@ -70,33 +70,44 @@ const MeetingDetailPage = () => {
|
||||
fetchUsers();
|
||||
}, []);
|
||||
|
||||
// Combined polling effect for both summary and preview tasks
|
||||
useEffect(() => {
|
||||
let intervalId = null;
|
||||
if (summaryTask && (summaryTask.state === 'PENDING' || summaryTask.state === 'PROGRESS')) {
|
||||
intervalId = setInterval(async () => {
|
||||
try {
|
||||
const updatedTask = await pollTaskStatus(summaryTask.status_url);
|
||||
if (['SUCCESS', 'FAILURE', 'REVOKED'].includes(updatedTask.state)) {
|
||||
clearInterval(intervalId);
|
||||
const task = summaryTask || previewTask;
|
||||
if (!task || !['PENDING', 'PROGRESS'].includes(task.state)) return;
|
||||
|
||||
const intervalId = setInterval(async () => {
|
||||
try {
|
||||
const updatedTask = await pollTaskStatus(task.status_url);
|
||||
|
||||
if (task === summaryTask) setSummaryTask(prev => ({...prev, ...updatedTask}));
|
||||
if (task === previewTask) setPreviewTask(prev => ({...prev, ...updatedTask}));
|
||||
|
||||
if (['SUCCESS', 'FAILURE', 'REVOKED'].includes(updatedTask.state)) {
|
||||
clearInterval(intervalId);
|
||||
if (summaryTask) { // Handle summary success
|
||||
setSummaryTask(null);
|
||||
if (updatedTask.state === 'SUCCESS' && updatedTask.info.summary) {
|
||||
// Directly update the summary instead of refetching everything
|
||||
setMeeting(prevMeeting => ({...prevMeeting, summary: updatedTask.info.summary}));
|
||||
setEditData(prevEditData => ({...prevEditData, summary: updatedTask.info.summary}));
|
||||
} else {
|
||||
// Fallback to refetch if something goes wrong or task fails
|
||||
fetchMeetingData();
|
||||
setMeeting(prev => ({...prev, summary: updatedTask.info.summary}));
|
||||
setEditData(prev => ({...prev, summary: updatedTask.info.summary}));
|
||||
}
|
||||
} else if (previewTask) { // Handle preview success
|
||||
setPreviewTask(null);
|
||||
if (updatedTask.state === 'SUCCESS' && updatedTask.info.items) {
|
||||
setPreviewedItems(updatedTask.info.items);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Polling failed:', err);
|
||||
clearInterval(intervalId);
|
||||
setSummaryTask(null);
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Polling failed:', err);
|
||||
clearInterval(intervalId);
|
||||
if (summaryTask) setSummaryTask(null);
|
||||
if (previewTask) setPreviewTask(null);
|
||||
}
|
||||
}, 2000);
|
||||
|
||||
return () => clearInterval(intervalId);
|
||||
}, [summaryTask, fetchMeetingData]);
|
||||
}, [summaryTask, previewTask, fetchMeetingData]);
|
||||
|
||||
|
||||
const handleSave = async (field, value) => {
|
||||
try {
|
||||
@@ -118,29 +129,25 @@ const MeetingDetailPage = () => {
|
||||
};
|
||||
|
||||
const handleGenerateSummary = async () => {
|
||||
// FIX 3: Set loading state immediately to give instant feedback
|
||||
setSummaryTask({ state: 'PENDING', info: 'Initializing summary task...' });
|
||||
try {
|
||||
const taskInfo = await summarizeMeeting(meetingId);
|
||||
setSummaryTask({ ...taskInfo, state: 'PENDING' });
|
||||
} catch (err) {
|
||||
setError('Failed to start summary generation.');
|
||||
// Clear the temporary loading state on error
|
||||
setSummaryTask(null);
|
||||
}
|
||||
};
|
||||
|
||||
const handlePreviewActionItems = async () => {
|
||||
const textToPreview = meeting?.summary || meeting?.transcript;
|
||||
if (!textToPreview) return;
|
||||
setIsPreviewLoading(true);
|
||||
setPreviewTask({ state: 'PENDING', info: 'Initializing preview task...' });
|
||||
try {
|
||||
const result = await previewActionItems(textToPreview);
|
||||
setPreviewedItems(result.items || []);
|
||||
// This now calls the async task endpoint
|
||||
const taskInfo = await previewActionItems(meetingId);
|
||||
setPreviewTask({ ...taskInfo, state: 'PENDING' });
|
||||
} catch (err) {
|
||||
setError('Failed to generate action item preview.');
|
||||
} finally {
|
||||
setIsPreviewLoading(false);
|
||||
setError('Failed to start action item preview.');
|
||||
setPreviewTask(null);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -149,7 +156,7 @@ const MeetingDetailPage = () => {
|
||||
try {
|
||||
await batchSaveActionItems(meetingId, previewedItems);
|
||||
setPreviewedItems([]);
|
||||
fetchMeetingData();
|
||||
fetchMeetingData(); // Refetch to update the main action items list
|
||||
} catch (err) {
|
||||
setError('Failed to save action items.');
|
||||
}
|
||||
@@ -235,20 +242,18 @@ const MeetingDetailPage = () => {
|
||||
</Paper>
|
||||
)}
|
||||
|
||||
{canManageMeeting && (
|
||||
<Box sx={{ mt: 3 }}>
|
||||
<Button variant="outlined" startIcon={<PreviewIcon />} onClick={handlePreviewActionItems} disabled={isPreviewLoading || isEditingSummary || (!meeting.summary && !meeting.transcript)}>{isPreviewLoading ? <CircularProgress size={24} /> : "Preview Action Items"}</Button>
|
||||
{previewedItems.length > 0 && (
|
||||
<Box>
|
||||
<TableContainer component={Paper} sx={{ mt: 2 }}><Table size="small">
|
||||
<TableHead><TableRow><TableCell>Context/Item</TableCell><TableCell>Action</TableCell><TableCell>Owner</TableCell><TableCell>Due Date</TableCell></TableRow></TableHead>
|
||||
<TableBody>{previewedItems.map((item, index) => (<TableRow key={index}><TableCell>{item.item}</TableCell><TableCell>{item.action}</TableCell><TableCell>{item.owner}</TableCell><TableCell>{item.due_date}</TableCell></TableRow>))}</TableBody>
|
||||
</Table></TableContainer>
|
||||
<Button variant="contained" sx={{ mt: 2 }} onClick={handleBatchSave}>Save All to List</Button>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
{canManageMeeting && (<Box sx={{ mt: 3 }}>
|
||||
<Button variant="outlined" startIcon={<PreviewIcon />} onClick={handlePreviewActionItems} disabled={previewTask || summaryTask || isEditingSummary || (!meeting.summary && !meeting.transcript)}>
|
||||
{previewTask ? <CircularProgress size={24} /> : "Preview Action Items"}
|
||||
</Button>
|
||||
{previewedItems.length > 0 && (<Box>
|
||||
<TableContainer component={Paper} sx={{ mt: 2 }}><Table size="small">
|
||||
<TableHead><TableRow><TableCell>Context/Item</TableCell><TableCell>Action</TableCell><TableCell>Owner</TableCell><TableCell>Due Date</TableCell></TableRow></TableHead>
|
||||
<TableBody>{previewedItems.map((item, index) => (<TableRow key={index}><TableCell>{item.item}</TableCell><TableCell>{item.action}</TableCell><TableCell>{item.owner}</TableCell><TableCell>{item.due_date}</TableCell></TableRow>))}</TableBody>
|
||||
</Table></TableContainer>
|
||||
<Button variant="contained" sx={{ mt: 2 }} onClick={handleBatchSave}>Save All to List</Button>
|
||||
</Box>)}
|
||||
</Box>)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
|
@@ -76,8 +76,8 @@ export const translateText = (text, target_language) =>
|
||||
unwrap(api.post('/tools/translate_text', { text, target_language }));
|
||||
|
||||
// --- AI Previews (for Meeting Page) ---
|
||||
export const previewActionItems = (text) =>
|
||||
unwrap(api.post('/action-items/preview', { text }));
|
||||
export const previewActionItems = (meetingId) =>
|
||||
unwrap(api.post(`/meetings/${meetingId}/preview-actions`));
|
||||
|
||||
// --- Action Items ---
|
||||
export const getActionItemsForMeeting = (meetingId) => unwrap(api.get(`/meetings/${meetingId}/action_items`));
|
||||
|
Reference in New Issue
Block a user