import { useCollection } from "@awsui/collection-hooks"; import { Box, Button, Pagination, SpaceBetween, Spinner, Table, TableProps, TextFilter } from "@awsui/components-react"; import StatusIndicator from "@awsui/components-react/status-indicator"; import React, { useMemo, useState } from "react"; import { useHistory, useLocation } from "react-router-dom"; import { usePortingAssistantSelector } from "../../createReduxStore"; import { HistoryState } from "../../models/locationState"; import { MetricSource, MetricType, ReactMetric } from "../../models/reactmetric"; import { SolutionDetails } from "../../models/solution"; import { selectPortingLocation } from "../../store/selectors/portingSelectors"; import { selectProjects } from "../../store/selectors/solutionSelectors"; import { selectProjectTableData } from "../../store/selectors/tableSelectors"; import { filteringCountText } from "../../utils/FilteringCountText"; import { getErrorMetric } from "../../utils/getErrorMetric"; import { getHash } from "../../utils/getHash"; import { hasNewData, isLoaded, isLoading, isReloading, Loadable } from "../../utils/Loadable"; import { InfoLink } from "../InfoLink"; import { LinkComponent } from "../LinkComponent"; import { PortConfigurationModal } from "../PortConfigurationModal/PortConfigurationModal"; import { TableHeader } from "../TableHeader"; interface Props { solution: Loadable; } export interface TableData { projectName: string; projectPath: string; solutionPath: string; targetFramework: string; referencedProjects: number; incompatiblePackages: number | null; totalPackages: number | null; incompatibleApis: number | null; totalApis: number | null; buildErrors: number | null; portingActions: number | null; ported: boolean; buildFailed: boolean; } const ProjectsTableInternal: React.FC = ({ solution }) => { const [selectedItems, setSelectedItems] = useState(Array()); const [showPortingModal, setShowPortingModal] = useState(false); const location = useLocation(); const history = useHistory(); const portingLocation = usePortingAssistantSelector(state => selectPortingLocation(state, location.pathname)); const projects = usePortingAssistantSelector(state => selectProjects(state, location.pathname)); const tableData = usePortingAssistantSelector(state => selectProjectTableData(state, location.pathname)); const empty = useMemo( () => ( Solution has no projects ), [] ); const { items, filteredItemsCount, collectionProps, filterProps, paginationProps } = useCollection(tableData, { filtering: { empty: empty }, pagination: {}, sorting: {} }); return ( {...collectionProps} loadingText="Loading packages" columnDefinitions={columnDefinitions} loading={(isLoading(projects) && !hasNewData(projects)) || isReloading(projects)} items={items} selectionType="multi" trackBy="projectPath" selectedItems={selectedItems} onSelectionChange={event => setSelectedItems(event.detail.selectedItems)} filter={ } pagination={} header={ Each project is identified by Visual Studio with a .csproj file. All of the project configuration is contained in the .xml file. Columns Name - Name of the project. Project framework - Target framework of the project. Referenced projects - Number of other projects that are referenced by project. Incompatible packages - The number of incompatible NuGet packages referenced by project. Incompatible APIs - The number of incompatible instances of API calls within the project. Build errors - The number of build errors in the project. Porting actions - The number of porting actions in the project. Port status - Port status of the project. } learnMoreLinks={[ { externalUrl: "https://docs.microsoft.com/en-us/aspnet/web-forms/overview/deployment/web-deployment-in-the-enterprise/understanding-the-project-file#msbuild-and-the-project-file", text: "Understanding the project file" } ]} /> } selectedItems={selectedItems} totalItems={tableData} description="Port your project when you have reached your desired level of compatibility." actionButtons={ setShowPortingModal(false)} onSubmit={() => { history.push({ pathname: `/port-solution/${encodeURIComponent(selectedItems[0].solutionPath)}`, state: { projects: isLoaded(projects) ? projects.data.filter(p => selectedItems.some(s => p.projectFilePath === s.projectPath)) : [] } }); }} /> } /> } empty={empty} > ); }; const escapeNonAlphaNumeric = (solutionPath: string) => { return solutionPath.replace(/[^0-9a-zA-Z]/gi, ""); }; const columnDefinitions: TableProps.ColumnDefinition[] = [ { id: "project-name", header: "Name", cell: item => ( {item.projectName} ), sortingField: "projectName" }, { id: "target-framework", header: "Project framework", cell: item =>
{item.targetFramework}
, sortingField: "projectFramework" //minWidth: "200px" }, { id: "project-references", header: "Referenced projects", cell: item => (
{item.referencedProjects}
), sortingField: "referencedProjects" }, { id: "nuget-compatibility", header: "Incompatible packages", cell: item => { return item.incompatiblePackages == null ? ( ) : (
{item.incompatiblePackages} of {item.totalPackages}
); }, sortingField: "incompatiblePackages" }, { id: "api-compatibility", header: "Incompatible APIs", cell: item => { if (item.incompatibleApis == null) { return ; } return (
{item.buildFailed === true ? "-" : `${item.incompatibleApis} of ${item.totalApis}`}
); }, sortingField: "incompatibleApis" }, { id: "build-error", header: "Build errors", cell: item => { if (item.buildErrors == null) { return ; } return (
{item.buildFailed === true ? ( Build failed ) : ( `${item.buildErrors}` )}
); }, sortingField: "buildErrors" }, { id: "porting-actions", header: "Porting actions", cell: item => { if (item.portingActions == null) { return ; } return
{item.portingActions}
; }, sortingField: "portingActions" }, { id: "ported", header: "Port status", cell: item => { return (
{item.ported ? ( Ported ) : ( Not ported )}
); }, sortingField: "ported" // width: 150 } ]; export const ProjectsTable = React.memo(ProjectsTableInternal);