From 1c663a4e23d957c36ff887479b0fcb193e32029a Mon Sep 17 00:00:00 2001 From: Fabian von Feilitzsch Date: Mon, 27 Nov 2023 11:33:56 -0500 Subject: [PATCH 1/3] :seedling: Add global ci (#1405) ## Global CI Integration for Component Builds This PR integrates a GitHub Action workflow to build and upload the component images, preparing them for the global CI system. By integrating the global CI, we aim to streamline and standardize our CI process across all components, ensuring a more efficient and unified CI/CD pipeline. Signed-off-by: Fabian von Feilitzsch Co-authored-by: Ian Bolton --- .github/workflows/ci-actions.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) 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 From c7c6d7c54fa1bf516dee95d2392339d886afb61b Mon Sep 17 00:00:00 2001 From: Ian Bolton Date: Mon, 27 Nov 2023 12:25:40 -0500 Subject: [PATCH 2/3] :bug: Add link to associated ticket (#1565) Resolves https://issues.redhat.com/browse/MTA-701 Resolves https://issues.redhat.com/browse/MTA-1539 --------- Signed-off-by: ibolton336 --- .../components/ticket-issue.tsx | 35 ++++--- .../components/wave-status-table.tsx | 96 +++++++++++-------- 2 files changed, 78 insertions(+), 53 deletions(-) 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 || "" - )} - - - - - - - - - - ))} + + + + ); + })} From ae8c567f968a4193335f7e7eed7ec1b79eb4103b Mon Sep 17 00:00:00 2001 From: Scott Dickerson Date: Mon, 27 Nov 2023 15:30:12 -0500 Subject: [PATCH 3/3] :bug: Handle confirm deletes with multiple spaces (#1572) Resolves: https://issues.redhat.com/browse/MTA-1725 When confirming the deletion of an entity by requiring the user to enter the name of the entity, the string check needs to ignore differences in white space. The entity name may contain multiple spaces between words, but not show the spaces when viewing the name outside of an input box. HTML normally collapses multiple spaces into a single space. Also if the confirming name gets an extra space typed, that can cause a hard to see string mismatch. Trimming and then collapsing multiple spaces into a single space before comparing the string avoids this problem. Signed-off-by: Scott J Dickerson --- .../ConfirmDeleteDialog.tsx | 8 ++++- client/src/app/utils/utils.test.ts | 34 +++++++++++++++++++ client/src/app/utils/utils.ts | 21 ++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) 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/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); +};