@openedx/frontend-app-instructor-dashboard 1.0.0-alpha.15 → 1.0.0-alpha.16

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.
Files changed (51) hide show
  1. package/dist/app.scss +4 -0
  2. package/dist/components/ActionCard.d.ts +2 -2
  3. package/dist/components/ActionCard.js +1 -1
  4. package/dist/components/ActionCard.js.map +1 -1
  5. package/dist/components/PendingTasks.d.ts +3 -1
  6. package/dist/components/PendingTasks.js +3 -2
  7. package/dist/components/PendingTasks.js.map +1 -1
  8. package/dist/components/SpecifyLearnerField.d.ts +4 -1
  9. package/dist/components/SpecifyLearnerField.js +18 -7
  10. package/dist/components/SpecifyLearnerField.js.map +1 -1
  11. package/dist/components/SpecifyProblemField.d.ts +13 -0
  12. package/dist/components/SpecifyProblemField.js +46 -0
  13. package/dist/components/SpecifyProblemField.js.map +1 -0
  14. package/dist/components/messages.d.ts +20 -0
  15. package/dist/components/messages.js +20 -0
  16. package/dist/components/messages.js.map +1 -1
  17. package/dist/data/api.d.ts +1 -0
  18. package/dist/data/api.js +7 -0
  19. package/dist/data/api.js.map +1 -1
  20. package/dist/data/apiHook.d.ts +1 -0
  21. package/dist/data/apiHook.js +10 -2
  22. package/dist/data/apiHook.js.map +1 -1
  23. package/dist/data/queryKeys.d.ts +4 -0
  24. package/dist/data/queryKeys.js +4 -0
  25. package/dist/data/queryKeys.js.map +1 -1
  26. package/dist/grading/GradingPage.js +5 -1
  27. package/dist/grading/GradingPage.js.map +1 -1
  28. package/dist/grading/components/GradingLearnerContent.d.ts +2 -1
  29. package/dist/grading/components/GradingLearnerContent.js +89 -4
  30. package/dist/grading/components/GradingLearnerContent.js.map +1 -1
  31. package/dist/grading/data/api.d.ts +5 -0
  32. package/dist/grading/data/api.js +42 -0
  33. package/dist/grading/data/api.js.map +1 -1
  34. package/dist/grading/data/apiHook.d.ts +5 -0
  35. package/dist/grading/data/apiHook.js +22 -2
  36. package/dist/grading/data/apiHook.js.map +1 -1
  37. package/dist/grading/data/queryKeys.d.ts +4 -0
  38. package/dist/grading/data/queryKeys.js +1 -0
  39. package/dist/grading/data/queryKeys.js.map +1 -1
  40. package/dist/grading/messages.d.ts +95 -0
  41. package/dist/grading/messages.js +95 -0
  42. package/dist/grading/messages.js.map +1 -1
  43. package/dist/grading/types.d.ts +10 -0
  44. package/dist/grading/types.js.map +1 -1
  45. package/dist/hooks/useDebouncedFilter.d.ts +1 -0
  46. package/dist/hooks/useDebouncedFilter.js +5 -0
  47. package/dist/hooks/useDebouncedFilter.js.map +1 -1
  48. package/package.json +1 -1
  49. package/dist/components/SpecifyProblem.d.ts +0 -2
  50. package/dist/components/SpecifyProblem.js +0 -6
  51. package/dist/components/SpecifyProblem.js.map +0 -1
package/dist/app.scss CHANGED
@@ -12,3 +12,7 @@
12
12
  .username .form-control::placeholder {
13
13
  font-size: var(--pgn-typography-form-input-font-size-sm);
14
14
  }
15
+
16
+ .info-tooltip .tooltip-inner {
17
+ max-width: none;
18
+ }
@@ -1,5 +1,5 @@
1
- interface ActionCardProps {
2
- buttonLabel: string;
1
+ export interface ActionCardProps {
2
+ buttonLabel?: string;
3
3
  customAction?: React.ReactNode;
4
4
  description: string;
5
5
  hasBorderBottom?: boolean;
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Button, Card } from '@openedx/paragon';
3
3
  const ActionCard = ({ buttonLabel, customAction, description, hasBorderBottom = true, isLoading = false, title, onButtonClick, }) => {
4
- return (_jsxs(Card, { className: `bg-light-200 py-2 border-gray-500 rounded-0 shadow-none ${hasBorderBottom ? 'border-bottom' : ''}`, orientation: "horizontal", children: [_jsx(Card.Body, { className: "flex-grow-1", children: _jsxs(Card.Section, { children: [_jsx("h4", { className: "mb-2", children: title }), _jsx("p", { className: "text-muted mb-0", children: description })] }) }), _jsx(Card.Footer, { className: "d-flex align-items-center justify-content-end", children: customAction !== null && customAction !== void 0 ? customAction : (_jsx(Button, { onClick: onButtonClick, disabled: isLoading, variant: "primary", children: buttonLabel })) })] }));
4
+ return (_jsxs(Card, { className: `bg-light-200 pb-2 mt-2 border-gray-500 rounded-0 shadow-none ${hasBorderBottom ? 'border-bottom' : ''}`, orientation: "horizontal", children: [_jsx(Card.Body, { className: "flex-grow-1", children: _jsxs(Card.Section, { className: "pl-0", children: [_jsx("h4", { className: "text-primary-700 mb-2", children: title }), _jsx("p", { className: "text-primary-500 mb-0", children: description })] }) }), _jsx(Card.Footer, { className: "d-flex align-items-center justify-content-end", children: customAction !== null && customAction !== void 0 ? customAction : (buttonLabel && onButtonClick && (_jsx(Button, { onClick: onButtonClick, disabled: isLoading, variant: "primary", children: buttonLabel }))) })] }));
5
5
  };
6
6
  export default ActionCard;
7
7
  //# sourceMappingURL=ActionCard.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ActionCard.js","sourceRoot":"","sources":["../../src/components/ActionCard.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAYhD,MAAM,UAAU,GAAG,CAAC,EAClB,WAAW,EACX,YAAY,EACZ,WAAW,EACX,eAAe,GAAG,IAAI,EACtB,SAAS,GAAG,KAAK,EACjB,KAAK,EACL,aAAa,GACG,EAAE,EAAE;IACpB,OAAO,CACL,MAAC,IAAI,IAAC,SAAS,EAAE,2DAA2D,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,WAAW,EAAC,YAAY,aAC5I,KAAC,IAAI,CAAC,IAAI,IAAC,SAAS,EAAC,aAAa,YAChC,MAAC,IAAI,CAAC,OAAO,eACX,aAAI,SAAS,EAAC,MAAM,YAAE,KAAK,GAAM,EACjC,YAAG,SAAS,EAAC,iBAAiB,YAAE,WAAW,GAAK,IACnC,GACL,EACZ,KAAC,IAAI,CAAC,MAAM,IAAC,SAAS,EAAC,+CAA+C,YACnE,YAAY,aAAZ,YAAY,cAAZ,YAAY,GAAI,CACf,KAAC,MAAM,IACL,OAAO,EAAE,aAAa,EACtB,QAAQ,EAAE,SAAS,EACnB,OAAO,EAAC,SAAS,YAEhB,WAAW,GACL,CACV,GACW,IACT,CACR,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,UAAU,CAAC","sourcesContent":["import { Button, Card } from '@openedx/paragon';\n\ninterface ActionCardProps {\n buttonLabel: string,\n customAction?: React.ReactNode,\n description: string,\n hasBorderBottom?: boolean,\n isLoading?: boolean,\n title: string,\n onButtonClick?: () => void,\n}\n\nconst ActionCard = ({\n buttonLabel,\n customAction,\n description,\n hasBorderBottom = true,\n isLoading = false,\n title,\n onButtonClick,\n}: ActionCardProps) => {\n return (\n <Card className={`bg-light-200 py-2 border-gray-500 rounded-0 shadow-none ${hasBorderBottom ? 'border-bottom' : ''}`} orientation=\"horizontal\">\n <Card.Body className=\"flex-grow-1\">\n <Card.Section>\n <h4 className=\"mb-2\">{title}</h4>\n <p className=\"text-muted mb-0\">{description}</p>\n </Card.Section>\n </Card.Body>\n <Card.Footer className=\"d-flex align-items-center justify-content-end\">\n {customAction ?? (\n <Button\n onClick={onButtonClick}\n disabled={isLoading}\n variant=\"primary\"\n >\n {buttonLabel}\n </Button>\n )}\n </Card.Footer>\n </Card>\n );\n};\n\nexport default ActionCard;\n"]}
1
+ {"version":3,"file":"ActionCard.js","sourceRoot":"","sources":["../../src/components/ActionCard.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAYhD,MAAM,UAAU,GAAG,CAAC,EAClB,WAAW,EACX,YAAY,EACZ,WAAW,EACX,eAAe,GAAG,IAAI,EACtB,SAAS,GAAG,KAAK,EACjB,KAAK,EACL,aAAa,GACG,EAAE,EAAE;IACpB,OAAO,CACL,MAAC,IAAI,IAAC,SAAS,EAAE,gEAAgE,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,WAAW,EAAC,YAAY,aACjJ,KAAC,IAAI,CAAC,IAAI,IAAC,SAAS,EAAC,aAAa,YAChC,MAAC,IAAI,CAAC,OAAO,IAAC,SAAS,EAAC,MAAM,aAC5B,aAAI,SAAS,EAAC,uBAAuB,YAAE,KAAK,GAAM,EAClD,YAAG,SAAS,EAAC,uBAAuB,YAAE,WAAW,GAAK,IACzC,GACL,EACZ,KAAC,IAAI,CAAC,MAAM,IAAC,SAAS,EAAC,+CAA+C,YACnE,YAAY,aAAZ,YAAY,cAAZ,YAAY,GAAI,CAAC,WAAW,IAAI,aAAa,IAAI,CAChD,KAAC,MAAM,IACL,OAAO,EAAE,aAAa,EACtB,QAAQ,EAAE,SAAS,EACnB,OAAO,EAAC,SAAS,YAEhB,WAAW,GACL,CACV,CAAC,GACU,IACT,CACR,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,UAAU,CAAC","sourcesContent":["import { Button, Card } from '@openedx/paragon';\n\nexport interface ActionCardProps {\n buttonLabel?: string,\n customAction?: React.ReactNode,\n description: string,\n hasBorderBottom?: boolean,\n isLoading?: boolean,\n title: string,\n onButtonClick?: () => void,\n}\n\nconst ActionCard = ({\n buttonLabel,\n customAction,\n description,\n hasBorderBottom = true,\n isLoading = false,\n title,\n onButtonClick,\n}: ActionCardProps) => {\n return (\n <Card className={`bg-light-200 pb-2 mt-2 border-gray-500 rounded-0 shadow-none ${hasBorderBottom ? 'border-bottom' : ''}`} orientation=\"horizontal\">\n <Card.Body className=\"flex-grow-1\">\n <Card.Section className=\"pl-0\">\n <h4 className=\"text-primary-700 mb-2\">{title}</h4>\n <p className=\"text-primary-500 mb-0\">{description}</p>\n </Card.Section>\n </Card.Body>\n <Card.Footer className=\"d-flex align-items-center justify-content-end\">\n {customAction ?? (buttonLabel && onButtonClick && (\n <Button\n onClick={onButtonClick}\n disabled={isLoading}\n variant=\"primary\"\n >\n {buttonLabel}\n </Button>\n ))}\n </Card.Footer>\n </Card>\n );\n};\n\nexport default ActionCard;\n"]}
@@ -1,5 +1,7 @@
1
1
  interface PendingTasksProps {
2
2
  isPolling?: boolean;
3
+ isOpen?: boolean;
4
+ onToggle?: () => void;
3
5
  }
4
- declare const PendingTasks: ({ isPolling }: PendingTasksProps) => import("react/jsx-runtime").JSX.Element;
6
+ declare const PendingTasks: ({ isPolling, isOpen, onToggle }: PendingTasksProps) => import("react/jsx-runtime").JSX.Element;
5
7
  export { PendingTasks };
@@ -7,7 +7,7 @@ import { ExpandLess, ExpandMore } from '@openedx/paragon/icons';
7
7
  import { usePendingTasks } from '../data/apiHook';
8
8
  import { useParams } from 'react-router';
9
9
  import { ObjectCell } from './ObjectCell';
10
- const PendingTasks = ({ isPolling = false }) => {
10
+ const PendingTasks = ({ isPolling = false, isOpen = false, onToggle }) => {
11
11
  const intl = useIntl();
12
12
  const { courseId = '' } = useParams();
13
13
  const { data: tasks, isLoading } = usePendingTasks(courseId, { enablePolling: isPolling });
@@ -32,7 +32,8 @@ const PendingTasks = ({ isPolling = false }) => {
32
32
  }
33
33
  return (_jsx(DataTable, { columns: tableColumns, data: tasks, RowStatusComponent: () => null }));
34
34
  };
35
- return (_jsxs(Collapsible.Advanced, { className: "mt-4 pt-4 border-top", styling: "basic", children: [_jsxs(Collapsible.Trigger, { className: "collapsible-trigger d-flex border-0 align-items-center text-decoration-none", children: [_jsx("div", { className: "d-flex", children: _jsx("h3", { className: "text-primary-700", children: intl.formatMessage(messages.pendingTasksTitle) }) }), _jsx(Collapsible.Visible, { whenClosed: true, children: _jsx("div", { className: "pl-2 d-flex", children: _jsx(Icon, { className: "text-primary-500", src: ExpandMore }) }) }), _jsx(Collapsible.Visible, { whenOpen: true, children: _jsx("div", { className: "pl-2 d-flex", children: _jsx(Icon, { className: "text-primary-500", src: ExpandLess }) }) })] }), _jsx(Collapsible.Body, { children: renderContent() })] }));
35
+ const collapsibleProps = onToggle ? { open: isOpen, onToggle } : {};
36
+ return (_jsxs(Collapsible.Advanced, Object.assign({ className: "mt-4 pt-4 border-top", styling: "basic" }, collapsibleProps, { children: [_jsxs(Collapsible.Trigger, { className: "collapsible-trigger d-flex border-0 align-items-center text-decoration-none", children: [_jsx("div", { className: "d-flex", children: _jsx("h3", { className: "text-primary-700", children: intl.formatMessage(messages.pendingTasksTitle) }) }), _jsx(Collapsible.Visible, { whenClosed: true, children: _jsx("div", { className: "pl-2 d-flex", children: _jsx(Icon, { className: "text-primary-500", src: ExpandMore }) }) }), _jsx(Collapsible.Visible, { whenOpen: true, children: _jsx("div", { className: "pl-2 d-flex", children: _jsx(Icon, { className: "text-primary-500", src: ExpandLess }) }) })] }), _jsx(Collapsible.Body, { children: renderContent() })] })));
36
37
  };
37
38
  export { PendingTasks };
38
39
  //# sourceMappingURL=PendingTasks.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PendingTasks.js","sourceRoot":"","sources":["../../src/components/PendingTasks.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useIntl } from '@openedx/frontend-base';\nimport { Collapsible, DataTable, Icon, Skeleton } from '@openedx/paragon';\nimport { useMemo } from 'react';\nimport messages from './messages';\nimport { ExpandLess, ExpandMore } from '@openedx/paragon/icons';\nimport { usePendingTasks } from '@src/data/apiHook';\nimport { useParams } from 'react-router';\nimport { ObjectCell } from './ObjectCell';\nimport { PendingTask, TableCellValue } from '@src/types';\n\ninterface PendingTasksProps {\n isPolling?: boolean,\n}\n\nconst PendingTasks = ({ isPolling = false }: PendingTasksProps) => {\n const intl = useIntl();\n const { courseId = '' } = useParams();\n const { data: tasks, isLoading } = usePendingTasks(courseId, { enablePolling: isPolling });\n\n const tableColumns = useMemo(() => [\n { accessor: 'taskType', Header: intl.formatMessage(messages.taskTypeColumnName) },\n { accessor: 'taskInput', Header: intl.formatMessage(messages.taskInputColumnName), Cell: ({ row }: TableCellValue<PendingTask>) => <ObjectCell value={row.original.taskInput} /> },\n { accessor: 'taskId', Header: intl.formatMessage(messages.taskIdColumnName) },\n { accessor: 'requester', Header: intl.formatMessage(messages.requesterColumnName) },\n { accessor: 'taskState', Header: intl.formatMessage(messages.taskStateColumnName) },\n { accessor: 'created', Header: intl.formatMessage(messages.createdColumnName) },\n { accessor: 'taskOutput', Header: intl.formatMessage(messages.taskOutputColumnName), Cell: ({ row }: TableCellValue<PendingTask>) => <ObjectCell value={row.original.taskOutput} /> },\n { accessor: 'durationSec', Header: intl.formatMessage(messages.durationColumnName) },\n { accessor: 'status', Header: intl.formatMessage(messages.statusColumnName) },\n { accessor: 'taskMessage', Header: intl.formatMessage(messages.taskMessageColumnName) },\n ], [intl]);\n\n const renderContent = () => {\n if (isLoading) {\n return <Skeleton count={3} />;\n }\n\n if (!tasks || tasks?.length === 0) {\n return <div className=\"my-3\">{intl.formatMessage(messages.noTasksMessage)}</div>;\n }\n\n return (\n <DataTable\n columns={tableColumns}\n data={tasks}\n RowStatusComponent={() => null}\n />\n );\n };\n\n return (\n <Collapsible.Advanced\n className=\"mt-4 pt-4 border-top\"\n styling=\"basic\"\n >\n <Collapsible.Trigger\n className=\"collapsible-trigger d-flex border-0 align-items-center text-decoration-none\"\n >\n <div className=\"d-flex\">\n <h3 className=\"text-primary-700\">{intl.formatMessage(messages.pendingTasksTitle)}</h3>\n </div>\n\n <Collapsible.Visible whenClosed>\n <div className=\"pl-2 d-flex\">\n <Icon className=\"text-primary-500\" src={ExpandMore} />\n </div>\n </Collapsible.Visible>\n <Collapsible.Visible whenOpen>\n <div className=\"pl-2 d-flex\">\n <Icon className=\"text-primary-500\" src={ExpandLess} />\n </div>\n </Collapsible.Visible>\n </Collapsible.Trigger>\n <Collapsible.Body>\n {renderContent() }\n </Collapsible.Body>\n </Collapsible.Advanced>\n );\n};\n\nexport { PendingTasks };\n"]}
1
+ {"version":3,"file":"PendingTasks.js","sourceRoot":"","sources":["../../src/components/PendingTasks.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useIntl } from '@openedx/frontend-base';\nimport { Collapsible, DataTable, Icon, Skeleton } from '@openedx/paragon';\nimport { useMemo } from 'react';\nimport messages from './messages';\nimport { ExpandLess, ExpandMore } from '@openedx/paragon/icons';\nimport { usePendingTasks } from '@src/data/apiHook';\nimport { useParams } from 'react-router';\nimport { ObjectCell } from './ObjectCell';\nimport { PendingTask, TableCellValue } from '@src/types';\n\ninterface PendingTasksProps {\n isPolling?: boolean,\n isOpen?: boolean,\n onToggle?: () => void,\n}\n\nconst PendingTasks = ({ isPolling = false, isOpen = false, onToggle }: PendingTasksProps) => {\n const intl = useIntl();\n const { courseId = '' } = useParams();\n const { data: tasks, isLoading } = usePendingTasks(courseId, { enablePolling: isPolling });\n\n const tableColumns = useMemo(() => [\n { accessor: 'taskType', Header: intl.formatMessage(messages.taskTypeColumnName) },\n { accessor: 'taskInput', Header: intl.formatMessage(messages.taskInputColumnName), Cell: ({ row }: TableCellValue<PendingTask>) => <ObjectCell value={row.original.taskInput} /> },\n { accessor: 'taskId', Header: intl.formatMessage(messages.taskIdColumnName) },\n { accessor: 'requester', Header: intl.formatMessage(messages.requesterColumnName) },\n { accessor: 'taskState', Header: intl.formatMessage(messages.taskStateColumnName) },\n { accessor: 'created', Header: intl.formatMessage(messages.createdColumnName) },\n { accessor: 'taskOutput', Header: intl.formatMessage(messages.taskOutputColumnName), Cell: ({ row }: TableCellValue<PendingTask>) => <ObjectCell value={row.original.taskOutput} /> },\n { accessor: 'durationSec', Header: intl.formatMessage(messages.durationColumnName) },\n { accessor: 'status', Header: intl.formatMessage(messages.statusColumnName) },\n { accessor: 'taskMessage', Header: intl.formatMessage(messages.taskMessageColumnName) },\n ], [intl]);\n\n const renderContent = () => {\n if (isLoading) {\n return <Skeleton count={3} />;\n }\n\n if (!tasks || tasks?.length === 0) {\n return <div className=\"my-3\">{intl.formatMessage(messages.noTasksMessage)}</div>;\n }\n\n return (\n <DataTable\n columns={tableColumns}\n data={tasks}\n RowStatusComponent={() => null}\n />\n );\n };\n\n const collapsibleProps = onToggle ? { open: isOpen, onToggle } : {};\n\n return (\n <Collapsible.Advanced\n className=\"mt-4 pt-4 border-top\"\n styling=\"basic\"\n {...collapsibleProps}\n >\n <Collapsible.Trigger\n className=\"collapsible-trigger d-flex border-0 align-items-center text-decoration-none\"\n >\n <div className=\"d-flex\">\n <h3 className=\"text-primary-700\">{intl.formatMessage(messages.pendingTasksTitle)}</h3>\n </div>\n\n <Collapsible.Visible whenClosed>\n <div className=\"pl-2 d-flex\">\n <Icon className=\"text-primary-500\" src={ExpandMore} />\n </div>\n </Collapsible.Visible>\n <Collapsible.Visible whenOpen>\n <div className=\"pl-2 d-flex\">\n <Icon className=\"text-primary-500\" src={ExpandLess} />\n </div>\n </Collapsible.Visible>\n </Collapsible.Trigger>\n <Collapsible.Body>\n {renderContent() }\n </Collapsible.Body>\n </Collapsible.Advanced>\n );\n};\n\nexport { PendingTasks };\n"]}
@@ -3,5 +3,8 @@ interface SpecifyLearnerFieldProps {
3
3
  learner?: SelectedLearner;
4
4
  onClickSelect: (emailOrUsername: string) => void;
5
5
  }
6
- declare const SpecifyLearnerField: ({ learner, onClickSelect }: SpecifyLearnerFieldProps) => import("react/jsx-runtime").JSX.Element;
6
+ interface SpecifyLearnerFieldRef {
7
+ reset: () => void;
8
+ }
9
+ declare const SpecifyLearnerField: import("react").ForwardRefExoticComponent<SpecifyLearnerFieldProps & import("react").RefAttributes<SpecifyLearnerFieldRef>>;
7
10
  export default SpecifyLearnerField;
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useState } from 'react';
2
+ import { useState, useImperativeHandle, forwardRef } from 'react';
3
3
  import { isAxiosError } from 'axios';
4
4
  import { useParams } from 'react-router-dom';
5
5
  import { Avatar, Button, FormControl, FormGroup, FormLabel, useToggle } from '@openedx/paragon';
@@ -8,7 +8,7 @@ import { SpinnerIcon } from '@openedx/paragon/icons';
8
8
  import { useDebouncedFilter } from '../hooks/useDebouncedFilter';
9
9
  import { useCourseInfo, useLearner } from '../data/apiHook';
10
10
  import messages from './messages';
11
- const SpecifyLearnerField = ({ learner, onClickSelect }) => {
11
+ const SpecifyLearnerField = forwardRef(({ learner, onClickSelect }, ref) => {
12
12
  var _a;
13
13
  const intl = useIntl();
14
14
  const { courseId = '' } = useParams();
@@ -16,11 +16,17 @@ const SpecifyLearnerField = ({ learner, onClickSelect }) => {
16
16
  const [showLearner, enableShowLearner, disableShowLearner] = useToggle(false);
17
17
  const { data: courseInfo } = useCourseInfo(courseId);
18
18
  const permissions = (courseInfo === null || courseInfo === void 0 ? void 0 : courseInfo.permissions) || { admin: false, dataResearcher: false };
19
- const { inputValue, handleChange } = useDebouncedFilter({
19
+ const { inputValue, handleChange, resetFilter } = useDebouncedFilter({
20
20
  filterValue: identifier,
21
21
  setFilter: setIdentifier,
22
22
  });
23
23
  const { data = { email: '', fullName: '', username: '' }, refetch, error } = useLearner(courseId, inputValue);
24
+ useImperativeHandle(ref, () => ({
25
+ reset: () => {
26
+ resetFilter();
27
+ disableShowLearner();
28
+ }
29
+ }));
24
30
  const selectedLearner = learner || data;
25
31
  const handleInputChange = (event) => {
26
32
  handleChange(event.target.value);
@@ -30,15 +36,20 @@ const SpecifyLearnerField = ({ learner, onClickSelect }) => {
30
36
  };
31
37
  const handleClickSelect = () => {
32
38
  if (inputValue) {
33
- onClickSelect(inputValue);
34
- refetch();
35
- enableShowLearner();
39
+ refetch().then((result) => {
40
+ // Need to pass empty value if learner is not valid to clear out any previously selected learner
41
+ // We could have other conditions/fields depending on valid learner
42
+ const formValue = !result.error ? inputValue : '';
43
+ onClickSelect(formValue);
44
+ enableShowLearner();
45
+ });
36
46
  }
37
47
  };
38
48
  return (_jsxs(FormGroup, { className: "mb-0", size: "sm", children: [_jsx(FormLabel, { className: "text-primary-500 d-flex", children: intl.formatMessage(messages.specifyLearner) }), _jsxs("div", { className: "d-flex align-items-center", children: [_jsx(FormControl, { className: `mr-2 ${selectedLearner.username && showLearner ? 'd-none' : ''}`, name: "emailOrUsername", placeholder: intl.formatMessage(messages.specifyLearnerPlaceholder), size: "md", autoResize: true, value: inputValue, onChange: handleInputChange }), selectedLearner.username && showLearner ? (_jsxs(_Fragment, { children: [_jsx(Avatar, { className: "mr-2.5", size: "sm" }), _jsxs("div", { className: "d-flex flex-column mr-3 text-primary-500", children: [_jsx("p", { className: "mb-0", children: selectedLearner.username }), (permissions.admin || permissions.dataResearcher)
39
49
  && (_jsxs("div", { className: "d-flex x-small", children: [_jsx("p", { className: "mr-3 mb-0", children: selectedLearner.fullName }), _jsx("p", { className: "mb-0", children: selectedLearner.email })] }))] }), !learner && _jsx(Button, { iconBefore: SpinnerIcon, onClick: disableShowLearner, children: intl.formatMessage(messages.change) })] })) : (_jsx(Button, { onClick: handleClickSelect, disabled: !inputValue, children: intl.formatMessage(messages.select) }))] }), showLearner && error
40
50
  && isAxiosError(error)
41
51
  && ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 404 && (_jsx("p", { className: "text-danger-500 mb-0 x-small mt-2", children: intl.formatMessage(messages.learnerNotFound, { identifier }) }))] }));
42
- };
52
+ });
53
+ SpecifyLearnerField.displayName = 'SpecifyLearnerField';
43
54
  export default SpecifyLearnerField;
44
55
  //# sourceMappingURL=SpecifyLearnerField.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SpecifyLearnerField.js","sourceRoot":"","sources":["../../src/components/SpecifyLearnerField.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useState, ChangeEvent } from 'react';\nimport { isAxiosError } from 'axios';\nimport { useParams } from 'react-router-dom';\nimport { Avatar, Button, FormControl, FormGroup, FormLabel, useToggle } from '@openedx/paragon';\nimport { useIntl } from '@openedx/frontend-base';\nimport { SpinnerIcon } from '@openedx/paragon/icons';\nimport { useDebouncedFilter } from '@src/hooks/useDebouncedFilter';\nimport { useCourseInfo, useLearner } from '@src/data/apiHook';\nimport { SelectedLearner } from '@src/types';\nimport messages from './messages';\n\ninterface SpecifyLearnerFieldProps {\n learner?: SelectedLearner,\n onClickSelect: (emailOrUsername: string) => void,\n}\n\nconst SpecifyLearnerField = ({ learner, onClickSelect }: SpecifyLearnerFieldProps) => {\n const intl = useIntl();\n const { courseId = '' } = useParams<{ courseId: string }>();\n const [identifier, setIdentifier] = useState('');\n const [showLearner, enableShowLearner, disableShowLearner] = useToggle(false);\n const { data: courseInfo } = useCourseInfo(courseId);\n const permissions = courseInfo?.permissions || { admin: false, dataResearcher: false };\n const { inputValue, handleChange } = useDebouncedFilter({\n filterValue: identifier,\n setFilter: setIdentifier,\n });\n const { data = { email: '', fullName: '', username: '' }, refetch, error } = useLearner(courseId, inputValue);\n\n const selectedLearner = learner || data;\n\n const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {\n handleChange(event.target.value);\n\n if (showLearner) {\n disableShowLearner();\n }\n };\n\n const handleClickSelect = () => {\n if (inputValue) {\n onClickSelect(inputValue);\n refetch();\n enableShowLearner();\n }\n };\n\n return (\n <FormGroup className=\"mb-0\" size=\"sm\">\n <FormLabel className=\"text-primary-500 d-flex\">{intl.formatMessage(messages.specifyLearner)}</FormLabel>\n <div className=\"d-flex align-items-center\">\n <FormControl\n className={`mr-2 ${selectedLearner.username && showLearner ? 'd-none' : ''}`}\n name=\"emailOrUsername\"\n placeholder={intl.formatMessage(messages.specifyLearnerPlaceholder)}\n size=\"md\"\n autoResize\n value={inputValue}\n onChange={handleInputChange}\n />\n {selectedLearner.username && showLearner ? (\n <>\n <Avatar className=\"mr-2.5\" size=\"sm\" />\n <div className=\"d-flex flex-column mr-3 text-primary-500\">\n <p className=\"mb-0\">{selectedLearner.username}</p>\n {(permissions.admin || permissions.dataResearcher)\n && (\n <div className=\"d-flex x-small\">\n <p className=\"mr-3 mb-0\">{selectedLearner.fullName}</p>\n <p className=\"mb-0\">{selectedLearner.email}</p>\n </div>\n )}\n </div>\n {!learner && <Button iconBefore={SpinnerIcon} onClick={disableShowLearner}>{intl.formatMessage(messages.change)}</Button>}\n </>\n ) : (\n <Button onClick={handleClickSelect} disabled={!inputValue}>{intl.formatMessage(messages.select)}</Button>\n )}\n </div>\n {showLearner && error\n && isAxiosError(error)\n && error.response?.status === 404 && (\n <p className=\"text-danger-500 mb-0 x-small mt-2\">\n {intl.formatMessage(messages.learnerNotFound, { identifier })}\n </p>\n )}\n </FormGroup>\n );\n};\n\nexport default SpecifyLearnerField;\n"]}
1
+ {"version":3,"file":"SpecifyLearnerField.js","sourceRoot":"","sources":["../../src/components/SpecifyLearnerField.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAe,mBAAmB,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAChG,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE9D,OAAO,QAAQ,MAAM,YAAY,CAAC;AAWlC,MAAM,mBAAmB,GAAG,UAAU,CAAmD,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE,GAAG,EAAE,EAAE;;IAC3H,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,EAAE,QAAQ,GAAG,EAAE,EAAE,GAAG,SAAS,EAAwB,CAAC;IAC5D,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACjD,MAAM,CAAC,WAAW,EAAE,iBAAiB,EAAE,kBAAkB,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IAC9E,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IACrD,MAAM,WAAW,GAAG,CAAA,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,WAAW,KAAI,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC;IACvF,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,GAAG,kBAAkB,CAAC;QACnE,WAAW,EAAE,UAAU;QACvB,SAAS,EAAE,aAAa;KACzB,CAAC,CAAC;IACH,MAAM,EAAE,IAAI,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAE9G,mBAAmB,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;QAC9B,KAAK,EAAE,GAAG,EAAE;YACV,WAAW,EAAE,CAAC;YACd,kBAAkB,EAAE,CAAC;QACvB,CAAC;KACF,CAAC,CAAC,CAAC;IAEJ,MAAM,eAAe,GAAG,OAAO,IAAI,IAAI,CAAC;IAExC,MAAM,iBAAiB,GAAG,CAAC,KAAoC,EAAE,EAAE;QACjE,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAEjC,IAAI,WAAW,EAAE,CAAC;YAChB,kBAAkB,EAAE,CAAC;QACvB,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,iBAAiB,GAAG,GAAG,EAAE;QAC7B,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;gBACxB,gGAAgG;gBAChG,mEAAmE;gBACnE,MAAM,SAAS,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;gBAClD,aAAa,CAAC,SAAS,CAAC,CAAC;gBACzB,iBAAiB,EAAE,CAAC;YACtB,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,CACL,MAAC,SAAS,IAAC,SAAS,EAAC,MAAM,EAAC,IAAI,EAAC,IAAI,aACnC,KAAC,SAAS,IAAC,SAAS,EAAC,yBAAyB,YAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,cAAc,CAAC,GAAa,EACxG,eAAK,SAAS,EAAC,2BAA2B,aACxC,KAAC,WAAW,IACV,SAAS,EAAE,QAAQ,eAAe,CAAC,QAAQ,IAAI,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,EAC5E,IAAI,EAAC,iBAAiB,EACtB,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,yBAAyB,CAAC,EACnE,IAAI,EAAC,IAAI,EACT,UAAU,QACV,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,iBAAiB,GAC3B,EACD,eAAe,CAAC,QAAQ,IAAI,WAAW,CAAC,CAAC,CAAC,CACzC,8BACE,KAAC,MAAM,IAAC,SAAS,EAAC,QAAQ,EAAC,IAAI,EAAC,IAAI,GAAG,EACvC,eAAK,SAAS,EAAC,0CAA0C,aACvD,YAAG,SAAS,EAAC,MAAM,YAAE,eAAe,CAAC,QAAQ,GAAK,EACjD,CAAC,WAAW,CAAC,KAAK,IAAI,WAAW,CAAC,cAAc,CAAC;2CAC/C,CACD,eAAK,SAAS,EAAC,gBAAgB,aAC7B,YAAG,SAAS,EAAC,WAAW,YAAE,eAAe,CAAC,QAAQ,GAAK,EACvD,YAAG,SAAS,EAAC,MAAM,YAAE,eAAe,CAAC,KAAK,GAAK,IAC3C,CACP,IACG,EACL,CAAC,OAAO,IAAI,KAAC,MAAM,IAAC,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,kBAAkB,YAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAU,IACxH,CACJ,CAAC,CAAC,CAAC,CACF,KAAC,MAAM,IAAC,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,CAAC,UAAU,YAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAU,CAC1G,IACG,EACL,WAAW,IAAI,KAAK;mBAClB,YAAY,CAAC,KAAK,CAAC;mBACnB,CAAA,MAAA,KAAK,CAAC,QAAQ,0CAAE,MAAM,MAAK,GAAG,IAAI,CACnC,YAAG,SAAS,EAAC,mCAAmC,YAC7C,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,eAAe,EAAE,EAAE,UAAU,EAAE,CAAC,GAC3D,CACL,IACS,CACb,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,mBAAmB,CAAC,WAAW,GAAG,qBAAqB,CAAC;AAExD,eAAe,mBAAmB,CAAC","sourcesContent":["import { useState, ChangeEvent, useImperativeHandle, forwardRef } from 'react';\nimport { isAxiosError } from 'axios';\nimport { useParams } from 'react-router-dom';\nimport { Avatar, Button, FormControl, FormGroup, FormLabel, useToggle } from '@openedx/paragon';\nimport { useIntl } from '@openedx/frontend-base';\nimport { SpinnerIcon } from '@openedx/paragon/icons';\nimport { useDebouncedFilter } from '@src/hooks/useDebouncedFilter';\nimport { useCourseInfo, useLearner } from '@src/data/apiHook';\nimport { SelectedLearner } from '@src/types';\nimport messages from './messages';\n\ninterface SpecifyLearnerFieldProps {\n learner?: SelectedLearner,\n onClickSelect: (emailOrUsername: string) => void,\n}\n\ninterface SpecifyLearnerFieldRef {\n reset: () => void,\n}\n\nconst SpecifyLearnerField = forwardRef<SpecifyLearnerFieldRef, SpecifyLearnerFieldProps>(({ learner, onClickSelect }, ref) => {\n const intl = useIntl();\n const { courseId = '' } = useParams<{ courseId: string }>();\n const [identifier, setIdentifier] = useState('');\n const [showLearner, enableShowLearner, disableShowLearner] = useToggle(false);\n const { data: courseInfo } = useCourseInfo(courseId);\n const permissions = courseInfo?.permissions || { admin: false, dataResearcher: false };\n const { inputValue, handleChange, resetFilter } = useDebouncedFilter({\n filterValue: identifier,\n setFilter: setIdentifier,\n });\n const { data = { email: '', fullName: '', username: '' }, refetch, error } = useLearner(courseId, inputValue);\n\n useImperativeHandle(ref, () => ({\n reset: () => {\n resetFilter();\n disableShowLearner();\n }\n }));\n\n const selectedLearner = learner || data;\n\n const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {\n handleChange(event.target.value);\n\n if (showLearner) {\n disableShowLearner();\n }\n };\n\n const handleClickSelect = () => {\n if (inputValue) {\n refetch().then((result) => {\n // Need to pass empty value if learner is not valid to clear out any previously selected learner\n // We could have other conditions/fields depending on valid learner\n const formValue = !result.error ? inputValue : '';\n onClickSelect(formValue);\n enableShowLearner();\n });\n }\n };\n\n return (\n <FormGroup className=\"mb-0\" size=\"sm\">\n <FormLabel className=\"text-primary-500 d-flex\">{intl.formatMessage(messages.specifyLearner)}</FormLabel>\n <div className=\"d-flex align-items-center\">\n <FormControl\n className={`mr-2 ${selectedLearner.username && showLearner ? 'd-none' : ''}`}\n name=\"emailOrUsername\"\n placeholder={intl.formatMessage(messages.specifyLearnerPlaceholder)}\n size=\"md\"\n autoResize\n value={inputValue}\n onChange={handleInputChange}\n />\n {selectedLearner.username && showLearner ? (\n <>\n <Avatar className=\"mr-2.5\" size=\"sm\" />\n <div className=\"d-flex flex-column mr-3 text-primary-500\">\n <p className=\"mb-0\">{selectedLearner.username}</p>\n {(permissions.admin || permissions.dataResearcher)\n && (\n <div className=\"d-flex x-small\">\n <p className=\"mr-3 mb-0\">{selectedLearner.fullName}</p>\n <p className=\"mb-0\">{selectedLearner.email}</p>\n </div>\n )}\n </div>\n {!learner && <Button iconBefore={SpinnerIcon} onClick={disableShowLearner}>{intl.formatMessage(messages.change)}</Button>}\n </>\n ) : (\n <Button onClick={handleClickSelect} disabled={!inputValue}>{intl.formatMessage(messages.select)}</Button>\n )}\n </div>\n {showLearner && error\n && isAxiosError(error)\n && error.response?.status === 404 && (\n <p className=\"text-danger-500 mb-0 x-small mt-2\">\n {intl.formatMessage(messages.learnerNotFound, { identifier })}\n </p>\n )}\n </FormGroup>\n );\n});\n\nSpecifyLearnerField.displayName = 'SpecifyLearnerField';\n\nexport default SpecifyLearnerField;\n"]}
@@ -0,0 +1,13 @@
1
+ interface SpecifyProblemFieldProps {
2
+ buttonLabel: string;
3
+ disabled?: boolean;
4
+ fieldLabel: string;
5
+ problemResponsesError?: string;
6
+ usernameOrEmail?: string;
7
+ onClickSelect: (problemLocation: string, event: React.MouseEvent<HTMLButtonElement>) => void;
8
+ }
9
+ interface SpecifyProblemFieldRef {
10
+ reset: () => void;
11
+ }
12
+ declare const SpecifyProblemField: import("react").ForwardRefExoticComponent<SpecifyProblemFieldProps & import("react").RefAttributes<SpecifyProblemFieldRef>>;
13
+ export default SpecifyProblemField;
@@ -0,0 +1,46 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useImperativeHandle, forwardRef } from 'react';
3
+ import { useParams } from 'react-router-dom';
4
+ import { Button, Form, Icon, OverlayTrigger, Tooltip, useToggle } from '@openedx/paragon';
5
+ import { InfoOutline, SpinnerIcon } from '@openedx/paragon/icons';
6
+ import { useIntl } from '@openedx/frontend-base';
7
+ import messages from './messages';
8
+ import { useDebouncedFilter } from '../hooks/useDebouncedFilter';
9
+ import { useProblemDetails } from '../data/apiHook';
10
+ const SpecifyProblemField = forwardRef(({ buttonLabel, disabled, fieldLabel, problemResponsesError, usernameOrEmail = '', onClickSelect, }, ref) => {
11
+ const intl = useIntl();
12
+ const { courseId = '' } = useParams();
13
+ const [problemLocation, setProblemLocation] = useState('');
14
+ const [showSelectedLocation, enableShowSelectedLocation, disableShowSelectedLocation] = useToggle(false);
15
+ const { inputValue, handleChange, resetFilter } = useDebouncedFilter({
16
+ filterValue: problemLocation,
17
+ setFilter: setProblemLocation,
18
+ });
19
+ const { data = { breadcrumbs: [], name: '', id: '' }, refetch } = useProblemDetails(courseId, inputValue, usernameOrEmail);
20
+ useImperativeHandle(ref, () => ({
21
+ reset: () => {
22
+ resetFilter();
23
+ disableShowSelectedLocation();
24
+ }
25
+ }));
26
+ const handleInputChange = (e) => {
27
+ handleChange(e.target.value);
28
+ if (showSelectedLocation) {
29
+ disableShowSelectedLocation();
30
+ }
31
+ };
32
+ const handleClick = (event) => {
33
+ refetch().then(() => {
34
+ onClickSelect(inputValue, event);
35
+ enableShowSelectedLocation();
36
+ });
37
+ };
38
+ return (_jsxs(Form.Group, { className: "mb-0", isInvalid: !!problemResponsesError, size: "sm", children: [_jsx(Form.Label, { className: "d-flex align-content-end align-items-center gap-2 text-primary-500", children: showSelectedLocation ? intl.formatMessage(messages.selectedProblem)
39
+ : (_jsxs(_Fragment, { children: [fieldLabel, _jsx(OverlayTrigger, { placement: "top", overlay: (_jsx(Tooltip, { id: "problem-location-tooltip", className: "info-tooltip", children: intl.formatMessage(messages.problemLocationTooltip) })), children: _jsx(Icon, { src: InfoOutline, size: "sm", "aria-label": intl.formatMessage(messages.problemLocationInfoIconLabel) }) })] })) }), _jsx("div", { className: "d-flex align-items-center", children: showSelectedLocation && data ? (_jsxs("div", { className: "d-flex gap-3 align-items-center col-8 p-0", children: [_jsxs("div", { className: "d-block w-100", children: [_jsx("p", { className: "x-small mb-0 text-primary-500 text-truncate", children: data.breadcrumbs
40
+ .slice(1, -1)
41
+ .map(breadcrumb => breadcrumb.displayName)
42
+ .join(' > ') }), _jsx("p", { className: "text-primary-500 mb-0", children: data.name }), _jsx("p", { className: "x-small text-gray-700 text-truncate mb-0", children: data.id })] }), _jsx(Button, { iconBefore: SpinnerIcon, onClick: disableShowSelectedLocation, children: intl.formatMessage(messages.change) })] })) : (_jsxs(_Fragment, { children: [_jsx(Form.Control, { type: "text", placeholder: intl.formatMessage(messages.problemLocationPlaceholder), value: inputValue, onChange: handleInputChange, className: "flex-grow-1", size: "md" }), problemResponsesError && (_jsx(Form.Control.Feedback, { type: "invalid", children: problemResponsesError })), _jsx(Button, { variant: "primary", onClick: handleClick, disabled: disabled || !inputValue, className: "text-nowrap", children: buttonLabel })] })) })] }));
43
+ });
44
+ SpecifyProblemField.displayName = 'SpecifyProblemField';
45
+ export default SpecifyProblemField;
46
+ //# sourceMappingURL=SpecifyProblemField.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SpecifyProblemField.js","sourceRoot":"","sources":["../../src/components/SpecifyProblemField.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useState, useImperativeHandle, forwardRef } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { Button, Form, Icon, OverlayTrigger, Tooltip, useToggle } from '@openedx/paragon';\nimport { InfoOutline, SpinnerIcon } from '@openedx/paragon/icons';\nimport { useIntl } from '@openedx/frontend-base';\nimport messages from './messages';\nimport { useDebouncedFilter } from '@src/hooks/useDebouncedFilter';\nimport { useProblemDetails } from '@src/data/apiHook';\n\ninterface SpecifyProblemFieldProps {\n buttonLabel: string,\n disabled?: boolean,\n fieldLabel: string,\n problemResponsesError?: string,\n usernameOrEmail?: string,\n onClickSelect: (problemLocation: string, event: React.MouseEvent<HTMLButtonElement>) => void,\n}\n\ninterface SpecifyProblemFieldRef {\n reset: () => void,\n}\n\nconst SpecifyProblemField = forwardRef<SpecifyProblemFieldRef, SpecifyProblemFieldProps>(({\n buttonLabel,\n disabled,\n fieldLabel,\n problemResponsesError,\n usernameOrEmail = '',\n onClickSelect,\n}, ref) => {\n const intl = useIntl();\n const { courseId = '' } = useParams<{ courseId: string }>();\n const [problemLocation, setProblemLocation] = useState('');\n const [showSelectedLocation, enableShowSelectedLocation, disableShowSelectedLocation] = useToggle(false);\n\n const { inputValue, handleChange, resetFilter } = useDebouncedFilter({\n filterValue: problemLocation,\n setFilter: setProblemLocation,\n });\n const { data = { breadcrumbs: [], name: '', id: '' }, refetch } = useProblemDetails(courseId, inputValue, usernameOrEmail);\n\n useImperativeHandle(ref, () => ({\n reset: () => {\n resetFilter();\n disableShowSelectedLocation();\n }\n }));\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n handleChange(e.target.value);\n\n if (showSelectedLocation) {\n disableShowSelectedLocation();\n }\n };\n\n const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n refetch().then(() => {\n onClickSelect(inputValue, event);\n enableShowSelectedLocation();\n });\n };\n\n return (\n <Form.Group className=\"mb-0\" isInvalid={!!problemResponsesError} size=\"sm\">\n <Form.Label className=\"d-flex align-content-end align-items-center gap-2 text-primary-500\">\n {showSelectedLocation ? intl.formatMessage(messages.selectedProblem)\n : (\n <>\n {fieldLabel}\n <OverlayTrigger\n placement=\"top\"\n overlay={(\n <Tooltip id=\"problem-location-tooltip\" className=\"info-tooltip\">\n {intl.formatMessage(messages.problemLocationTooltip)}\n </Tooltip>\n )}\n >\n <Icon src={InfoOutline} size=\"sm\" aria-label={intl.formatMessage(messages.problemLocationInfoIconLabel)} />\n </OverlayTrigger>\n </>\n )}\n </Form.Label>\n <div className=\"d-flex align-items-center\">\n {showSelectedLocation && data ? (\n <div className=\"d-flex gap-3 align-items-center col-8 p-0\">\n <div className=\"d-block w-100\">\n <p className=\"x-small mb-0 text-primary-500 text-truncate\">\n {data.breadcrumbs\n .slice(1, -1)\n .map(breadcrumb => breadcrumb.displayName)\n .join(' > ')}\n </p>\n <p className=\"text-primary-500 mb-0\">{data.name}</p>\n <p className=\"x-small text-gray-700 text-truncate mb-0\">{data.id}</p>\n </div>\n <Button iconBefore={SpinnerIcon} onClick={disableShowSelectedLocation}>{intl.formatMessage(messages.change)}</Button>\n </div>\n ) : (\n <>\n <Form.Control\n type=\"text\"\n placeholder={intl.formatMessage(messages.problemLocationPlaceholder)}\n value={inputValue}\n onChange={handleInputChange}\n className=\"flex-grow-1\"\n size=\"md\"\n />\n {problemResponsesError && (\n <Form.Control.Feedback type=\"invalid\">\n {problemResponsesError}\n </Form.Control.Feedback>\n )}\n <Button\n variant=\"primary\"\n onClick={handleClick}\n disabled={disabled || !inputValue}\n className=\"text-nowrap\"\n >\n {buttonLabel}\n </Button>\n </>\n )}\n </div>\n </Form.Group>\n );\n});\n\nSpecifyProblemField.displayName = 'SpecifyProblemField';\n\nexport default SpecifyProblemField;\n"]}
@@ -119,5 +119,25 @@ declare const messages: {
119
119
  defaultMessage: string;
120
120
  description: string;
121
121
  };
122
+ problemLocationPlaceholder: {
123
+ id: string;
124
+ defaultMessage: string;
125
+ description: string;
126
+ };
127
+ problemLocationInfoIconLabel: {
128
+ id: string;
129
+ defaultMessage: string;
130
+ description: string;
131
+ };
132
+ problemLocationTooltip: {
133
+ id: string;
134
+ defaultMessage: string;
135
+ description: string;
136
+ };
137
+ selectedProblem: {
138
+ id: string;
139
+ defaultMessage: string;
140
+ description: string;
141
+ };
122
142
  };
123
143
  export default messages;
@@ -119,6 +119,26 @@ const messages = defineMessages({
119
119
  id: 'instruct.usernameFilter.searchPlaceholder',
120
120
  defaultMessage: 'Search By Username or Email',
121
121
  description: 'Placeholder text for the username filter input',
122
+ },
123
+ problemLocationPlaceholder: {
124
+ id: 'instruct.specifyProblemField.locationPlaceholder',
125
+ defaultMessage: 'Problem location',
126
+ description: 'Placeholder text for problem location input',
127
+ },
128
+ problemLocationInfoIconLabel: {
129
+ id: 'instruct.specifyProblemField.infoIconLabel',
130
+ defaultMessage: 'Example format for problem location',
131
+ description: 'Aria label for the info icon next to the problem location input',
132
+ },
133
+ problemLocationTooltip: {
134
+ id: 'instruct.specifyProblemField.locationTooltip',
135
+ defaultMessage: 'Example: block-v1:edX+DemoX+2015+type@problem+block@618c5933b8b544e4a4cc103d3e508378',
136
+ description: 'Tooltip text showing an example problem location format',
137
+ },
138
+ selectedProblem: {
139
+ id: 'instruct.specifyProblemField.selectedProblem',
140
+ defaultMessage: 'Selected Problem:',
141
+ description: 'Label for specify problem field when a problem has been selected',
122
142
  }
123
143
  });
124
144
  export default messages;
@@ -1 +1 @@
1
- {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/components/messages.ts"],"names":[],"mappings":"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","sourcesContent":["import { defineMessages } from '@openedx/frontend-base';\n\nconst messages = defineMessages({\n select: {\n id: 'instruct.specifyLearner.select',\n defaultMessage: 'Select',\n description: 'Label for select dropdown in specify learner field',\n },\n specifyLearner: {\n id: 'instruct.specifyLearner.label',\n defaultMessage: 'Specify Learner:',\n description: 'Label for specify learner field',\n },\n specifyLearnerPlaceholder: {\n id: 'instruct.specifyLearner.placeholder',\n defaultMessage: 'Learner email address or username',\n description: 'Placeholder text for specify learner input field',\n },\n pageNotFoundHeader: {\n id: 'instruct.pageNotFound.header',\n defaultMessage: 'Page not found',\n description: 'Header for page not found error',\n },\n pageNotFoundBody: {\n id: 'instruct.pageNotFound.body',\n defaultMessage: \"The page you're looking for is unavailable or there's an error in the URL. Please check the URL and try again.\",\n description: 'Body text for page not found error',\n },\n pendingTasksTitle: {\n id: 'instruct.pendingTasks.section.title',\n defaultMessage: 'Pending Tasks',\n description: 'Title for the pending tasks section',\n },\n noTasksMessage: {\n id: 'instruct.pendingTasks.section.noTasks',\n defaultMessage: 'No tasks currently running.',\n description: 'Message displayed when there are no pending tasks',\n },\n taskTypeColumnName: {\n id: 'instruct.pendingTasks.table.column.taskType',\n defaultMessage: 'Task Type',\n description: 'Column name for task type in pending tasks table',\n },\n taskInputColumnName: {\n id: 'instruct.pendingTasks.table.column.taskInput',\n defaultMessage: 'Task Input',\n description: 'Column name for task input in pending tasks table',\n },\n taskIdColumnName: {\n id: 'instruct.pendingTasks.table.column.taskId',\n defaultMessage: 'Task ID',\n description: 'Column name for task ID in pending tasks table',\n },\n requesterColumnName: {\n id: 'instruct.pendingTasks.table.column.requester',\n defaultMessage: 'Requester',\n description: 'Column name for requester in pending tasks table',\n },\n taskStateColumnName: {\n id: 'instruct.pendingTasks.table.column.taskState',\n defaultMessage: 'Task State',\n description: 'Column name for task state in pending tasks table',\n },\n createdColumnName: {\n id: 'instruct.pendingTasks.table.column.created',\n defaultMessage: 'Created',\n description: 'Column name for created date in pending tasks table',\n },\n taskOutputColumnName: {\n id: 'instruct.pendingTasks.table.column.taskOutput',\n defaultMessage: 'Task Output',\n description: 'Column name for task output in pending tasks table',\n },\n durationColumnName: {\n id: 'instruct.pendingTasks.table.column.duration',\n defaultMessage: 'Duration (sec)',\n description: 'Column name for duration in pending tasks table',\n },\n statusColumnName: {\n id: 'instruct.pendingTasks.table.column.status',\n defaultMessage: 'Status',\n description: 'Column name for status in pending tasks table',\n },\n taskMessageColumnName: {\n id: 'instruct.pendingTasks.table.column.taskMessage',\n defaultMessage: 'Task Message',\n description: 'Column name for task message in pending tasks table',\n },\n downloadCSVTitle: {\n id: 'instruct.csvComponent.downloadCSVTitle',\n defaultMessage: 'Upload CSV File',\n description: 'Title for the upload CSV file section'\n },\n downloadCSVDescription: {\n id: 'instruct.csvComponent.downloadCSVDescription',\n defaultMessage: 'Only properly formatted CSV files will be accepted',\n description: 'Description for the upload CSV file section'\n },\n viewCSVTemplate: {\n id: 'instruct.csvComponent.viewCSVTemplate',\n defaultMessage: 'View Template',\n description: 'Label for the view CSV template link'\n },\n uploadingFileMessage: {\n id: 'instruct.csvComponent.uploadingFileMessage',\n defaultMessage: 'File chosen: {fileName}',\n description: 'Message displayed when a file is being uploaded, with the file name included'\n },\n change: {\n id: 'instruct.specifyLearner.change',\n defaultMessage: 'Change',\n description: 'Label for change button in specify learner field',\n },\n learnerNotFound: {\n id: 'instruct.specifyLearner.learnerNotFound',\n defaultMessage: 'Could not find student matching identifier: {identifier}',\n description: 'Error message displayed when a learner cannot be found based on the provided identifier (email or username)',\n },\n searchPlaceholder: {\n id: 'instruct.usernameFilter.searchPlaceholder',\n defaultMessage: 'Search By Username or Email',\n description: 'Placeholder text for the username filter input',\n }\n});\n\nexport default messages;\n"]}
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/components/messages.ts"],"names":[],"mappings":"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","sourcesContent":["import { defineMessages } from '@openedx/frontend-base';\n\nconst messages = defineMessages({\n select: {\n id: 'instruct.specifyLearner.select',\n defaultMessage: 'Select',\n description: 'Label for select dropdown in specify learner field',\n },\n specifyLearner: {\n id: 'instruct.specifyLearner.label',\n defaultMessage: 'Specify Learner:',\n description: 'Label for specify learner field',\n },\n specifyLearnerPlaceholder: {\n id: 'instruct.specifyLearner.placeholder',\n defaultMessage: 'Learner email address or username',\n description: 'Placeholder text for specify learner input field',\n },\n pageNotFoundHeader: {\n id: 'instruct.pageNotFound.header',\n defaultMessage: 'Page not found',\n description: 'Header for page not found error',\n },\n pageNotFoundBody: {\n id: 'instruct.pageNotFound.body',\n defaultMessage: \"The page you're looking for is unavailable or there's an error in the URL. Please check the URL and try again.\",\n description: 'Body text for page not found error',\n },\n pendingTasksTitle: {\n id: 'instruct.pendingTasks.section.title',\n defaultMessage: 'Pending Tasks',\n description: 'Title for the pending tasks section',\n },\n noTasksMessage: {\n id: 'instruct.pendingTasks.section.noTasks',\n defaultMessage: 'No tasks currently running.',\n description: 'Message displayed when there are no pending tasks',\n },\n taskTypeColumnName: {\n id: 'instruct.pendingTasks.table.column.taskType',\n defaultMessage: 'Task Type',\n description: 'Column name for task type in pending tasks table',\n },\n taskInputColumnName: {\n id: 'instruct.pendingTasks.table.column.taskInput',\n defaultMessage: 'Task Input',\n description: 'Column name for task input in pending tasks table',\n },\n taskIdColumnName: {\n id: 'instruct.pendingTasks.table.column.taskId',\n defaultMessage: 'Task ID',\n description: 'Column name for task ID in pending tasks table',\n },\n requesterColumnName: {\n id: 'instruct.pendingTasks.table.column.requester',\n defaultMessage: 'Requester',\n description: 'Column name for requester in pending tasks table',\n },\n taskStateColumnName: {\n id: 'instruct.pendingTasks.table.column.taskState',\n defaultMessage: 'Task State',\n description: 'Column name for task state in pending tasks table',\n },\n createdColumnName: {\n id: 'instruct.pendingTasks.table.column.created',\n defaultMessage: 'Created',\n description: 'Column name for created date in pending tasks table',\n },\n taskOutputColumnName: {\n id: 'instruct.pendingTasks.table.column.taskOutput',\n defaultMessage: 'Task Output',\n description: 'Column name for task output in pending tasks table',\n },\n durationColumnName: {\n id: 'instruct.pendingTasks.table.column.duration',\n defaultMessage: 'Duration (sec)',\n description: 'Column name for duration in pending tasks table',\n },\n statusColumnName: {\n id: 'instruct.pendingTasks.table.column.status',\n defaultMessage: 'Status',\n description: 'Column name for status in pending tasks table',\n },\n taskMessageColumnName: {\n id: 'instruct.pendingTasks.table.column.taskMessage',\n defaultMessage: 'Task Message',\n description: 'Column name for task message in pending tasks table',\n },\n downloadCSVTitle: {\n id: 'instruct.csvComponent.downloadCSVTitle',\n defaultMessage: 'Upload CSV File',\n description: 'Title for the upload CSV file section'\n },\n downloadCSVDescription: {\n id: 'instruct.csvComponent.downloadCSVDescription',\n defaultMessage: 'Only properly formatted CSV files will be accepted',\n description: 'Description for the upload CSV file section'\n },\n viewCSVTemplate: {\n id: 'instruct.csvComponent.viewCSVTemplate',\n defaultMessage: 'View Template',\n description: 'Label for the view CSV template link'\n },\n uploadingFileMessage: {\n id: 'instruct.csvComponent.uploadingFileMessage',\n defaultMessage: 'File chosen: {fileName}',\n description: 'Message displayed when a file is being uploaded, with the file name included'\n },\n change: {\n id: 'instruct.specifyLearner.change',\n defaultMessage: 'Change',\n description: 'Label for change button in specify learner field',\n },\n learnerNotFound: {\n id: 'instruct.specifyLearner.learnerNotFound',\n defaultMessage: 'Could not find student matching identifier: {identifier}',\n description: 'Error message displayed when a learner cannot be found based on the provided identifier (email or username)',\n },\n searchPlaceholder: {\n id: 'instruct.usernameFilter.searchPlaceholder',\n defaultMessage: 'Search By Username or Email',\n description: 'Placeholder text for the username filter input',\n },\n problemLocationPlaceholder: {\n id: 'instruct.specifyProblemField.locationPlaceholder',\n defaultMessage: 'Problem location',\n description: 'Placeholder text for problem location input',\n },\n problemLocationInfoIconLabel: {\n id: 'instruct.specifyProblemField.infoIconLabel',\n defaultMessage: 'Example format for problem location',\n description: 'Aria label for the info icon next to the problem location input',\n },\n problemLocationTooltip: {\n id: 'instruct.specifyProblemField.locationTooltip',\n defaultMessage: 'Example: block-v1:edX+DemoX+2015+type@problem+block@618c5933b8b544e4a4cc103d3e508378',\n description: 'Tooltip text showing an example problem location format',\n },\n selectedProblem: {\n id: 'instruct.specifyProblemField.selectedProblem',\n defaultMessage: 'Selected Problem:',\n description: 'Label for specify problem field when a problem has been selected',\n }\n});\n\nexport default messages;\n"]}
@@ -20,3 +20,4 @@ export declare const fetchPendingTasks: (courseId: string) => Promise<any>;
20
20
  * @returns {Promise<SelectedLearner>}
21
21
  */
22
22
  export declare const getLearner: (courseId: string, emailOrUsername: string) => Promise<SelectedLearner>;
23
+ export declare const getProblemDetails: (courseId: string, blockId: string, emailOrUsername?: string) => Promise<any>;
package/dist/data/api.js CHANGED
@@ -40,4 +40,11 @@ export const getLearner = (courseId, emailOrUsername) => __awaiter(void 0, void
40
40
  .get(`${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/learners/${emailOrUsername}`);
41
41
  return camelCaseObject(data);
42
42
  });
43
+ export const getProblemDetails = (courseId, blockId, emailOrUsername) => __awaiter(void 0, void 0, void 0, function* () {
44
+ const { data } = yield getAuthenticatedHttpClient()
45
+ .get(`${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/problems/${blockId}`, {
46
+ params: { email_or_username: emailOrUsername },
47
+ });
48
+ return camelCaseObject(data);
49
+ });
43
50
  //# sourceMappingURL=api.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/data/api.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAIpG,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,EAAE,CAAC,aAAa,EAAE,CAAC,UAAU,CAAC;AAE9D;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAO,QAAgB,EAA+B,EAAE;IACnF,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,0BAA0B,EAAE;SAChD,GAAG,CAAC,GAAG,aAAa,EAAE,8BAA8B,QAAQ,EAAE,CAAC,CAAC;IACnE,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC,CAAA,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAO,QAAgB,EAAE,EAAE;;IAC1D,MAAM,QAAQ,GAAG,MAAM,0BAA0B,EAAE,CAAC,IAAI,CACtD,GAAG,aAAa,EAAE,YAAY,QAAQ,uCAAuC,CAC9E,CAAC;IACF,OAAO,MAAA,MAAA,QAAQ,CAAC,IAAI,0CAAE,KAAK,0CAAE,GAAG,CAAC,eAAe,CAAC,CAAC;AACpD,CAAC,CAAA,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAO,QAAgB,EAAE,eAAuB,EAA4B,EAAE;IACtG,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,0BAA0B,EAAE;SAChD,GAAG,CAAC,GAAG,aAAa,EAAE,8BAA8B,QAAQ,aAAa,eAAe,EAAE,CAAC,CAAC;IAC/F,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC,CAAA,CAAC","sourcesContent":["import { camelCaseObject, getSiteConfig, getAuthenticatedHttpClient } from '@openedx/frontend-base';\nimport { CourseInfoResponse } from '@src/courseInfo/types';\nimport { SelectedLearner } from '@src/types';\n\nexport const getApiBaseUrl = () => getSiteConfig().lmsBaseUrl;\n\n/**\n * Get course settings.\n * @param {string} courseId\n * @returns {Promise<Object>}\n */\nexport const getCourseInfo = async (courseId: string): Promise<CourseInfoResponse> => {\n const { data } = await getAuthenticatedHttpClient()\n .get(`${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}`);\n return camelCaseObject(data);\n};\n\n/**\n * Fetch pending instructor tasks for a course.\n * @param {string} courseId\n * @returns {Promise<Array>}\n */\nexport const fetchPendingTasks = async (courseId: string) => {\n const response = await getAuthenticatedHttpClient().post<{ results: Record<string, any>[] }>(\n `${getApiBaseUrl()}/courses/${courseId}/instructor/api/list_instructor_tasks`\n );\n return response.data?.tasks?.map(camelCaseObject);\n};\n\n/**\n * Get learner information for a course.\n * @param {string} courseId\n * @param {string} emailOrUsername\n * @returns {Promise<SelectedLearner>}\n */\nexport const getLearner = async (courseId: string, emailOrUsername: string): Promise<SelectedLearner> => {\n const { data } = await getAuthenticatedHttpClient()\n .get(`${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/learners/${emailOrUsername}`);\n return camelCaseObject(data);\n};\n"]}
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/data/api.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAIpG,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,EAAE,CAAC,aAAa,EAAE,CAAC,UAAU,CAAC;AAE9D;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAO,QAAgB,EAA+B,EAAE;IACnF,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,0BAA0B,EAAE;SAChD,GAAG,CAAC,GAAG,aAAa,EAAE,8BAA8B,QAAQ,EAAE,CAAC,CAAC;IACnE,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC,CAAA,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAO,QAAgB,EAAE,EAAE;;IAC1D,MAAM,QAAQ,GAAG,MAAM,0BAA0B,EAAE,CAAC,IAAI,CACtD,GAAG,aAAa,EAAE,YAAY,QAAQ,uCAAuC,CAC9E,CAAC;IACF,OAAO,MAAA,MAAA,QAAQ,CAAC,IAAI,0CAAE,KAAK,0CAAE,GAAG,CAAC,eAAe,CAAC,CAAC;AACpD,CAAC,CAAA,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAO,QAAgB,EAAE,eAAuB,EAA4B,EAAE;IACtG,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,0BAA0B,EAAE;SAChD,GAAG,CAAC,GAAG,aAAa,EAAE,8BAA8B,QAAQ,aAAa,eAAe,EAAE,CAAC,CAAC;IAC/F,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC,CAAA,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAO,QAAgB,EAAE,OAAe,EAAE,eAAwB,EAAE,EAAE;IACrG,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,0BAA0B,EAAE;SAChD,GAAG,CAAC,GAAG,aAAa,EAAE,8BAA8B,QAAQ,aAAa,OAAO,EAAE,EAAE;QACnF,MAAM,EAAE,EAAE,iBAAiB,EAAE,eAAe,EAAE;KAC/C,CAAC,CAAC;IACL,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC,CAAA,CAAC","sourcesContent":["import { camelCaseObject, getSiteConfig, getAuthenticatedHttpClient } from '@openedx/frontend-base';\nimport { CourseInfoResponse } from '@src/courseInfo/types';\nimport { SelectedLearner } from '@src/types';\n\nexport const getApiBaseUrl = () => getSiteConfig().lmsBaseUrl;\n\n/**\n * Get course settings.\n * @param {string} courseId\n * @returns {Promise<Object>}\n */\nexport const getCourseInfo = async (courseId: string): Promise<CourseInfoResponse> => {\n const { data } = await getAuthenticatedHttpClient()\n .get(`${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}`);\n return camelCaseObject(data);\n};\n\n/**\n * Fetch pending instructor tasks for a course.\n * @param {string} courseId\n * @returns {Promise<Array>}\n */\nexport const fetchPendingTasks = async (courseId: string) => {\n const response = await getAuthenticatedHttpClient().post<{ results: Record<string, any>[] }>(\n `${getApiBaseUrl()}/courses/${courseId}/instructor/api/list_instructor_tasks`\n );\n return response.data?.tasks?.map(camelCaseObject);\n};\n\n/**\n * Get learner information for a course.\n * @param {string} courseId\n * @param {string} emailOrUsername\n * @returns {Promise<SelectedLearner>}\n */\nexport const getLearner = async (courseId: string, emailOrUsername: string): Promise<SelectedLearner> => {\n const { data } = await getAuthenticatedHttpClient()\n .get(`${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/learners/${emailOrUsername}`);\n return camelCaseObject(data);\n};\n\nexport const getProblemDetails = async (courseId: string, blockId: string, emailOrUsername?: string) => {\n const { data } = await getAuthenticatedHttpClient()\n .get(`${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/problems/${blockId}`, {\n params: { email_or_username: emailOrUsername },\n });\n return camelCaseObject(data);\n};\n"]}
@@ -3,3 +3,4 @@ export declare const usePendingTasks: (courseId: string, options?: {
3
3
  enablePolling?: boolean;
4
4
  }) => import("@tanstack/react-query").UseQueryResult<any, Error>;
5
5
  export declare const useLearner: (courseId: string, emailOrUsername: string) => import("@tanstack/react-query").UseQueryResult<import("../types").SelectedLearner, Error>;
6
+ export declare const useProblemDetails: (courseId: string, blockId: string, emailOrUsername: string) => import("@tanstack/react-query").UseQueryResult<any, Error>;
@@ -8,8 +8,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { useQuery } from '@tanstack/react-query';
11
- import { fetchPendingTasks, getCourseInfo, getLearner } from './api';
12
- import { courseInfoQueryKeys, learnerQueryKeys, pendingTasksQueryKey } from './queryKeys';
11
+ import { fetchPendingTasks, getCourseInfo, getLearner, getProblemDetails } from './api';
12
+ import { courseInfoQueryKeys, learnerQueryKeys, pendingTasksQueryKey, problemQueryKeys } from './queryKeys';
13
13
  export const useCourseInfo = (courseId) => (useQuery({
14
14
  queryKey: courseInfoQueryKeys.byCourse(courseId),
15
15
  queryFn: () => getCourseInfo(courseId),
@@ -33,4 +33,12 @@ export const useLearner = (courseId, emailOrUsername) => (useQuery({
33
33
  refetchOnWindowFocus: false,
34
34
  refetchOnMount: false,
35
35
  }));
36
+ export const useProblemDetails = (courseId, blockId, emailOrUsername) => (useQuery({
37
+ queryKey: problemQueryKeys.byCourseAndLearner(courseId, blockId, emailOrUsername),
38
+ queryFn: () => getProblemDetails(courseId, blockId, emailOrUsername),
39
+ enabled: false,
40
+ retry: false,
41
+ refetchOnWindowFocus: false,
42
+ refetchOnMount: false,
43
+ }));
36
44
  //# sourceMappingURL=apiHook.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"apiHook.js","sourceRoot":"","sources":["../../src/data/apiHook.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAE1F,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,QAAgB,EAAE,EAAE,CAAC,CACjD,QAAQ,CAAC;IACP,QAAQ,EAAE,mBAAmB,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAChD,OAAO,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC;IACtC,OAAO,EAAE,CAAC,CAAC,QAAQ;IACnB,oBAAoB,EAAE,KAAK;IAC3B,cAAc,EAAE,KAAK;CACtB,CAAC,CACH,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,QAAgB,EAAE,OAAqC,EAAE,EAAE;IACzF,OAAO,QAAQ,CAAC;QACd,QAAQ,EAAE,oBAAoB,CAAC,QAAQ,CAAC,QAAQ,CAAC;QACjD,OAAO,EAAE,GAAS,EAAE,kDAAC,OAAA,iBAAiB,CAAC,QAAQ,CAAC,CAAA,GAAA;QAChD,OAAO,EAAE,CAAC,CAAC,QAAQ;QACnB,eAAe,EAAE,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,aAAa,EAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK;KACvD,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,QAAgB,EAAE,eAAuB,EAAE,EAAE,CAAC,CACvE,QAAQ,CAAC;IACP,QAAQ,EAAE,gBAAgB,CAAC,kBAAkB,CAAC,QAAQ,EAAE,eAAe,CAAC;IACxE,OAAO,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,eAAe,CAAC;IACpD,OAAO,EAAE,KAAK;IACd,KAAK,EAAE,KAAK;IACZ,oBAAoB,EAAE,KAAK;IAC3B,cAAc,EAAE,KAAK;CACtB,CAAC,CAAC,CAAC","sourcesContent":["import { useQuery } from '@tanstack/react-query';\nimport { fetchPendingTasks, getCourseInfo, getLearner } from './api';\nimport { courseInfoQueryKeys, learnerQueryKeys, pendingTasksQueryKey } from './queryKeys';\n\nexport const useCourseInfo = (courseId: string) => (\n useQuery({\n queryKey: courseInfoQueryKeys.byCourse(courseId),\n queryFn: () => getCourseInfo(courseId),\n enabled: !!courseId,\n refetchOnWindowFocus: false,\n refetchOnMount: false,\n })\n);\n\nexport const usePendingTasks = (courseId: string, options?: { enablePolling?: boolean }) => {\n return useQuery({\n queryKey: pendingTasksQueryKey.byCourse(courseId),\n queryFn: async () => fetchPendingTasks(courseId),\n enabled: !!courseId,\n refetchInterval: options?.enablePolling ? 3000 : false,\n });\n};\n\nexport const useLearner = (courseId: string, emailOrUsername: string) => (\n useQuery({\n queryKey: learnerQueryKeys.byCourseAndLearner(courseId, emailOrUsername),\n queryFn: () => getLearner(courseId, emailOrUsername),\n enabled: false,\n retry: false,\n refetchOnWindowFocus: false,\n refetchOnMount: false,\n }));\n"]}
1
+ {"version":3,"file":"apiHook.js","sourceRoot":"","sources":["../../src/data/apiHook.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AACxF,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE5G,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,QAAgB,EAAE,EAAE,CAAC,CACjD,QAAQ,CAAC;IACP,QAAQ,EAAE,mBAAmB,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAChD,OAAO,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC;IACtC,OAAO,EAAE,CAAC,CAAC,QAAQ;IACnB,oBAAoB,EAAE,KAAK;IAC3B,cAAc,EAAE,KAAK;CACtB,CAAC,CACH,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,QAAgB,EAAE,OAAqC,EAAE,EAAE;IACzF,OAAO,QAAQ,CAAC;QACd,QAAQ,EAAE,oBAAoB,CAAC,QAAQ,CAAC,QAAQ,CAAC;QACjD,OAAO,EAAE,GAAS,EAAE,kDAAC,OAAA,iBAAiB,CAAC,QAAQ,CAAC,CAAA,GAAA;QAChD,OAAO,EAAE,CAAC,CAAC,QAAQ;QACnB,eAAe,EAAE,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,aAAa,EAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK;KACvD,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,QAAgB,EAAE,eAAuB,EAAE,EAAE,CAAC,CACvE,QAAQ,CAAC;IACP,QAAQ,EAAE,gBAAgB,CAAC,kBAAkB,CAAC,QAAQ,EAAE,eAAe,CAAC;IACxE,OAAO,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,eAAe,CAAC;IACpD,OAAO,EAAE,KAAK;IACd,KAAK,EAAE,KAAK;IACZ,oBAAoB,EAAE,KAAK;IAC3B,cAAc,EAAE,KAAK;CACtB,CAAC,CAAC,CAAC;AAEN,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,QAAgB,EAAE,OAAe,EAAE,eAAuB,EAAE,EAAE,CAAC,CAC/F,QAAQ,CAAC;IACP,QAAQ,EAAE,gBAAgB,CAAC,kBAAkB,CAAC,QAAQ,EAAE,OAAO,EAAE,eAAe,CAAC;IACjF,OAAO,EAAE,GAAG,EAAE,CAAC,iBAAiB,CAAC,QAAQ,EAAE,OAAO,EAAE,eAAe,CAAC;IACpE,OAAO,EAAE,KAAK;IACd,KAAK,EAAE,KAAK;IACZ,oBAAoB,EAAE,KAAK;IAC3B,cAAc,EAAE,KAAK;CACtB,CAAC,CAAC,CAAC","sourcesContent":["import { useQuery } from '@tanstack/react-query';\nimport { fetchPendingTasks, getCourseInfo, getLearner, getProblemDetails } from './api';\nimport { courseInfoQueryKeys, learnerQueryKeys, pendingTasksQueryKey, problemQueryKeys } from './queryKeys';\n\nexport const useCourseInfo = (courseId: string) => (\n useQuery({\n queryKey: courseInfoQueryKeys.byCourse(courseId),\n queryFn: () => getCourseInfo(courseId),\n enabled: !!courseId,\n refetchOnWindowFocus: false,\n refetchOnMount: false,\n })\n);\n\nexport const usePendingTasks = (courseId: string, options?: { enablePolling?: boolean }) => {\n return useQuery({\n queryKey: pendingTasksQueryKey.byCourse(courseId),\n queryFn: async () => fetchPendingTasks(courseId),\n enabled: !!courseId,\n refetchInterval: options?.enablePolling ? 3000 : false,\n });\n};\n\nexport const useLearner = (courseId: string, emailOrUsername: string) => (\n useQuery({\n queryKey: learnerQueryKeys.byCourseAndLearner(courseId, emailOrUsername),\n queryFn: () => getLearner(courseId, emailOrUsername),\n enabled: false,\n retry: false,\n refetchOnWindowFocus: false,\n refetchOnMount: false,\n }));\n\nexport const useProblemDetails = (courseId: string, blockId: string, emailOrUsername: string) => (\n useQuery({\n queryKey: problemQueryKeys.byCourseAndLearner(courseId, blockId, emailOrUsername),\n queryFn: () => getProblemDetails(courseId, blockId, emailOrUsername),\n enabled: false,\n retry: false,\n refetchOnWindowFocus: false,\n refetchOnMount: false,\n }));\n"]}
@@ -10,3 +10,7 @@ export declare const learnerQueryKeys: {
10
10
  all: readonly ["org.openedx.frontend.app.instructorDashboard", "learner"];
11
11
  byCourseAndLearner: (courseId: string, emailOrUsername: string) => readonly ["org.openedx.frontend.app.instructorDashboard", "learner", string, string];
12
12
  };
13
+ export declare const problemQueryKeys: {
14
+ all: readonly ["org.openedx.frontend.app.instructorDashboard", "problemDetails"];
15
+ byCourseAndLearner: (courseId: string, blockId: string, emailOrUsername: string) => readonly ["org.openedx.frontend.app.instructorDashboard", "problemDetails", string, string, string];
16
+ };
@@ -11,4 +11,8 @@ export const learnerQueryKeys = {
11
11
  all: [appId, 'learner'],
12
12
  byCourseAndLearner: (courseId, emailOrUsername) => [appId, 'learner', courseId, emailOrUsername],
13
13
  };
14
+ export const problemQueryKeys = {
15
+ all: [appId, 'problemDetails'],
16
+ byCourseAndLearner: (courseId, blockId, emailOrUsername) => [appId, 'problemDetails', courseId, blockId, emailOrUsername],
17
+ };
14
18
  //# sourceMappingURL=queryKeys.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"queryKeys.js","sourceRoot":"","sources":["../../src/data/queryKeys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAEvC,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,GAAG,EAAE,CAAC,KAAK,EAAE,YAAY,CAAU;IACnC,QAAQ,EAAE,CAAC,QAAgB,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,YAAY,EAAE,QAAQ,CAAU;CACzE,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,GAAG,EAAE,CAAC,KAAK,EAAE,cAAc,CAAU;IACrC,QAAQ,EAAE,CAAC,QAAgB,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,cAAc,EAAE,QAAQ,CAAU;CAC3E,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,GAAG,EAAE,CAAC,KAAK,EAAE,SAAS,CAAU;IAChC,kBAAkB,EAAE,CAAC,QAAgB,EAAE,eAAuB,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,eAAe,CAAU;CAC1H,CAAC","sourcesContent":["import { appId } from '@src/constants';\n\nexport const courseInfoQueryKeys = {\n all: [appId, 'courseInfo'] as const,\n byCourse: (courseId: string) => [appId, 'courseInfo', courseId] as const,\n};\n\nexport const pendingTasksQueryKey = {\n all: [appId, 'pendingTasks'] as const,\n byCourse: (courseId: string) => [appId, 'pendingTasks', courseId] as const,\n};\n\nexport const learnerQueryKeys = {\n all: [appId, 'learner'] as const,\n byCourseAndLearner: (courseId: string, emailOrUsername: string) => [appId, 'learner', courseId, emailOrUsername] as const,\n};\n"]}
1
+ {"version":3,"file":"queryKeys.js","sourceRoot":"","sources":["../../src/data/queryKeys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAEvC,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,GAAG,EAAE,CAAC,KAAK,EAAE,YAAY,CAAU;IACnC,QAAQ,EAAE,CAAC,QAAgB,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,YAAY,EAAE,QAAQ,CAAU;CACzE,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,GAAG,EAAE,CAAC,KAAK,EAAE,cAAc,CAAU;IACrC,QAAQ,EAAE,CAAC,QAAgB,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,cAAc,EAAE,QAAQ,CAAU;CAC3E,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,GAAG,EAAE,CAAC,KAAK,EAAE,SAAS,CAAU;IAChC,kBAAkB,EAAE,CAAC,QAAgB,EAAE,eAAuB,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,eAAe,CAAU;CAC1H,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,GAAG,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAU;IACvC,kBAAkB,EAAE,CAAC,QAAgB,EAAE,OAAe,EAAE,eAAuB,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,CAAU;CAC3J,CAAC","sourcesContent":["import { appId } from '@src/constants';\n\nexport const courseInfoQueryKeys = {\n all: [appId, 'courseInfo'] as const,\n byCourse: (courseId: string) => [appId, 'courseInfo', courseId] as const,\n};\n\nexport const pendingTasksQueryKey = {\n all: [appId, 'pendingTasks'] as const,\n byCourse: (courseId: string) => [appId, 'pendingTasks', courseId] as const,\n};\n\nexport const learnerQueryKeys = {\n all: [appId, 'learner'] as const,\n byCourseAndLearner: (courseId: string, emailOrUsername: string) => [appId, 'learner', courseId, emailOrUsername] as const,\n};\n\nexport const problemQueryKeys = {\n all: [appId, 'problemDetails'] as const,\n byCourseAndLearner: (courseId: string, blockId: string, emailOrUsername: string) => [appId, 'problemDetails', courseId, blockId, emailOrUsername] as const,\n};\n"]}
@@ -9,7 +9,11 @@ import messages from '../grading/messages';
9
9
  const GradingPage = () => {
10
10
  const intl = useIntl();
11
11
  const [selectedTools, setSelectedTools] = useState('single');
12
- return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "d-flex justify-content-between align-items-center", children: [_jsx("h3", { className: "text-primary-700 mb-0", children: intl.formatMessage(messages.pageTitle) }), _jsx(GradingActionRow, {})] }), _jsxs(Card, { className: "bg-light-200 p-4 mt-4.5", children: [_jsxs(ButtonGroup, { className: "d-block", children: [_jsx(Button, { onClick: () => setSelectedTools('single'), variant: selectedTools === 'single' ? 'primary' : 'outline-primary', children: intl.formatMessage(messages.singleLearner) }), _jsx(Button, { onClick: () => setSelectedTools('all'), variant: selectedTools === 'all' ? 'primary' : 'outline-primary', children: intl.formatMessage(messages.allLearners) })] }), _jsx(GradingLearnerContent, { toolType: selectedTools })] }), _jsx(PendingTasks, {})] }));
12
+ const [isPendingTasksOpen, setIsPendingTasksOpen] = useState(false);
13
+ const handleOpenPendingTasks = () => {
14
+ setIsPendingTasksOpen(true);
15
+ };
16
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "d-flex justify-content-between align-items-center", children: [_jsx("h3", { className: "text-primary-700 mb-0", children: intl.formatMessage(messages.pageTitle) }), _jsx(GradingActionRow, {})] }), _jsxs(Card, { className: "bg-light-200 p-4 mt-4.5", children: [_jsxs(ButtonGroup, { className: "d-block", children: [_jsx(Button, { onClick: () => setSelectedTools('single'), variant: selectedTools === 'single' ? 'primary' : 'outline-primary', children: intl.formatMessage(messages.singleLearner) }), _jsx(Button, { onClick: () => setSelectedTools('all'), variant: selectedTools === 'all' ? 'primary' : 'outline-primary', children: intl.formatMessage(messages.allLearners) })] }), _jsx(GradingLearnerContent, { toolType: selectedTools, onShowTasks: handleOpenPendingTasks })] }), _jsx(PendingTasks, { isOpen: isPendingTasksOpen, onToggle: () => setIsPendingTasksOpen(prev => !prev) })] }));
13
17
  };
14
18
  export default GradingPage;
15
19
  //# sourceMappingURL=GradingPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"GradingPage.js","sourceRoot":"","sources":["../../src/grading/GradingPage.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,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,gBAAgB,MAAM,0CAA0C,CAAC;AACxE,OAAO,qBAAqB,MAAM,+CAA+C,CAAC;AAClF,OAAO,QAAQ,MAAM,uBAAuB,CAAC;AAG7C,MAAM,WAAW,GAAG,GAAG,EAAE;IACvB,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAmB,QAAQ,CAAC,CAAC;IAE/E,OAAO,CACL,8BACE,eAAK,SAAS,EAAC,mDAAmD,aAChE,aAAI,SAAS,EAAC,uBAAuB,YAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAM,EACnF,KAAC,gBAAgB,KAAG,IAChB,EACN,MAAC,IAAI,IAAC,SAAS,EAAC,yBAAyB,aACvC,MAAC,WAAW,IAAC,SAAS,EAAC,SAAS,aAC9B,KAAC,MAAM,IACL,OAAO,EAAE,GAAG,EAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EACzC,OAAO,EAAE,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,YAElE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,aAAa,CAAC,GACpC,EACT,KAAC,MAAM,IACL,OAAO,EAAE,GAAG,EAAE,CAAC,gBAAgB,CAAC,KAAK,CAAC,EACtC,OAAO,EAAE,aAAa,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,YAE/D,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,WAAW,CAAC,GAClC,IACG,EACd,KAAC,qBAAqB,IAAC,QAAQ,EAAE,aAAa,GAAI,IAC7C,EACP,KAAC,YAAY,KAAG,IACf,CACJ,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,WAAW,CAAC","sourcesContent":["import { useState } from 'react';\nimport { useIntl } from '@openedx/frontend-base';\nimport { Button, ButtonGroup, Card } from '@openedx/paragon';\nimport { PendingTasks } from '@src/components/PendingTasks';\nimport GradingActionRow from '@src/grading/components/GradingActionRow';\nimport GradingLearnerContent from '@src/grading/components/GradingLearnerContent';\nimport messages from '@src/grading/messages';\nimport { GradingToolsType } from '@src/grading/types';\n\nconst GradingPage = () => {\n const intl = useIntl();\n const [selectedTools, setSelectedTools] = useState<GradingToolsType>('single');\n\n return (\n <>\n <div className=\"d-flex justify-content-between align-items-center\">\n <h3 className=\"text-primary-700 mb-0\">{intl.formatMessage(messages.pageTitle)}</h3>\n <GradingActionRow />\n </div>\n <Card className=\"bg-light-200 p-4 mt-4.5\">\n <ButtonGroup className=\"d-block\">\n <Button\n onClick={() => setSelectedTools('single')}\n variant={selectedTools === 'single' ? 'primary' : 'outline-primary'}\n >\n {intl.formatMessage(messages.singleLearner)}\n </Button>\n <Button\n onClick={() => setSelectedTools('all')}\n variant={selectedTools === 'all' ? 'primary' : 'outline-primary'}\n >\n {intl.formatMessage(messages.allLearners)}\n </Button>\n </ButtonGroup>\n <GradingLearnerContent toolType={selectedTools} />\n </Card>\n <PendingTasks />\n </>\n );\n};\n\nexport default GradingPage;\n"]}
1
+ {"version":3,"file":"GradingPage.js","sourceRoot":"","sources":["../../src/grading/GradingPage.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,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,gBAAgB,MAAM,0CAA0C,CAAC;AACxE,OAAO,qBAAqB,MAAM,+CAA+C,CAAC;AAClF,OAAO,QAAQ,MAAM,uBAAuB,CAAC;AAG7C,MAAM,WAAW,GAAG,GAAG,EAAE;IACvB,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAmB,QAAQ,CAAC,CAAC;IAC/E,MAAM,CAAC,kBAAkB,EAAE,qBAAqB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEpE,MAAM,sBAAsB,GAAG,GAAG,EAAE;QAClC,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC,CAAC;IAEF,OAAO,CACL,8BACE,eAAK,SAAS,EAAC,mDAAmD,aAChE,aAAI,SAAS,EAAC,uBAAuB,YAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAM,EACnF,KAAC,gBAAgB,KAAG,IAChB,EACN,MAAC,IAAI,IAAC,SAAS,EAAC,yBAAyB,aACvC,MAAC,WAAW,IAAC,SAAS,EAAC,SAAS,aAC9B,KAAC,MAAM,IACL,OAAO,EAAE,GAAG,EAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EACzC,OAAO,EAAE,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,YAElE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,aAAa,CAAC,GACpC,EACT,KAAC,MAAM,IACL,OAAO,EAAE,GAAG,EAAE,CAAC,gBAAgB,CAAC,KAAK,CAAC,EACtC,OAAO,EAAE,aAAa,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,YAE/D,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,WAAW,CAAC,GAClC,IACG,EACd,KAAC,qBAAqB,IAAC,QAAQ,EAAE,aAAa,EAAE,WAAW,EAAE,sBAAsB,GAAI,IAClF,EACP,KAAC,YAAY,IAAC,MAAM,EAAE,kBAAkB,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAI,IACjG,CACJ,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,WAAW,CAAC","sourcesContent":["import { useState } from 'react';\nimport { useIntl } from '@openedx/frontend-base';\nimport { Button, ButtonGroup, Card } from '@openedx/paragon';\nimport { PendingTasks } from '@src/components/PendingTasks';\nimport GradingActionRow from '@src/grading/components/GradingActionRow';\nimport GradingLearnerContent from '@src/grading/components/GradingLearnerContent';\nimport messages from '@src/grading/messages';\nimport { GradingToolsType } from '@src/grading/types';\n\nconst GradingPage = () => {\n const intl = useIntl();\n const [selectedTools, setSelectedTools] = useState<GradingToolsType>('single');\n const [isPendingTasksOpen, setIsPendingTasksOpen] = useState(false);\n\n const handleOpenPendingTasks = () => {\n setIsPendingTasksOpen(true);\n };\n\n return (\n <>\n <div className=\"d-flex justify-content-between align-items-center\">\n <h3 className=\"text-primary-700 mb-0\">{intl.formatMessage(messages.pageTitle)}</h3>\n <GradingActionRow />\n </div>\n <Card className=\"bg-light-200 p-4 mt-4.5\">\n <ButtonGroup className=\"d-block\">\n <Button\n onClick={() => setSelectedTools('single')}\n variant={selectedTools === 'single' ? 'primary' : 'outline-primary'}\n >\n {intl.formatMessage(messages.singleLearner)}\n </Button>\n <Button\n onClick={() => setSelectedTools('all')}\n variant={selectedTools === 'all' ? 'primary' : 'outline-primary'}\n >\n {intl.formatMessage(messages.allLearners)}\n </Button>\n </ButtonGroup>\n <GradingLearnerContent toolType={selectedTools} onShowTasks={handleOpenPendingTasks} />\n </Card>\n <PendingTasks isOpen={isPendingTasksOpen} onToggle={() => setIsPendingTasksOpen(prev => !prev)} />\n </>\n );\n};\n\nexport default GradingPage;\n"]}
@@ -1,6 +1,7 @@
1
1
  import { GradingToolsType } from '../../grading/types';
2
2
  interface GradingLearnerContentProps {
3
3
  toolType: GradingToolsType;
4
+ onShowTasks: () => void;
4
5
  }
5
- declare const GradingLearnerContent: ({ toolType }: GradingLearnerContentProps) => import("react/jsx-runtime").JSX.Element;
6
+ declare const GradingLearnerContent: ({ toolType, onShowTasks }: GradingLearnerContentProps) => import("react/jsx-runtime").JSX.Element;
6
7
  export default GradingLearnerContent;