import { Box, Button, Checkbox, ColumnLayout, Container, Form, FormField, Header, Input, Multiselect, SelectProps, SpaceBetween } from "@awsui/components-react"; import { OptionDefinition } from "@awsui/components-react/internal/components/option/interfaces"; import { MemoryHistory } from "history"; import path from "path"; import React, { useCallback, useEffect, useState } from "react"; import { useDispatch } from "react-redux"; import { useLocation } from "react-router"; import { useHistory } from "react-router-dom"; import { v4 as uuid } from "uuid"; import { externalUrls } from "../../constants/externalUrls"; import { RuleContribSource } from "../../containers/RuleContribution"; import { HistoryState } from "../../models/locationState"; import { pushCurrentMessageUpdate } from "../../store/actions/error"; import { getSupportedVersion } from "../../utils/getSupportedVersions"; import { validatePackageInput } from "../../utils/validateRuleContrib"; interface Props { source: RuleContribSource; } interface KeyValProps { label: string; description?: any; children: string | undefined; } export interface PackageContribution { packageNameSource: string; packageVersionSource: string | undefined; packageName: string; packageVersion: string; packageVersionLatest: boolean; targetFramework: readonly OptionDefinition[]; comments?: string; } const PackageRuleContributionInternal: React.FC = ({ source }) => { const cachedTargetFramework = window.electron.getState("targetFramework"); const history = useHistory() as MemoryHistory; const location = useLocation(); const nextPagePath = window.electron.getDirectory(location.pathname); const dispatch = useDispatch(); const [packageName, setPackageName] = useState(""); const [packageVersion, setPackageVersion] = useState(""); const [packageError, setPackageError] = useState(""); const [versionError, setVersionError] = useState(""); const [targetFrameworkError, setTargetFrameworkError] = useState(""); const [submitLoading, setSubmitLoading] = useState(false); const [useLatestPackageVersion, setUseLatestPackageVersion] = useState(false); const [targetFramework, setTargetFramework] = useState([ { label: cachedTargetFramework.label, value: cachedTargetFramework.id } ]); const [comments, setComments] = useState(""); const [targetFrameworkOptions, setFrameworkOptions] = useState(new Array()); useEffect(() => { (async () => { var result = await getSupportedVersion(); if (result[1] == null || result[1].trim() === "") { setFrameworkOptions(result[0]); // Need to convert from existing user selection to latest options if name changes. var lookupOption = result[0].find((item) => { return item.value === cachedTargetFramework.id; }); var currentOption = {label: lookupOption?.label, id: lookupOption?.value} as SelectProps.Option; setTargetFramework([currentOption]); } else { setTargetFrameworkError(result[1]); } })(); }, []); const onCancel = () => { history.goBack(); }; const setFlashbar = useCallback( messageContent => { dispatch(pushCurrentMessageUpdate(messageContent)); }, [dispatch] ); const onSubmit = async () => { setSubmitLoading(true); setPackageError(""); setVersionError(""); setTargetFrameworkError(""); const submission: PackageContribution = { packageNameSource: source.packageName, packageVersionSource: source.packageVersion, packageName: packageName, packageVersion: packageVersion, packageVersionLatest: useLatestPackageVersion, targetFramework: targetFramework, comments: comments }; if (await validateInput(submission)) { const formattedSubmission = formatPackageContribution(submission); var content = JSON.stringify(formattedSubmission, null, 4) .split("\n") .join("%0D%0A"); window.location.href = `mailto:${externalUrls.email}?subject=Rule Contribution - Porting Assistant for .NET&body=${content}`; history.push(nextPagePath); } else { setSubmitLoading(false); } }; const validateInput = async (submission: PackageContribution) => { //Error handling for API call try { // result is type ValidationResult: // {valid: boolean, field?: string, message?: string} const result = await validatePackageInput(submission); if (!result.valid) { switch (result.field) { case "packageName": if (result.message) setPackageError(result.message); break; case "packageVersion": if (result.message) setVersionError(result.message); break; case "targetFramework": if (result.message) setTargetFrameworkError(result.message); break; case "packageName/packageVersion": if (result.message) { setPackageError(result.message); setVersionError(result.message); } break; default: break; } return false; } } catch { // Shows an error flashbar at the top setFlashbar({ messageId: uuid(), type: "error", content: "Unable to reach the server to verify the provided package. Please try again.", dismissible: true }); return false; } return true; }; const formatPackageContribution = (submission: PackageContribution) => { return { Name: submission.packageNameSource, Version: submission.packageVersionSource, Packages: [ { Name: submission.packageNameSource, Type: "Nuget" } ], Recommendations: [ { Type: "Namespace", Name: submission.packageNameSource, Value: submission.packageNameSource, KeyType: "Name", ContainingType: "", RecommendedActions: [ { Source: "External", Preferred: "Yes", TargetFrameworks: submission.targetFramework.map(t => ({ Name: t.value, TargetCPU: ["x86", "x64", "ARM32", "ARM64"] })), Description: "", Actions: submission.packageVersionLatest ? [ { Name: "AddPackage", Type: "Package", Value: submission.packageName, Description: submission.comments } ] : [ { Name: "AddPackage", Type: "Package", Value: submission.packageName, Version: submission.packageVersion, Description: submission.comments } ] } ] } ] }; }; const ValueWithLabel: React.FC = ({ label, description, children }) => ( {label} {description}
{children}
); const recommendationForm = (
} > setPackageName(detail.value.trim())} placeholder="Example.Package.Name" /> setPackageVersion(detail.value)} disabled={useLatestPackageVersion} placeholder="1.0.0" /> { setUseLatestPackageVersion(detail.checked); if (detail.checked) { setPackageVersion(""); setVersionError(""); } }} checked={useLatestPackageVersion} > Latest setTargetFramework(detail.selectedOptions)} /> Comments} description="Please provide a short description." stretch={true} > setComments(detail.value)} />
); return ( NuGet package details } > {source?.packageName} {source?.packageVersion} Suggestion form } > {recommendationForm} ); }; export const PackageRuleContribution = React.memo(PackageRuleContributionInternal);