diff --git a/.github/workflows/ci-actions.yml b/.github/workflows/ci-actions.yml index cec3dd8a9f..cc0f3ae185 100644 --- a/.github/workflows/ci-actions.yml +++ b/.github/workflows/ci-actions.yml @@ -53,3 +53,27 @@ jobs: with: flags: server directory: ./*/coverage + + build-and-upload-for-global-ci: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: save tackle2-ui image + run: | + docker build . -t quay.io/konveyor/tackle2-ui:latest + docker save -o /tmp/tackle2-ui.tar quay.io/konveyor/tackle2-ui:latest + + - name: Upload tackle2-ui image as artifact + uses: actions/upload-artifact@v3 + with: + name: tackle2-ui + path: /tmp/tackle2-ui.tar + retention-days: 1 + + test-integration: + needs: build-and-upload-for-global-ci + uses: konveyor/ci/.github/workflows/global-ci.yml@main + with: + component_name: tackle2-ui + run_api_tests: false diff --git a/client/src/app/components/ConfirmDeleteDialog/ConfirmDeleteDialog.tsx b/client/src/app/components/ConfirmDeleteDialog/ConfirmDeleteDialog.tsx index 5e64af7409..a37059b20d 100644 --- a/client/src/app/components/ConfirmDeleteDialog/ConfirmDeleteDialog.tsx +++ b/client/src/app/components/ConfirmDeleteDialog/ConfirmDeleteDialog.tsx @@ -9,6 +9,7 @@ import { Text, TextInput, } from "@patternfly/react-core"; +import { collapseSpacesAndCompare } from "@app/utils/utils"; import "./ConfirmDeleteDialog.css"; @@ -39,7 +40,12 @@ const ConfirmDeleteDialog: FC = ({ const [nameToDeleteInput, setNameToDeleteInput] = useState(""); - const isDisabled = nameToDeleteInput !== nameToDelete; + /* + Enable the delete button once the input name matches the `nameToDelete`, BUT + collapse spaces since that is the way the name is rendered + */ + const isDisabled = + collapseSpacesAndCompare(nameToDeleteInput, nameToDelete) !== 0; const handleClose = () => { setNameToDeleteInput(""); diff --git a/client/src/app/pages/migration-waves/components/ticket-issue.tsx b/client/src/app/pages/migration-waves/components/ticket-issue.tsx index 3f70f0a551..a1004ffcb5 100644 --- a/client/src/app/pages/migration-waves/components/ticket-issue.tsx +++ b/client/src/app/pages/migration-waves/components/ticket-issue.tsx @@ -1,7 +1,9 @@ import React from "react"; -import { Text } from "@patternfly/react-core"; +import { Text, TextVariants } from "@patternfly/react-core"; import { Ticket } from "@app/api/models"; +import { useTranslation } from "react-i18next"; +import ExternalLink from "@app/components/ExternalLink"; import { useTrackerTypesByProjectId } from "@app/queries/trackers"; export interface ITicketIssueProps { @@ -9,17 +11,26 @@ export interface ITicketIssueProps { } export const TicketIssue: React.FC = ({ ticket }) => { - const useTicketIssue = () => { - const types = useTrackerTypesByProjectId( - ticket?.tracker?.name, - ticket?.parent - ); - const type = types.find((kind) => kind.id === ticket?.kind); - if (type) return type.name; - return ""; - }; + const { t } = useTranslation(); + const ticketIssue = useTicketIssue(ticket); - const ticketIssue = useTicketIssue(); + return ( + + {ticket?.link ? ( + {ticketIssue} + ) : ( + t("terms.unassigned") + )} + + ); +}; + +const useTicketIssue = (ticket?: Ticket) => { + const types = useTrackerTypesByProjectId( + ticket?.tracker?.name, + ticket?.parent + ); + const type = types.find((kind) => kind.id === ticket?.kind); - return {ticketIssue}; + return type ? type.name : ""; }; diff --git a/client/src/app/pages/migration-waves/components/wave-status-table.tsx b/client/src/app/pages/migration-waves/components/wave-status-table.tsx index b59d981837..2be8d576fb 100644 --- a/client/src/app/pages/migration-waves/components/wave-status-table.tsx +++ b/client/src/app/pages/migration-waves/components/wave-status-table.tsx @@ -27,6 +27,8 @@ import { useHistory } from "react-router-dom"; import { useFetchTickets } from "@app/queries/tickets"; import { Paths } from "@app/Paths"; import { TicketIssue } from "./ticket-issue"; +import { useDeleteTicketMutation } from "@app/queries/migration-waves"; +import UnlinkIcon from "@patternfly/react-icons/dist/esm/icons/unlink-icon"; export interface IWaveStatusTableProps { migrationWave: WaveWithStatus; @@ -44,6 +46,7 @@ export const WaveStatusTable: React.FC = ({ const history = useHistory(); const { tickets } = useFetchTickets(); + const { mutate: deleteTicket } = useDeleteTicketMutation(); const tableControls = useLocalTableControls({ idProperty: "name", @@ -130,52 +133,63 @@ export const WaveStatusTable: React.FC = ({ } > - {currentPageItems?.map((app, rowIndex) => ( - - - - {app.name} - - - {getTicketByApplication(tickets, app.id)?.error ? ( + {currentPageItems?.map((app, rowIndex) => { + const ticket = getTicketByApplication(tickets, app.id); + return ( + + + + {app.name} + + + {getTicketByApplication(tickets, app.id)?.error ? ( + + ) : ( + getTicketByApplication(tickets, app?.id)?.status || "" + )} + + + + + + {ticket?.id && ( + - ) : ( - getTicketByApplication(tickets, app?.id)?.status || "" - )} - - - - - - - - - - ))} + + + + ); + })} diff --git a/client/src/app/utils/utils.test.ts b/client/src/app/utils/utils.test.ts index 016eab1841..fac1ca32e7 100644 --- a/client/src/app/utils/utils.test.ts +++ b/client/src/app/utils/utils.test.ts @@ -8,6 +8,7 @@ import { standardURLRegex, formatPath, extractFirstSha, + collapseSpacesAndCompare, } from "./utils"; import { Paths } from "@app/Paths"; @@ -219,3 +220,36 @@ describe("SHA extraction", () => { expect(first).toBe("9c04cd6372077e9b11f70ca111c9807dc7137e4b"); }); }); + +describe("space collapse string compare (using en-US compares)", () => { + it("both undefined matches", () => { + const result = collapseSpacesAndCompare(undefined, undefined, "en-US"); + expect(result).toBe(0); + }); + + it("left undefined goes before right defined", () => { + const result = collapseSpacesAndCompare(undefined, "anything", "en-US"); + expect(result).toBe(-1); + }); + + it("left defined goes after right undefined", () => { + const result = collapseSpacesAndCompare("anything", undefined, "en-US"); + expect(result).toBe(1); + }); + + it.each([ + ["alpha", "alpha", 0], + ["alpha", "bravo", -1], + ["bravo", "alpha", 1], + [" alpha", "alpha ", 0], + ["alpha bravo", "alpha bravo", 0], + ["bravo alpha", "bravo bravo", -1], + ["The quick brown fox ", "The quick brown fox", 0], + ])( + "mismatching spaces work as if spaces are collapsed (%s) to (%s) = %i", + (a, b, expected) => { + const result = collapseSpacesAndCompare(a, b, "en-US"); + expect(result).toBe(expected); + } + ); +}); diff --git a/client/src/app/utils/utils.ts b/client/src/app/utils/utils.ts index 29c3a8840a..f8e87259fc 100644 --- a/client/src/app/utils/utils.ts +++ b/client/src/app/utils/utils.ts @@ -168,3 +168,24 @@ export const extractFirstSha = (str: string): string | undefined => { const match = str.match(SHA_REGEX); return match && match[0] ? match[0] : undefined; }; + +export const collapseSpacesAndCompare = ( + str1: string | undefined, + str2: string | undefined, + locale?: string +): number => { + if (!str1 && !str2) { + return 0; + } + if (str1 && !str2) { + return 1; + } + if (!str1 && str2) { + return -1; + } + + const a = str1?.trim().replace(/\s+/g, " ") ?? ""; + const b = str2?.trim().replace(/\s+/g, " ") ?? ""; + + return a.localeCompare(b, locale); +};