Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ jobs:
run: npm ci
- name: Lint
run: npm run lint
- name: Types
run: npm run types
- name: Test
run: npm run test
- name: Build
Expand Down
4 changes: 2 additions & 2 deletions src/authz-module/audit-user/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ const AuditUserPage = () => {

useEffect(() => {
if (!user && !isLoadingUser) {
// @ts-ignore
if (!isErrorUser || errorUser?.customAttributes?.httpErrorStatus === 404) {
const err = errorUser as { customAttributes?: { httpErrorStatus?: number } } | null;
if (!isErrorUser || err?.customAttributes?.httpErrorStatus === 404) {
navigate(AUTHZ_HOME_PATH);
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/authz-module/components/AuthZTitle.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ describe('AuthZTitle', () => {

it('renders without optional fields', () => {
render(<AuthZTitle {...defaultProps} />);
expect(screen.getByText(defaultProps.activeLabel)).toBeInTheDocument();
expect(screen.getByText(defaultProps.activeLabel as string)).toBeInTheDocument();
expect(screen.getByText(defaultProps.pageTitle)).toBeInTheDocument();
expect(screen.getByText(defaultProps.pageSubtitle as string)).toBeInTheDocument();
});
Expand All @@ -35,7 +35,7 @@ describe('AuthZTitle', () => {
expect(screen.getByText(label)).toHaveAttribute('href', expect.stringContaining(to));
});

expect(screen.getByText(defaultProps.activeLabel)).toBeInTheDocument();
expect(screen.getByText(defaultProps.activeLabel as string)).toBeInTheDocument();
});

it('renders page title', () => {
Expand Down
4 changes: 2 additions & 2 deletions src/authz-module/components/PermissionTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
Card, Icon, OverlayTrigger, Tooltip,
} from '@openedx/paragon';
import { PermissionsResourceGrouped, Role } from '@src/types';
import { actionsDictionary } from './RoleCard/constants';
import { actionsDictionary, ActionKey } from './RoleCard/constants';
import ResourceTooltip from './ResourceTooltip';
import messages from './messages';

Expand Down Expand Up @@ -66,7 +66,7 @@ const PermissionTable = ({ permissionsTable, roles, title }: PermissionTableProp
{resourceGroup.permissions.map(permission => (
<tr key={permission.key} className="border-top">
<td className="text-start d-flex align-items-center small px-4 py-3">
<Icon className="d-inline-block mr-2" size="sm" src={actionsDictionary[permission.actionKey]} />
<Icon className="d-inline-block mr-2" size="sm" src={actionsDictionary[permission.actionKey as ActionKey]} />
{permission.label}
</td>
{roles.map(role => (
Expand Down
2 changes: 1 addition & 1 deletion src/authz-module/components/ResourceTooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const ResourceTooltip = ({ resourceGroup }:ResourceTooltipProps) => (
<p className="small">{resourceGroup.description}</p>
<ul className="small">
{resourceGroup.permissions.map(permission => (
<li><b>{permission.label.trim()}:</b> {permission.description}</li>
<li><b>{permission.label?.trim()}:</b> {permission.description}</li>
))}
</ul>
</Popover.Content>
Expand Down
5 changes: 3 additions & 2 deletions src/authz-module/components/RoleCard/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,13 @@ describe('RoleCard', () => {
{
key: 'library',
label: 'Library Resource',
description: 'Library resource description',
permissions: [
{
key: 'view', label: 'View', actionKey: 'view', disabled: false,
key: 'view', resource: 'library', label: 'View', actionKey: 'view', disabled: false,
},
{
key: 'manage', label: 'Manage', actionKey: 'manage', disabled: true,
key: 'manage', resource: 'library', label: 'Manage', actionKey: 'manage', disabled: true,
},
],
},
Expand Down
3 changes: 2 additions & 1 deletion src/authz-module/components/RoleCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
Card, Collapsible, Container, Icon, IconButton,
} from '@openedx/paragon';
import { Delete, Person } from '@openedx/paragon/icons';
import { RoleResourceGroup } from '@src/types';
import PermissionRow from './PermissionsRow';
import messages from './messages';

Expand All @@ -15,7 +16,7 @@ interface RoleCardProps extends CardTitleProps {
objectName?: string | null;
description: string;
handleDelete?: () => void;
permissionsByResource: any[];
permissionsByResource: RoleResourceGroup[];
}

const CardTitle = ({ title, userCounter = null }: CardTitleProps) => {
Expand Down
11 changes: 6 additions & 5 deletions src/authz-module/components/TableCells.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { ContextType, useContext, useMemo } from 'react';
import { useNavigate } from 'react-router-dom';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Icon, IconButton } from '@openedx/paragon';
import { AppContext } from '@edx/frontend-platform/react';
import {
RemoveRedEye,
Delete, ExpandMore,
} from '@openedx/paragon/icons';
import { TableCellValue, AppContextType, UserRole } from '@src/types';
import { useNavigate } from 'react-router-dom';
import { useContext, useMemo } from 'react';
import { UserRole } from '@src/types';
import type { TableCellValue } from '@src/paragon';
import { DJANGO_MANAGED_ROLES, MAP_ROLE_KEY_TO_LABEL } from '@src/authz-module/constants';
import { RESOURCE_ICONS } from './constants';
import messages from './messages';
Expand All @@ -25,7 +26,7 @@

const NameCell = ({ row }: CellProps) => {
const intl = useIntl();
const { authenticatedUser } = useContext(AppContext) as AppContextType;
const { authenticatedUser } = useContext(AppContext) as ContextType<typeof AppContext>;

Check failure on line 29 in src/authz-module/components/TableCells.tsx

View workflow job for this annotation

GitHub Actions / test

Property 'authenticatedUser' does not exist on type 'unknown'.
const username = authenticatedUser?.username;

if (row.original.username === username) {
Expand All @@ -36,7 +37,7 @@
</span>
);
}
return row.original.fullName || row.original.username;
return <span>{row.original.fullName || row.original.username}</span>;
};

const ViewActionCell = ({ row }: CellProps) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const MultipleChoiceFilter = ({
const { formatMessage } = useIntl();

const checkedBoxes = filterValue || [];
const handleClickCheckbox = (value, displayName) => {
const handleClickCheckbox = (value: string, displayName: string) => {
const newValue = {
groupName: filterButtonText?.toLocaleLowerCase() || '',
value,
Expand Down Expand Up @@ -71,7 +71,7 @@ const MultipleChoiceFilter = ({
type="text"
trailingElement={<Icon src={Search} />}
placeholder={formatMessage(messages['authz.table.controlbar.search'])}
onChange={(e) => {
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setSearchValue(e.target.value);
onSearchChange?.(e.target.value);
}}
Expand Down
4 changes: 2 additions & 2 deletions src/authz-module/components/TableControlBar/SearchFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Search } from '@openedx/paragon/icons';

interface SearchFilterProps {
filterValue: string;
setFilter: (value: string) => void;
setFilter: (value: string | undefined) => void;
placeholder: string;
}

Expand All @@ -19,7 +19,7 @@ const SearchFilter = ({
trailingElement={<Icon src={Search} />}
value={filterValue || ''}
type="text"
onChange={e => {
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setFilter(e.target.value || undefined); // Set undefined to remove the filter entirely
}}
placeholder={placeholder}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ describe('TableControlBar', () => {
state: mockState,
};

const renderWithContext = (component, contextOverride = {}) => {
const renderWithContext = (component: React.ReactNode, contextOverride = {}) => {
const context = { ...mockDataTableContext, ...contextOverride };
return renderWrapper(
<DataTableContext.Provider value={context}>
Expand Down
47 changes: 26 additions & 21 deletions src/authz-module/components/TableControlBar/TableControlBar.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { useContext, useEffect, useState } from 'react';
import {
Context, useContext, useEffect, useState,
} from 'react';
import { useIntl } from '@edx/frontend-platform/i18n';
import {
DataTableContext,
Expand All @@ -13,6 +15,7 @@ import {
Business, Close, LocationOn, Person,
Warning,
} from '@openedx/paragon/icons';
import type { DataTableContextShape } from '@src/paragon';

import { MAX_TABLE_FILTERS_APPLIED } from '@src/authz-module/constants';
import MultipleChoiceFilter from './MultipleChoiceFilter';
Expand Down Expand Up @@ -48,8 +51,7 @@ const TableControlBar = ({ onFilterChange }: TableControlBarProps) => {
columns,
setAllFilters,
state,
// @ts-ignore-next-line - Paragon's DataTableContext is not typed
} = useContext<DataTableContext>(DataTableContext);
} = useContext(DataTableContext as unknown as Context<DataTableContextShape>);

useEffect(() => {
if (state.filters.length > 0) {
Expand Down Expand Up @@ -78,20 +80,23 @@ const TableControlBar = ({ onFilterChange }: TableControlBarProps) => {
.map((column) => column.Header);

const getSearchPlaceholder = () => intl.formatMessage(messages['authz.table.controlbar.search.by.fields'], {
firstField: columnTextFilterHeaders[0] || '',
secondField: columnTextFilterHeaders[1] || '',
firstField: String(columnTextFilterHeaders[0] || ''),
secondField: String(columnTextFilterHeaders[1] || ''),
});

const handleCloseFilter = (filterName, filterValue) => {
const actualFilterId = FILTER_GROUP_TO_ID[filterName] || filterName;
const handleCloseFilter = (filterName: string, filterValue: string) => {
const actualFilterId = FILTER_GROUP_TO_ID[filterName as keyof typeof FILTER_GROUP_TO_ID] || filterName;
const filterGroup = state.filters.find((filter) => filter.id === actualFilterId);
const newFilterValue = filterGroup?.value.filter(item => item !== filterValue) || [];
setAllFilters(state.filters.map(item => (
const newFilterValue = filterGroup?.value.filter((item: string) => item !== filterValue) || [];
setAllFilters(state.filters.map((item) => (
item.id !== actualFilterId ? item : { id: item.id, value: newFilterValue })));
setChronologicalFilters((prevFilters) => prevFilters.filter((filter) => filter.value !== filterValue));
};

const handleSetFilters = (setFilter) => (allFilters: string[], newFilter: FilterChoice) => {
const handleSetFilters = (setFilter: (value: string[]) => void) => (
allFilters: string[],
newFilter: FilterChoice,
) => {
setFilter(allFilters);
setChronologicalFilters((prevFilters) => {
if (!prevFilters.find((filter) => filter.value === newFilter.value)) {
Expand All @@ -113,35 +118,35 @@ const TableControlBar = ({ onFilterChange }: TableControlBarProps) => {
if (Filter === RolesFilter) {
return (
<RolesFilter
{...column}
setFilter={handleSetFilters(column.setFilter)}
{...(column as unknown as React.ComponentProps<typeof RolesFilter>)}
setFilter={handleSetFilters(column.setFilter!)}
disabled={filtersLimitReached}
/>
);
}
if (Filter === OrgFilter) {
return (
<OrgFilter
{...column}
setFilter={handleSetFilters(column.setFilter)}
{...(column as unknown as React.ComponentProps<typeof OrgFilter>)}
setFilter={handleSetFilters(column.setFilter!)}
disabled={filtersLimitReached}
/>
);
}
if (Filter === MultipleChoiceFilter) {
return (
<MultipleChoiceFilter
{...column}
setFilter={handleSetFilters(column.setFilter)}
{...(column as unknown as React.ComponentProps<typeof MultipleChoiceFilter>)}
setFilter={handleSetFilters(column.setFilter!)}
disabled={filtersLimitReached}
/>
);
}
if (Filter === ScopesFilter) {
return (
<ScopesFilter
{...column}
setFilter={handleSetFilters(column.setFilter)}
{...(column as unknown as React.ComponentProps<typeof ScopesFilter>)}
setFilter={handleSetFilters(column.setFilter!)}
disabled={filtersLimitReached}
filterValue={state.filters.find(filter => filter.id === 'scope')?.value || null}
/>
Expand All @@ -153,7 +158,7 @@ const TableControlBar = ({ onFilterChange }: TableControlBarProps) => {
<SearchFilter
key={column.id || column.accessor}
filterValue={column.filterValue}
setFilter={column.setFilter}
setFilter={column.setFilter!}
placeholder={getSearchPlaceholder()}
/>
);
Expand All @@ -169,9 +174,9 @@ const TableControlBar = ({ onFilterChange }: TableControlBarProps) => {
{chronologicalFilters.map((filter) => (
<Chip
key={filter.value}
iconBefore={FILTER_CHIPS_ICONS[filter.groupName || '']}
iconBefore={FILTER_CHIPS_ICONS[(filter.groupName || '') as keyof typeof FILTER_CHIPS_ICONS]}
iconAfter={Close}
onIconAfterClick={() => handleCloseFilter(filter.groupName, filter.value)}
onIconAfterClick={() => handleCloseFilter(filter.groupName || '', filter.value)}
>
{filter.displayName}
</Chip>
Expand Down
8 changes: 4 additions & 4 deletions src/authz-module/components/TableFooter/TableFooter.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useContext } from 'react';
import { Context, useContext } from 'react';
import { DataTableContextShape } from '@src/paragon';
import { useIntl } from '@edx/frontend-platform/i18n';
import { DataTableContext, Pagination, TableFooter } from '@openedx/paragon';
import messages from '../messages';
Expand All @@ -7,8 +8,7 @@ const Footer = () => {
const { formatMessage } = useIntl();
const {
pageCount, gotoPage, state, itemCount, rows,
// @ts-ignore-next-line - Paragon's DataTableContext is not typed
} = useContext<DataTableContext>(DataTableContext);
} = useContext(DataTableContext as unknown as Context<DataTableContextShape>);
const { pageIndex } = state;
return (
<TableFooter>
Expand All @@ -19,7 +19,7 @@ const Footer = () => {
variant="reduced"
currentPage={pageIndex + 1}
pageCount={pageCount}
onPageSelect={(pageNum) => gotoPage(pageNum - 1)}
onPageSelect={(pageNum: number) => gotoPage(pageNum - 1)}
/>
</TableFooter>
);
Expand Down
17 changes: 1 addition & 16 deletions src/authz-module/components/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const messages = defineMessages({
'authz.table.footer.items.showing.text': {
id: 'authz.table.footer.items.showing.text',
defaultMessage: 'Showing {pageSize} of {itemCount}.',
description: 'Message displayed when the user reaches the applied filters limit',
description: 'Text in the table footer indicating how many items are being shown out of the total count.',
},
'authz.table.username.current': {
id: 'authz.table.username.current',
Expand Down Expand Up @@ -97,21 +97,6 @@ const messages = defineMessages({
defaultMessage: 'Search to show more',
description: 'Message displayed when there are more results available than currently shown',
},
'authz.table.footer.items.showing.text': {
id: 'authz.table.footer.items.showing.text',
defaultMessage: 'Showing {pageSize} of {itemCount}.',
description: 'Text in the table footer indicating how many items are being shown out of the total count.',
},
'authz.user.table.org.all.organizations.label': {
id: 'authz.user.table.org.all.organizations.label',
defaultMessage: 'All Organizations',
description: 'Label for the "All Organizations" message on the user assignments table when a user has a django managed role assigned.',
},
'authz.user.table.scope.global.label': {
id: 'authz.user.table.scope.global.label',
defaultMessage: 'Global',
description: 'Label for the "Global" scope in the user assignments table when a user has a django managed role assigned.',
},
'authz.user.table.permissions.access.label': {
id: 'authz.user.table.permissions.access.label',
defaultMessage: '{accessType, select, total {Total Access} partial {Partial Access} other {No Access}}',
Expand Down
2 changes: 1 addition & 1 deletion src/authz-module/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PermissionMetadata, ResourceMetadata, RoleMetadata } from 'types';
import { PermissionMetadata, ResourceMetadata, RoleMetadata } from '@src/types';

export const CONTENT_LIBRARY_PERMISSIONS = {
DELETE_LIBRARY: 'content_libraries.delete_library',
Expand Down
Loading
Loading