From 3c257c23a904021a610188a91c1ed24497e61c1b Mon Sep 17 00:00:00 2001 From: Ludwig Kristoffersson Date: Wed, 8 Mar 2023 01:21:08 +0100 Subject: [PATCH 1/3] add only_failed option to lecture endpoint that returns only lectures with the failed state --- api/routers/lectures.py | 5 +++++ db/crud.py | 12 ++++++++++++ 2 files changed, 17 insertions(+) diff --git a/api/routers/lectures.py b/api/routers/lectures.py index 94983ce..5e3c42c 100644 --- a/api/routers/lectures.py +++ b/api/routers/lectures.py @@ -13,6 +13,7 @@ get_lecture_by_public_id_and_language, delete_lecture_course_relation, get_all_denied_lectures, + get_all_failed_lectures, get_unfinished_lectures, find_course_code, get_all_lectures, @@ -86,6 +87,7 @@ def get_all( summary: Union[bool, None] = None, only_unfinished: Union[bool, None] = None, only_denied: Union[bool, None] = None, + only_failed: Union[bool, None] = None, include_denied: Union[bool, None] = False, include_failed: Union[bool, None] = False, random: Union[bool, None] = None, @@ -95,6 +97,9 @@ def get_all( elif only_denied: include_denied = True lectures = get_all_denied_lectures() + elif only_failed: + include_failed = True + lectures = get_all_failed_lectures() else: lectures = get_all_lectures() diff --git a/db/crud.py b/db/crud.py index f92403b..e8b3e52 100644 --- a/db/crud.py +++ b/db/crud.py @@ -48,6 +48,18 @@ def get_all_denied_lectures(): return out +def get_all_failed_lectures(): + from db.models.lecture import Analysis + lectures = get_all_lectures() + + out = [] + for lecture in lectures: + if lecture.get_last_analysis().state == Analysis.State.FAILURE: + out.append(lecture) + + return out + + def get_unfinished_lectures(): from db.models.lecture import Analysis lectures = get_all_lectures() From cc176b38e1e7fef111abf118701d3bdb6588dc49 Mon Sep 17 00:00:00 2001 From: Ludwig Kristoffersson Date: Wed, 8 Mar 2023 01:22:18 +0100 Subject: [PATCH 2/3] add page with table that shows all failed lectures --- web-ui/.umirc.ts | 1 + .../src/components/tables/failures-table.less | 10 ++ .../src/components/tables/failures-table.tsx | 157 ++++++++++++++++++ web-ui/src/pages/failures.tsx | 24 +++ 4 files changed, 192 insertions(+) create mode 100644 web-ui/src/components/tables/failures-table.less create mode 100644 web-ui/src/components/tables/failures-table.tsx create mode 100644 web-ui/src/pages/failures.tsx diff --git a/web-ui/.umirc.ts b/web-ui/.umirc.ts index fcd3110..837be0b 100644 --- a/web-ui/.umirc.ts +++ b/web-ui/.umirc.ts @@ -7,6 +7,7 @@ export default defineConfig({ { path: '/questions/lectures/:id/:language', component: 'questions' }, { path: '/queue', component: 'queue' }, { path: '/denied', component: 'denied' }, + { path: '/failures', component: 'failures' }, { path: '/about', component: 'about' }, { path: '*', component: '404' }, diff --git a/web-ui/src/components/tables/failures-table.less b/web-ui/src/components/tables/failures-table.less new file mode 100644 index 0000000..c635376 --- /dev/null +++ b/web-ui/src/components/tables/failures-table.less @@ -0,0 +1,10 @@ + +.flag { + width: 100% !important; + height: 50px; + border-radius: 3px; +} + +.logo { + border-radius: 3px; +} diff --git a/web-ui/src/components/tables/failures-table.tsx b/web-ui/src/components/tables/failures-table.tsx new file mode 100644 index 0000000..80d8111 --- /dev/null +++ b/web-ui/src/components/tables/failures-table.tsx @@ -0,0 +1,157 @@ +import { Table, Image, Typography } from 'antd'; +import { notification } from 'antd'; +import { useEffect, useState } from 'react'; +import { useMutation } from '@tanstack/react-query'; +import apiClient, { ServerErrorResponse, ServerResponse } from '@/http'; +import { Lecture } from '@/components/lecture'; +import styles from './denied-table.less'; +import { ColumnsType } from 'antd/es/table'; +import svFlag from '@/assets/flag-sv.svg'; +import enFlag from '@/assets/flag-en.svg'; +import kthLogo from '@/assets/kth.svg'; +import youtubeLogo from '@/assets/youtube.svg'; + +const { Link } = Typography; + +const UPDATE_INTERVAL = 5000; + +const columns: ColumnsType = [ + { + title: 'Source', + dataIndex: 'source', + render: (source: string) => { + let icon = ''; + if (source === 'youtube') { + icon = youtubeLogo; + } else if (source === 'kth') { + icon = kthLogo; + } + return ( + + ); + }, + }, + { + title: 'Title', + dataIndex: 'title', + }, + { + title: 'Analysis', + dataIndex: 'combined_public_id_and_lang', + render: (combined_public_id_and_lang: string) => ( + <> + + View Progress + + + ), + }, + { + title: 'Content Link', + dataIndex: 'content_link', + render: (content_link: string) => ( + <> + + {content_link} + + + ), + }, + { + title: 'Language', + dataIndex: 'language', + render: (val: string) => { + let flagIcon = ''; + if (val === 'sv') { + flagIcon = svFlag; + } else if (val === 'en') { + flagIcon = enFlag; + } + return ( + + ); + }, + }, + { + title: 'Added At', + dataIndex: 'created_at', + render: (val: string) => { + const d = new Date(val); + const date = d.toDateString(); + const time = d.toLocaleTimeString('sv'); + return ( + <> + {date}, {time} + + ); + }, + }, + { + title: 'Progress', + dataIndex: 'overall_progress', + render: (val: string) => <>{val}%, + }, +]; + +interface LectureResponse extends ServerResponse { + data: Lecture[]; +} + +export default function FailuresTable() { + const [lectures, setLectures] = useState([]); + const [notificationApi, contextHolder] = notification.useNotification(); + + const { mutate: fetchLectures } = useMutation( + async () => { + return await apiClient.get(`/lectures?summary=true&only_failed=true`); + }, + { + onSuccess: (res: LectureResponse) => { + const result = { + status: res.status + '-' + res.statusText, + headers: res.headers, + data: res.data, + }; + for (let i = 0; i < res.data.length; i++) { + const lecture = res.data[i]; + lecture.combined_public_id_and_lang = `${lecture.public_id}/${lecture.language}`; + lecture['key'] = lecture.combined_public_id_and_lang; + } + setLectures(result.data as Lecture[]); + }, + onError: (err: ServerErrorResponse) => { + notificationApi['error']({ + message: 'Failed to get lectures', + description: err.response.data.detail, + }); + }, + } + ); + + useEffect(() => { + fetchLectures(); + }, [fetchLectures]); + + useEffect(() => { + const interval = setInterval(() => { + fetchLectures(); + }, UPDATE_INTERVAL); + + return () => clearInterval(interval); + }, [fetchLectures]); + + return ( + <> + {contextHolder} + + + ); +} diff --git a/web-ui/src/pages/failures.tsx b/web-ui/src/pages/failures.tsx new file mode 100644 index 0000000..c5525fc --- /dev/null +++ b/web-ui/src/pages/failures.tsx @@ -0,0 +1,24 @@ +import Frame from '@/components/main/frame'; +import DeniedTable from '@/components/tables/failures-table'; +import { registerPageLoad } from '@/matomo'; +import { useEffect } from 'react'; +import { Typography } from 'antd'; + +const { Title } = Typography; + +export default function FailuresPage() { + useEffect(() => { + registerPageLoad(); + }, []); + + return ( + <> + + <> + Lectures that has failed + + + + + ); +} From f43a06c37dbd3cbf194c2a65da1e1de788ec74a9 Mon Sep 17 00:00:00 2001 From: Ludwig Kristoffersson Date: Wed, 8 Mar 2023 01:24:30 +0100 Subject: [PATCH 3/3] update the advertised time an analysis take --- web-ui/src/components/selector/lecture-adder.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web-ui/src/components/selector/lecture-adder.tsx b/web-ui/src/components/selector/lecture-adder.tsx index 53b4afe..180ba43 100644 --- a/web-ui/src/components/selector/lecture-adder.tsx +++ b/web-ui/src/components/selector/lecture-adder.tsx @@ -360,7 +360,7 @@ export default function LectureAdder() { - This process usually takes between 10 and 30 minutes, depending on the + This process usually takes between 5 and 15 minutes, depending on the length of the lecture and how many other lectures are being watched.