@openedx/frontend-app-instructor-dashboard 1.0.0-alpha.19 → 1.0.0-alpha.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,14 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { useIntl } from '@openedx/frontend-base';
4
+ import { Button, ButtonGroup, Card } from '@openedx/paragon';
5
+ import messages from './messages';
6
+ import Allowances from './components/Allowances';
7
+ import AttemptsList from './components/AttemptsList';
2
8
  const SpecialExamsPage = () => {
3
- return (_jsx("div", { children: _jsx("h3", { children: "Special Exams" }) }));
9
+ const intl = useIntl();
10
+ const [selectedTab, setSelectedTab] = useState('attempts');
11
+ return (_jsxs(_Fragment, { children: [_jsx("h3", { className: "text-primary-700", children: intl.formatMessage(messages.specialExamsTitle) }), _jsxs(Card, { className: "bg-light-200 mt-4.5", children: [_jsxs(ButtonGroup, { className: "d-block mx-4 mt-4", children: [_jsx(Button, { variant: selectedTab === 'attempts' ? 'primary' : 'outline-primary', onClick: () => setSelectedTab('attempts'), children: intl.formatMessage(messages.examAttempts) }), _jsx(Button, { variant: selectedTab === 'allowances' ? 'primary' : 'outline-primary', onClick: () => setSelectedTab('allowances'), children: intl.formatMessage(messages.allowances) })] }), selectedTab === 'attempts' ? _jsx(AttemptsList, {}) : _jsx(Allowances, {})] })] }));
4
12
  };
5
13
  export default SpecialExamsPage;
6
14
  //# sourceMappingURL=SpecialExamsPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SpecialExamsPage.js","sourceRoot":"","sources":["../../src/specialExams/SpecialExamsPage.tsx"],"names":[],"mappings":";AAAA,MAAM,gBAAgB,GAAG,GAAG,EAAE;IAC5B,OAAO,CACL,wBACE,yCAAsB,GAClB,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,gBAAgB,CAAC","sourcesContent":["const SpecialExamsPage = () => {\n return (\n <div>\n <h3>Special Exams</h3>\n </div>\n );\n};\n\nexport default SpecialExamsPage;\n"]}
1
+ {"version":3,"file":"SpecialExamsPage.js","sourceRoot":"","sources":["../../src/specialExams/SpecialExamsPage.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,QAAQ,MAAM,YAAY,CAAC;AAClC,OAAO,UAAU,MAAM,yBAAyB,CAAC;AACjD,OAAO,YAAY,MAAM,2BAA2B,CAAC;AAErD,MAAM,gBAAgB,GAAG,GAAG,EAAE;IAC5B,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAA4B,UAAU,CAAC,CAAC;IAEtF,OAAO,CACL,8BACE,aAAI,SAAS,EAAC,kBAAkB,YAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,iBAAiB,CAAC,GAAM,EACtF,MAAC,IAAI,IAAC,SAAS,EAAC,qBAAqB,aACnC,MAAC,WAAW,IAAC,SAAS,EAAC,mBAAmB,aACxC,KAAC,MAAM,IAAC,OAAO,EAAE,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,UAAU,CAAC,YAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,YAAY,CAAC,GAAU,EAC5K,KAAC,MAAM,IAAC,OAAO,EAAE,WAAW,KAAK,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,YAAY,CAAC,YAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAU,IAClK,EAEZ,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,KAAC,YAAY,KAAG,CAAC,CAAC,CAAC,KAAC,UAAU,KAAG,IAE3D,IACN,CACJ,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,gBAAgB,CAAC","sourcesContent":["import { useState } from 'react';\nimport { useIntl } from '@openedx/frontend-base';\nimport { Button, ButtonGroup, Card } from '@openedx/paragon';\nimport messages from './messages';\nimport Allowances from './components/Allowances';\nimport AttemptsList from './components/AttemptsList';\n\nconst SpecialExamsPage = () => {\n const intl = useIntl();\n const [selectedTab, setSelectedTab] = useState<'attempts' | 'allowances'>('attempts');\n\n return (\n <>\n <h3 className=\"text-primary-700\">{intl.formatMessage(messages.specialExamsTitle)}</h3>\n <Card className=\"bg-light-200 mt-4.5\">\n <ButtonGroup className=\"d-block mx-4 mt-4\">\n <Button variant={selectedTab === 'attempts' ? 'primary' : 'outline-primary'} onClick={() => setSelectedTab('attempts')}>{intl.formatMessage(messages.examAttempts)}</Button>\n <Button variant={selectedTab === 'allowances' ? 'primary' : 'outline-primary'} onClick={() => setSelectedTab('allowances')}>{intl.formatMessage(messages.allowances)}</Button>\n </ButtonGroup>\n {\n selectedTab === 'attempts' ? <AttemptsList /> : <Allowances />\n }\n </Card>\n </>\n );\n};\n\nexport default SpecialExamsPage;\n"]}
@@ -0,0 +1,2 @@
1
+ declare const Allowances: () => import("react/jsx-runtime").JSX.Element;
2
+ export default Allowances;
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ const Allowances = () => {
3
+ return _jsx("div", { children: "Allowances" });
4
+ };
5
+ export default Allowances;
6
+ //# sourceMappingURL=Allowances.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Allowances.js","sourceRoot":"","sources":["../../../src/specialExams/components/Allowances.tsx"],"names":[],"mappings":";AAAA,MAAM,UAAU,GAAG,GAAG,EAAE;IACtB,OAAO,uCAAqB,CAAC;AAC/B,CAAC,CAAC;AAEF,eAAe,UAAU,CAAC","sourcesContent":["const Allowances = () => {\n return <div>Allowances</div>;\n};\n\nexport default Allowances;\n"]}
@@ -0,0 +1,3 @@
1
+ export declare const ATTEMPTS_PAGE_SIZE = 25;
2
+ declare const AttemptsList: () => import("react/jsx-runtime").JSX.Element;
3
+ export default AttemptsList;
@@ -0,0 +1,44 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useMemo, useState } from 'react';
3
+ import { useParams } from 'react-router-dom';
4
+ import { useIntl } from '@openedx/frontend-base';
5
+ import { DataTable } from '@openedx/paragon';
6
+ import UsernameFilter from '../../components/UsernameFilter';
7
+ import messages from '../../specialExams/messages';
8
+ import { useAttempts } from '../../specialExams/data/apiHook';
9
+ export const ATTEMPTS_PAGE_SIZE = 25;
10
+ const AttemptsList = () => {
11
+ const intl = useIntl();
12
+ const { courseId = '' } = useParams();
13
+ const [filters, setFilters] = useState({ page: 0, emailOrUsername: '' });
14
+ const { data = { results: [], count: 0, numPages: 0 }, isLoading = false } = useAttempts(courseId, Object.assign(Object.assign({}, filters), { pageSize: ATTEMPTS_PAGE_SIZE }));
15
+ const columns = useMemo(() => [
16
+ { accessor: 'username', Header: intl.formatMessage(messages.username), Filter: UsernameFilter, },
17
+ { accessor: 'examName', Header: intl.formatMessage(messages.examName), disableFilters: true, },
18
+ { accessor: 'timeLimit', Header: intl.formatMessage(messages.timeLimit), disableFilters: true, },
19
+ { accessor: 'type', Header: intl.formatMessage(messages.type), disableFilters: true, },
20
+ { accessor: 'startedAt', Header: intl.formatMessage(messages.startedAt), disableFilters: true, },
21
+ { accessor: 'completedAt', Header: intl.formatMessage(messages.completedAt), disableFilters: true, },
22
+ { accessor: 'status', Header: intl.formatMessage(messages.status), disableFilters: true, },
23
+ ], [intl]);
24
+ const handleFetchData = (data) => {
25
+ var _a;
26
+ const emailOrUsernameFilter = (_a = data.filters) === null || _a === void 0 ? void 0 : _a.find((f) => f.id === 'username');
27
+ if (emailOrUsernameFilter && emailOrUsernameFilter.value !== filters.emailOrUsername) {
28
+ setFilters((prevFilters) => (Object.assign(Object.assign({}, prevFilters), { emailOrUsername: emailOrUsernameFilter.value, page: 0 })));
29
+ return;
30
+ }
31
+ if (data.pageIndex !== filters.page) {
32
+ setFilters((prevFilters) => (Object.assign(Object.assign({}, prevFilters), { page: data.pageIndex })));
33
+ }
34
+ };
35
+ return (_jsxs(DataTable, { className: "mt-3", columns: columns, data: data.results, state: {
36
+ pageIndex: filters.page,
37
+ pageSize: ATTEMPTS_PAGE_SIZE,
38
+ filters: [
39
+ { id: 'emailOrUsername', value: filters.emailOrUsername }
40
+ ]
41
+ }, fetchData: handleFetchData, isFilterable: true, isLoading: isLoading, isPaginated: true, isSortable: true, itemCount: data.count, manualFilters: true, manualPagination: true, manualSortBy: true, pageSize: ATTEMPTS_PAGE_SIZE, pageCount: data.numPages, FilterStatusComponent: () => null, children: [_jsx(DataTable.TableControlBar, { className: "bg-light-200 py-3 px-4" }), _jsx(DataTable.Table, {}), _jsx(DataTable.EmptyTable, { content: intl.formatMessage(messages.noAttempts) }), _jsx(DataTable.TableFooter, {})] }));
42
+ };
43
+ export default AttemptsList;
44
+ //# sourceMappingURL=AttemptsList.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AttemptsList.js","sourceRoot":"","sources":["../../../src/specialExams/components/AttemptsList.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useMemo, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { useIntl } from '@openedx/frontend-base';\nimport { DataTable } from '@openedx/paragon';\nimport UsernameFilter from '@src/components/UsernameFilter';\nimport messages from '@src/specialExams/messages';\nimport { useAttempts } from '@src/specialExams/data/apiHook';\nimport { DataTableFetchDataProps } from '@src/types';\n\nexport const ATTEMPTS_PAGE_SIZE = 25;\n\nconst AttemptsList = () => {\n const intl = useIntl();\n const { courseId = '' } = useParams();\n const [filters, setFilters] = useState({ page: 0, emailOrUsername: '' });\n const { data = { results: [], count: 0, numPages: 0 }, isLoading = false } = useAttempts(courseId, {\n ...filters,\n pageSize: ATTEMPTS_PAGE_SIZE\n });\n\n const columns = useMemo(() => [\n { accessor: 'username', Header: intl.formatMessage(messages.username), Filter: UsernameFilter, },\n { accessor: 'examName', Header: intl.formatMessage(messages.examName), disableFilters: true, },\n { accessor: 'timeLimit', Header: intl.formatMessage(messages.timeLimit), disableFilters: true, },\n { accessor: 'type', Header: intl.formatMessage(messages.type), disableFilters: true, },\n { accessor: 'startedAt', Header: intl.formatMessage(messages.startedAt), disableFilters: true, },\n { accessor: 'completedAt', Header: intl.formatMessage(messages.completedAt), disableFilters: true, },\n { accessor: 'status', Header: intl.formatMessage(messages.status), disableFilters: true, },\n ], [intl]);\n\n const handleFetchData = (data: DataTableFetchDataProps) => {\n const emailOrUsernameFilter = data.filters?.find((f) => f.id === 'username');\n if (emailOrUsernameFilter && emailOrUsernameFilter.value !== filters.emailOrUsername) {\n setFilters((prevFilters) => ({ ...prevFilters, emailOrUsername: emailOrUsernameFilter.value, page: 0 }));\n return;\n }\n if (data.pageIndex !== filters.page) {\n setFilters((prevFilters) => ({ ...prevFilters, page: data.pageIndex }));\n }\n };\n\n return (\n <DataTable\n className=\"mt-3\"\n columns={columns}\n data={data.results}\n state={{\n pageIndex: filters.page,\n pageSize: ATTEMPTS_PAGE_SIZE,\n filters: [\n { id: 'emailOrUsername', value: filters.emailOrUsername }\n ]\n }}\n fetchData={handleFetchData}\n isFilterable\n isLoading={isLoading}\n isPaginated\n isSortable\n itemCount={data.count}\n manualFilters\n manualPagination\n manualSortBy\n pageSize={ATTEMPTS_PAGE_SIZE}\n pageCount={data.numPages}\n FilterStatusComponent={() => null}\n >\n <DataTable.TableControlBar className=\"bg-light-200 py-3 px-4\" />\n <DataTable.Table />\n <DataTable.EmptyTable content={intl.formatMessage(messages.noAttempts)} />\n <DataTable.TableFooter />\n </DataTable>\n );\n};\n\nexport default AttemptsList;\n"]}
@@ -0,0 +1,3 @@
1
+ import { DataList } from '../../types';
2
+ import { Attempt, AttemptsParams } from '../types';
3
+ export declare const getAttempts: (courseId: string, params: AttemptsParams) => Promise<DataList<Attempt>>;
@@ -0,0 +1,23 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { getAuthenticatedHttpClient, camelCaseObject } from '@openedx/frontend-base';
11
+ import { getApiBaseUrl } from '../../data/api';
12
+ export const getAttempts = (courseId, params) => __awaiter(void 0, void 0, void 0, function* () {
13
+ const queryParams = new URLSearchParams({
14
+ page: (params.page + 1).toString(),
15
+ page_size: params.pageSize.toString(),
16
+ });
17
+ if (params.emailOrUsername) {
18
+ queryParams.append('search', params.emailOrUsername);
19
+ }
20
+ const { data } = yield getAuthenticatedHttpClient().get(`${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/special_exams/attempts?${queryParams.toString()}`);
21
+ return camelCaseObject(data);
22
+ });
23
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/specialExams/data/api.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,0BAA0B,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAI9C,MAAM,CAAC,MAAM,WAAW,GAAG,CAAO,QAAgB,EAAE,MAAsB,EAA8B,EAAE;IACxG,MAAM,WAAW,GAAG,IAAI,eAAe,CAAC;QACtC,IAAI,EAAE,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE;QAClC,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE;KACtC,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,eAAe,EAAE,CAAC;QAC3B,WAAW,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,eAAe,CAAC,CAAC;IACvD,CAAC;IAED,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,0BAA0B,EAAE,CAAC,GAAG,CACrD,GAAG,aAAa,EAAE,8BAA8B,QAAQ,2BAA2B,WAAW,CAAC,QAAQ,EAAE,EAAE,CAC5G,CAAC;IACF,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC,CAAA,CAAC","sourcesContent":["import { getAuthenticatedHttpClient, camelCaseObject } from '@openedx/frontend-base';\nimport { getApiBaseUrl } from '@src/data/api';\nimport { DataList } from '@src/types';\nimport { Attempt, AttemptsParams } from '../types';\n\nexport const getAttempts = async (courseId: string, params: AttemptsParams): Promise<DataList<Attempt>> => {\n const queryParams = new URLSearchParams({\n page: (params.page + 1).toString(),\n page_size: params.pageSize.toString(),\n });\n\n if (params.emailOrUsername) {\n queryParams.append('search', params.emailOrUsername);\n }\n\n const { data } = await getAuthenticatedHttpClient().get(\n `${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/special_exams/attempts?${queryParams.toString()}`\n );\n return camelCaseObject(data);\n};\n"]}
@@ -0,0 +1,2 @@
1
+ import { AttemptsParams } from '../types';
2
+ export declare const useAttempts: (courseId: string, params: AttemptsParams) => import("@tanstack/react-query").UseQueryResult<import("../../types").DataList<import("../types").Attempt>, Error>;
@@ -0,0 +1,9 @@
1
+ import { useQuery } from '@tanstack/react-query';
2
+ import { getAttempts } from './api';
3
+ import { specialExamsQueryKeys } from './queryKeys';
4
+ export const useAttempts = (courseId, params) => (useQuery({
5
+ queryKey: specialExamsQueryKeys.attempts(courseId, params),
6
+ queryFn: () => getAttempts(courseId, params),
7
+ enabled: !!courseId,
8
+ }));
9
+ //# sourceMappingURL=apiHook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiHook.js","sourceRoot":"","sources":["../../../src/specialExams/data/apiHook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAGpD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,QAAgB,EAAE,MAAsB,EAAE,EAAE,CAAC,CACvE,QAAQ,CAAC;IACP,QAAQ,EAAE,qBAAqB,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1D,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC5C,OAAO,EAAE,CAAC,CAAC,QAAQ;CACpB,CAAC,CACH,CAAC","sourcesContent":["import { useQuery } from '@tanstack/react-query';\nimport { getAttempts } from './api';\nimport { specialExamsQueryKeys } from './queryKeys';\nimport { AttemptsParams } from '../types';\n\nexport const useAttempts = (courseId: string, params: AttemptsParams) => (\n useQuery({\n queryKey: specialExamsQueryKeys.attempts(courseId, params),\n queryFn: () => getAttempts(courseId, params),\n enabled: !!courseId,\n })\n);\n"]}
@@ -0,0 +1,5 @@
1
+ import { AttemptsParams } from '../types';
2
+ export declare const specialExamsQueryKeys: {
3
+ all: readonly ["org.openedx.frontend.app.instructorDashboard", "specialExams"];
4
+ attempts: (courseId: string, params: AttemptsParams) => readonly ["org.openedx.frontend.app.instructorDashboard", "specialExams", "attempts", string, number, string];
5
+ };
@@ -0,0 +1,6 @@
1
+ import { appId } from '../../constants';
2
+ export const specialExamsQueryKeys = {
3
+ all: [appId, 'specialExams'],
4
+ attempts: (courseId, params) => [...specialExamsQueryKeys.all, 'attempts', courseId, params.page, params.emailOrUsername],
5
+ };
6
+ //# sourceMappingURL=queryKeys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queryKeys.js","sourceRoot":"","sources":["../../../src/specialExams/data/queryKeys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAGvC,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,GAAG,EAAE,CAAC,KAAK,EAAE,cAAc,CAAU;IACrC,QAAQ,EAAE,CAAC,QAAgB,EAAE,MAAsB,EAAE,EAAE,CAAC,CAAC,GAAG,qBAAqB,CAAC,GAAG,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,eAAe,CAAU;CAC3J,CAAC","sourcesContent":["import { appId } from '@src/constants';\nimport { AttemptsParams } from '../types';\n\nexport const specialExamsQueryKeys = {\n all: [appId, 'specialExams'] as const,\n attempts: (courseId: string, params: AttemptsParams) => [...specialExamsQueryKeys.all, 'attempts', courseId, params.page, params.emailOrUsername] as const,\n};\n"]}
@@ -0,0 +1,58 @@
1
+ declare const messages: {
2
+ specialExamsTitle: {
3
+ id: string;
4
+ defaultMessage: string;
5
+ description: string;
6
+ };
7
+ examAttempts: {
8
+ id: string;
9
+ defaultMessage: string;
10
+ description: string;
11
+ };
12
+ allowances: {
13
+ id: string;
14
+ defaultMessage: string;
15
+ description: string;
16
+ };
17
+ username: {
18
+ id: string;
19
+ defaultMessage: string;
20
+ description: string;
21
+ };
22
+ examName: {
23
+ id: string;
24
+ defaultMessage: string;
25
+ description: string;
26
+ };
27
+ timeLimit: {
28
+ id: string;
29
+ defaultMessage: string;
30
+ description: string;
31
+ };
32
+ type: {
33
+ id: string;
34
+ defaultMessage: string;
35
+ description: string;
36
+ };
37
+ startedAt: {
38
+ id: string;
39
+ defaultMessage: string;
40
+ description: string;
41
+ };
42
+ completedAt: {
43
+ id: string;
44
+ defaultMessage: string;
45
+ description: string;
46
+ };
47
+ status: {
48
+ id: string;
49
+ defaultMessage: string;
50
+ description: string;
51
+ };
52
+ noAttempts: {
53
+ id: string;
54
+ defaultMessage: string;
55
+ description: string;
56
+ };
57
+ };
58
+ export default messages;
@@ -0,0 +1,60 @@
1
+ import { defineMessages } from '@openedx/frontend-base';
2
+ const messages = defineMessages({
3
+ specialExamsTitle: {
4
+ id: 'instruct.specialExams.title',
5
+ defaultMessage: 'Special Exams',
6
+ description: 'Title for the special exams page'
7
+ },
8
+ examAttempts: {
9
+ id: 'instruct.specialExams.examAttempts',
10
+ defaultMessage: 'Exam Attempts',
11
+ description: 'Label for the exam attempts tab'
12
+ },
13
+ allowances: {
14
+ id: 'instruct.specialExams.allowances',
15
+ defaultMessage: 'Allowances',
16
+ description: 'Label for the allowances tab'
17
+ },
18
+ username: {
19
+ id: 'instruct.specialExams.username',
20
+ defaultMessage: 'Username',
21
+ description: 'Column header for username in exam attempts list',
22
+ },
23
+ examName: {
24
+ id: 'instruct.specialExams.examName',
25
+ defaultMessage: 'Exam Name',
26
+ description: 'Column header for exam name in exam attempts list',
27
+ },
28
+ timeLimit: {
29
+ id: 'instruct.specialExams.timeLimit',
30
+ defaultMessage: 'Time Limit',
31
+ description: 'Column header for time limit in exam attempts list',
32
+ },
33
+ type: {
34
+ id: 'instruct.specialExams.type',
35
+ defaultMessage: 'Type',
36
+ description: 'Column header for type in exam attempts list',
37
+ },
38
+ startedAt: {
39
+ id: 'instruct.specialExams.startedAt',
40
+ defaultMessage: 'Started At',
41
+ description: 'Column header for started at in exam attempts list',
42
+ },
43
+ completedAt: {
44
+ id: 'instruct.specialExams.completedAt',
45
+ defaultMessage: 'Completed At',
46
+ description: 'Column header for completed at in exam attempts list',
47
+ },
48
+ status: {
49
+ id: 'instruct.specialExams.status',
50
+ defaultMessage: 'Status',
51
+ description: 'Column header for status in exam attempts list',
52
+ },
53
+ noAttempts: {
54
+ id: 'instruct.specialExams.noAttempts',
55
+ defaultMessage: 'No exam attempts found',
56
+ description: 'Message displayed when there are no exam attempts to show',
57
+ }
58
+ });
59
+ export default messages;
60
+ //# sourceMappingURL=messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/specialExams/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,QAAQ,GAAG,cAAc,CAAC;IAC9B,iBAAiB,EAAE;QACjB,EAAE,EAAE,6BAA6B;QACjC,cAAc,EAAE,eAAe;QAC/B,WAAW,EAAE,kCAAkC;KAChD;IACD,YAAY,EAAE;QACZ,EAAE,EAAE,oCAAoC;QACxC,cAAc,EAAE,eAAe;QAC/B,WAAW,EAAE,iCAAiC;KAC/C;IACD,UAAU,EAAE;QACV,EAAE,EAAE,kCAAkC;QACtC,cAAc,EAAE,YAAY;QAC5B,WAAW,EAAE,8BAA8B;KAC5C;IACD,QAAQ,EAAE;QACR,EAAE,EAAE,gCAAgC;QACpC,cAAc,EAAE,UAAU;QAC1B,WAAW,EAAE,kDAAkD;KAChE;IACD,QAAQ,EAAE;QACR,EAAE,EAAE,gCAAgC;QACpC,cAAc,EAAE,WAAW;QAC3B,WAAW,EAAE,mDAAmD;KACjE;IACD,SAAS,EAAE;QACT,EAAE,EAAE,iCAAiC;QACrC,cAAc,EAAE,YAAY;QAC5B,WAAW,EAAE,oDAAoD;KAClE;IACD,IAAI,EAAE;QACJ,EAAE,EAAE,4BAA4B;QAChC,cAAc,EAAE,MAAM;QACtB,WAAW,EAAE,8CAA8C;KAC5D;IACD,SAAS,EAAE;QACT,EAAE,EAAE,iCAAiC;QACrC,cAAc,EAAE,YAAY;QAC5B,WAAW,EAAE,oDAAoD;KAClE;IACD,WAAW,EAAE;QACX,EAAE,EAAE,mCAAmC;QACvC,cAAc,EAAE,cAAc;QAC9B,WAAW,EAAE,sDAAsD;KACpE;IACD,MAAM,EAAE;QACN,EAAE,EAAE,8BAA8B;QAClC,cAAc,EAAE,QAAQ;QACxB,WAAW,EAAE,gDAAgD;KAC9D;IACD,UAAU,EAAE;QACV,EAAE,EAAE,kCAAkC;QACtC,cAAc,EAAE,wBAAwB;QACxC,WAAW,EAAE,2DAA2D;KACzE;CACF,CAAC,CAAC;AAEH,eAAe,QAAQ,CAAC","sourcesContent":["import { defineMessages } from '@openedx/frontend-base';\n\nconst messages = defineMessages({\n specialExamsTitle: {\n id: 'instruct.specialExams.title',\n defaultMessage: 'Special Exams',\n description: 'Title for the special exams page'\n },\n examAttempts: {\n id: 'instruct.specialExams.examAttempts',\n defaultMessage: 'Exam Attempts',\n description: 'Label for the exam attempts tab'\n },\n allowances: {\n id: 'instruct.specialExams.allowances',\n defaultMessage: 'Allowances',\n description: 'Label for the allowances tab'\n },\n username: {\n id: 'instruct.specialExams.username',\n defaultMessage: 'Username',\n description: 'Column header for username in exam attempts list',\n },\n examName: {\n id: 'instruct.specialExams.examName',\n defaultMessage: 'Exam Name',\n description: 'Column header for exam name in exam attempts list',\n },\n timeLimit: {\n id: 'instruct.specialExams.timeLimit',\n defaultMessage: 'Time Limit',\n description: 'Column header for time limit in exam attempts list',\n },\n type: {\n id: 'instruct.specialExams.type',\n defaultMessage: 'Type',\n description: 'Column header for type in exam attempts list',\n },\n startedAt: {\n id: 'instruct.specialExams.startedAt',\n defaultMessage: 'Started At',\n description: 'Column header for started at in exam attempts list',\n },\n completedAt: {\n id: 'instruct.specialExams.completedAt',\n defaultMessage: 'Completed At',\n description: 'Column header for completed at in exam attempts list',\n },\n status: {\n id: 'instruct.specialExams.status',\n defaultMessage: 'Status',\n description: 'Column header for status in exam attempts list',\n },\n noAttempts: {\n id: 'instruct.specialExams.noAttempts',\n defaultMessage: 'No exam attempts found',\n description: 'Message displayed when there are no exam attempts to show',\n }\n});\n\nexport default messages;\n"]}
@@ -0,0 +1,13 @@
1
+ import { PaginationParams } from '../types';
2
+ export interface Attempt {
3
+ username: string;
4
+ examName: string;
5
+ timeLimit: number;
6
+ type: string;
7
+ startedAt: string;
8
+ completedAt: string;
9
+ status: string;
10
+ }
11
+ export interface AttemptsParams extends PaginationParams {
12
+ emailOrUsername: string;
13
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/specialExams/types.ts"],"names":[],"mappings":"","sourcesContent":["import { PaginationParams } from '@src/types';\n\nexport interface Attempt {\n username: string,\n examName: string,\n timeLimit: number,\n type: string,\n startedAt: string,\n completedAt: string,\n status: string,\n}\n\nexport interface AttemptsParams extends PaginationParams {\n emailOrUsername: string,\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openedx/frontend-app-instructor-dashboard",
3
- "version": "1.0.0-alpha.19",
3
+ "version": "1.0.0-alpha.20",
4
4
  "description": "The Open edX Instructor Dashboard",
5
5
  "repository": {
6
6
  "type": "git",