From 0bdd6a816d683d2b7bd1b1eca802387ae82c2845 Mon Sep 17 00:00:00 2001 From: Kimi Kuru Date: Tue, 16 Jul 2024 10:07:09 +0300 Subject: [PATCH 01/14] Add Jira connect alert to entryform --- web/src/components/entry-dialog/EntryForm.tsx | 6 +++++ web/src/components/settings/SettingsMenu.tsx | 6 ++--- web/src/i18n/en.ts | 2 ++ web/src/i18n/fi.ts | 2 ++ .../jira/components/JiraIntegrationAlert.tsx | 23 +++++++++++++++++++ web/src/jira/jiraUtils.ts | 10 ++++++++ 6 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 web/src/jira/components/JiraIntegrationAlert.tsx diff --git a/web/src/components/entry-dialog/EntryForm.tsx b/web/src/components/entry-dialog/EntryForm.tsx index 643edb1e..25c750a9 100644 --- a/web/src/components/entry-dialog/EntryForm.tsx +++ b/web/src/components/entry-dialog/EntryForm.tsx @@ -31,6 +31,7 @@ import WorkdayHours from "./WorkdayHours"; import useEntryForm, { EntryFormSchema } from "./useEntryForm"; import { useIsJiraAuthenticated } from "../../jira/jiraApi"; import JiraIssueComboBox from "../../jira/components/JiraIssueComboBox"; +import { JiraIntegrationAlert } from "../../jira/components/JiraIntegrationAlert"; export type EntryFormProps = { form: UseFormReturn; @@ -132,6 +133,11 @@ const EntryForm = () => { )} /> + {!isJiraAuth && ( + + + + )} diff --git a/web/src/components/settings/SettingsMenu.tsx b/web/src/components/settings/SettingsMenu.tsx index c6dcb126..6c4a48f1 100644 --- a/web/src/components/settings/SettingsMenu.tsx +++ b/web/src/components/settings/SettingsMenu.tsx @@ -6,8 +6,8 @@ import Menu from "@mui/material/Menu"; import MenuItem from "@mui/material/MenuItem"; import { useTranslation } from "react-i18next"; import { generatePath, useLocation, useNavigate } from "react-router-dom"; -import { keijoJiraApiUrl } from "../../jira/jiraConfig"; import { useIsJiraAuthenticated } from "../../jira/jiraApi"; +import { connectToJira, disconnectJira } from "../../jira/jiraUtils"; type SettingsMenuProps = { anchor: HTMLElement | null; @@ -27,12 +27,12 @@ const SettingsMenu = ({ anchor, onClose }: SettingsMenuProps) => { const handleConnectToJira = () => { onClose(); - window.location.href = keijoJiraApiUrl; + connectToJira(); }; const handleDisconnectJira = () => { onClose(); - window.location.href = keijoJiraApiUrl + "/remove-session"; + disconnectJira(); }; return ( diff --git a/web/src/i18n/en.ts b/web/src/i18n/en.ts index 0677ad9b..1403fa1b 100644 --- a/web/src/i18n/en.ts +++ b/web/src/i18n/en.ts @@ -113,6 +113,8 @@ const en = { all: "All", recent: "Recent", }, + connectNotification: + "Jira Integration has been added to Keijo. Connect to Jira to get e.g., issue summaries.", }, }; diff --git a/web/src/i18n/fi.ts b/web/src/i18n/fi.ts index e0c48358..800e7abe 100644 --- a/web/src/i18n/fi.ts +++ b/web/src/i18n/fi.ts @@ -113,6 +113,8 @@ const fi = { all: "Kaikki", recent: "Viimeaikaiset", }, + connectNotification: + "Jira-integraation on lisätty Keijoon. Yhdistä Jiraan saadaksesi mm. tikettien otsikot Jirasta.", }, }; diff --git a/web/src/jira/components/JiraIntegrationAlert.tsx b/web/src/jira/components/JiraIntegrationAlert.tsx new file mode 100644 index 00000000..acdf1bb4 --- /dev/null +++ b/web/src/jira/components/JiraIntegrationAlert.tsx @@ -0,0 +1,23 @@ +import { Alert, Button } from "@mui/material"; +import { t } from "i18next"; +import { connectToJira } from "../jiraUtils"; + +export const JiraIntegrationAlert = () => { + return ( + + + + + } + > + {t("jira.connectNotification")} + + ); +}; diff --git a/web/src/jira/jiraUtils.ts b/web/src/jira/jiraUtils.ts index ff3c0935..cf107c88 100644 --- a/web/src/jira/jiraUtils.ts +++ b/web/src/jira/jiraUtils.ts @@ -1,3 +1,5 @@ +import { keijoJiraApiUrl } from "./jiraConfig"; + export const mergePages = (...arrays: T[][][]): T[][] => { const maxLength = Math.max(...arrays.map((arr) => arr.length)); return Array.from({ length: maxLength }, (_, i) => { @@ -50,3 +52,11 @@ export const removeWord = (searchFilter: string, word: string) => .filter((text) => text.trim() !== word) .join(" ") : searchFilter; + +export const connectToJira = () => { + window.location.href = keijoJiraApiUrl; +}; + +export const disconnectJira = () => { + window.location.href = keijoJiraApiUrl + "/remove-session"; +}; From 358fe295e2947ebca19e24d1f1d4dab5e8359f84 Mon Sep 17 00:00:00 2001 From: Kimi Kuru Date: Tue, 16 Jul 2024 11:52:35 +0300 Subject: [PATCH 02/14] Add jira notification setting --- .../1721115925197-add-jira-auth-option.ts | 18 ++++++++++++++++++ .../user-settings/dto/update-settings.dto.ts | 3 +++ .../src/user-settings/user-settings.model.ts | 4 ++++ web/src/graphql/generated/graphql.ts | 6 ++++-- web/src/graphql/user-settings.graphql | 1 + 5 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 server/src/database/migrations/1721115925197-add-jira-auth-option.ts diff --git a/server/src/database/migrations/1721115925197-add-jira-auth-option.ts b/server/src/database/migrations/1721115925197-add-jira-auth-option.ts new file mode 100644 index 00000000..ae88fc2d --- /dev/null +++ b/server/src/database/migrations/1721115925197-add-jira-auth-option.ts @@ -0,0 +1,18 @@ +import { MigrationInterface, QueryRunner, TableColumn } from "typeorm"; + +export class Migrations1721115925197 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.addColumn( + "user_settings", + new TableColumn({ + name: "jiraNotificationIgnore", + type: "boolean", + isNullable: true, + }), + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.dropColumn("user_settings", "jiraNotificationIgnore"); + } +} diff --git a/server/src/user-settings/dto/update-settings.dto.ts b/server/src/user-settings/dto/update-settings.dto.ts index ace4af93..4e97f20f 100644 --- a/server/src/user-settings/dto/update-settings.dto.ts +++ b/server/src/user-settings/dto/update-settings.dto.ts @@ -7,4 +7,7 @@ export class UpdateSettingsDto { @Field({ nullable: true }) activityPreset?: string; + + @Field({ nullable: true }) + jiraNotificationIgnore?: boolean; } diff --git a/server/src/user-settings/user-settings.model.ts b/server/src/user-settings/user-settings.model.ts index 99547ccf..7689c51e 100644 --- a/server/src/user-settings/user-settings.model.ts +++ b/server/src/user-settings/user-settings.model.ts @@ -15,4 +15,8 @@ export class UserSettings { @Column({ nullable: true }) @Field({ nullable: true }) activityPreset: string; + + @Column({ nullable: true }) + @Field({ nullable: true }) + jiraNotificationIgnore: boolean; } diff --git a/web/src/graphql/generated/graphql.ts b/web/src/graphql/generated/graphql.ts index 24aaf2e4..7560fc19 100644 --- a/web/src/graphql/generated/graphql.ts +++ b/web/src/graphql/generated/graphql.ts @@ -115,6 +115,7 @@ export type SessionStatus = { export type UpdateSettingsDto = { activityPreset?: InputMaybe; + jiraNotificationIgnore?: InputMaybe; productPreset?: InputMaybe; }; @@ -122,6 +123,7 @@ export type UserSettings = { __typename?: 'UserSettings'; activityPreset?: Maybe; employeeNumber: Scalars['Float']['output']; + jiraNotificationIgnore?: Maybe; productPreset?: Maybe; }; @@ -174,7 +176,7 @@ export type ReplaceWorkdayEntryMutation = { __typename?: 'Mutation', replaceWork export type GetMySettingsQueryVariables = Exact<{ [key: string]: never; }>; -export type GetMySettingsQuery = { __typename?: 'Query', getMySettings: { __typename?: 'UserSettings', employeeNumber: number, productPreset?: string | null, activityPreset?: string | null } }; +export type GetMySettingsQuery = { __typename?: 'Query', getMySettings: { __typename?: 'UserSettings', employeeNumber: number, productPreset?: string | null, activityPreset?: string | null, jiraNotificationIgnore?: boolean | null } }; export type UpdateSettingsMutationVariables = Exact<{ settings: UpdateSettingsDto; @@ -190,5 +192,5 @@ export const FindWorkdaysDocument = {"kind":"Document","definitions":[{"kind":"O export const GetSessionStatusDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetSessionStatus"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getSessionStatus"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"employeeNumber"}}]}}]}}]} as unknown as DocumentNode; export const RemoveWorkdayEntryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RemoveWorkdayEntry"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"entry"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"RemoveWorkdayEntryInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"removeWorkdayEntry"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"entry"},"value":{"kind":"Variable","name":{"kind":"Name","value":"entry"}}}]}]}}]} as unknown as DocumentNode; export const ReplaceWorkdayEntryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ReplaceWorkdayEntry"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"originalEntry"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"RemoveWorkdayEntryInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"replacementEntry"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"AddWorkdayEntryInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"replaceWorkdayEntry"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"originalEntry"},"value":{"kind":"Variable","name":{"kind":"Name","value":"originalEntry"}}},{"kind":"Argument","name":{"kind":"Name","value":"replacementEntry"},"value":{"kind":"Variable","name":{"kind":"Name","value":"replacementEntry"}}}]}]}}]} as unknown as DocumentNode; -export const GetMySettingsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetMySettings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getMySettings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"employeeNumber"}},{"kind":"Field","name":{"kind":"Name","value":"productPreset"}},{"kind":"Field","name":{"kind":"Name","value":"activityPreset"}}]}}]}}]} as unknown as DocumentNode; +export const GetMySettingsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetMySettings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getMySettings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"employeeNumber"}},{"kind":"Field","name":{"kind":"Name","value":"productPreset"}},{"kind":"Field","name":{"kind":"Name","value":"activityPreset"}},{"kind":"Field","name":{"kind":"Name","value":"jiraNotificationIgnore"}}]}}]}}]} as unknown as DocumentNode; export const UpdateSettingsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateSettings"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"settings"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateSettingsDto"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateSettings"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"settings"},"value":{"kind":"Variable","name":{"kind":"Name","value":"settings"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"employeeNumber"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/web/src/graphql/user-settings.graphql b/web/src/graphql/user-settings.graphql index f4d38f88..bd46f3a5 100644 --- a/web/src/graphql/user-settings.graphql +++ b/web/src/graphql/user-settings.graphql @@ -3,6 +3,7 @@ query GetMySettings { employeeNumber productPreset activityPreset + jiraNotificationIgnore } } From 2b862fc091d56d8c69257b684cab067db64aaf87 Mon Sep 17 00:00:00 2001 From: Kimi Kuru Date: Tue, 16 Jul 2024 13:41:02 +0300 Subject: [PATCH 03/14] Add Jira Integration alert to entry form --- web/src/components/entry-dialog/EntryForm.tsx | 27 +++++++++++++++---- .../workday-browser/WorkdayList.tsx | 3 +-- web/src/i18n/en.ts | 2 +- .../jira/components/JiraIntegrationAlert.tsx | 12 ++++++--- web/src/jira/jiraApi.ts | 2 +- 5 files changed, 33 insertions(+), 13 deletions(-) diff --git a/web/src/components/entry-dialog/EntryForm.tsx b/web/src/components/entry-dialog/EntryForm.tsx index 25c750a9..4b3fe540 100644 --- a/web/src/components/entry-dialog/EntryForm.tsx +++ b/web/src/components/entry-dialog/EntryForm.tsx @@ -21,7 +21,12 @@ import { Controller, UseFormReturn } from "react-hook-form"; import { useTranslation } from "react-i18next"; import { useLocation, useNavigate } from "react-router-dom"; import useDayjs from "../../common/useDayjs"; -import { AcceptanceStatus, Entry } from "../../graphql/generated/graphql"; +import { + AcceptanceStatus, + Entry, + GetMySettingsDocument, + UpdateSettingsDocument, +} from "../../graphql/generated/graphql"; import usePreferSetRemainingHours from "../user-preferences/usePreferSetRemainingHours"; import BigDeleteEntryButton from "./BigDeleteEntryButton"; import DimensionComboBox from "./DimensionComboBox"; @@ -32,6 +37,8 @@ import useEntryForm, { EntryFormSchema } from "./useEntryForm"; import { useIsJiraAuthenticated } from "../../jira/jiraApi"; import JiraIssueComboBox from "../../jira/components/JiraIssueComboBox"; import { JiraIntegrationAlert } from "../../jira/components/JiraIntegrationAlert"; +import { useMutation, useQuery } from "@apollo/client"; +import { connectToJira } from "../../jira/jiraUtils"; export type EntryFormProps = { form: UseFormReturn; @@ -74,7 +81,12 @@ const EntryForm = () => { const { userPrefersSetRemainingHours, toggleRemainingHours } = usePreferSetRemainingHours(); const { control, watch } = form; const dateWatch = dayjs(watch("date")).locale(dayjs.locale()); - const { isJiraAuth } = useIsJiraAuthenticated(); + const { isJiraAuth, isLoading } = useIsJiraAuthenticated(); + + const { data } = useQuery(GetMySettingsDocument); + const [updateSettings] = useMutation(UpdateSettingsDocument, { + refetchQueries: [GetMySettingsDocument], + }); return (
@@ -133,11 +145,16 @@ const EntryForm = () => { )} /> - {!isJiraAuth && ( + {data && !data.getMySettings.jiraNotificationIgnore && !isJiraAuth && !isLoading ? ( - + + updateSettings({ variables: { settings: { jiraNotificationIgnore: true } } }) + } + /> - )} + ) : null} diff --git a/web/src/components/workday-browser/WorkdayList.tsx b/web/src/components/workday-browser/WorkdayList.tsx index 81550a56..b436c727 100644 --- a/web/src/components/workday-browser/WorkdayList.tsx +++ b/web/src/components/workday-browser/WorkdayList.tsx @@ -59,12 +59,11 @@ const WorkdayList = () => { return ( <> - {dividedWorkdays.map((wdArr) => { if (isWeekend(wdArr[0].date)) { return ( - + {wdArr.map((wd) => ( ))} diff --git a/web/src/i18n/en.ts b/web/src/i18n/en.ts index 1403fa1b..d2016d4f 100644 --- a/web/src/i18n/en.ts +++ b/web/src/i18n/en.ts @@ -114,7 +114,7 @@ const en = { recent: "Recent", }, connectNotification: - "Jira Integration has been added to Keijo. Connect to Jira to get e.g., issue summaries.", + "Jira Integration has been added to Keijo. Connect Jira to get features such as issue summaries.", }, }; diff --git a/web/src/jira/components/JiraIntegrationAlert.tsx b/web/src/jira/components/JiraIntegrationAlert.tsx index acdf1bb4..a2a203de 100644 --- a/web/src/jira/components/JiraIntegrationAlert.tsx +++ b/web/src/jira/components/JiraIntegrationAlert.tsx @@ -1,17 +1,21 @@ import { Alert, Button } from "@mui/material"; import { t } from "i18next"; -import { connectToJira } from "../jiraUtils"; -export const JiraIntegrationAlert = () => { +type JiraIntegrationAlertProps = { + onConnect: () => void; + onHide: () => void; +}; + +export const JiraIntegrationAlert = ({ onConnect, onHide }: JiraIntegrationAlertProps) => { return ( - - diff --git a/web/src/jira/jiraApi.ts b/web/src/jira/jiraApi.ts index cd96a18b..9a400365 100644 --- a/web/src/jira/jiraApi.ts +++ b/web/src/jira/jiraApi.ts @@ -70,7 +70,7 @@ const getIssues = async ( export const useIsJiraAuthenticated = () => { const { data, error, isLoading } = useGetAccessToken(); - return { isJiraAuth: !isLoading && data && !error, data, error }; + return { isJiraAuth: !isLoading && !error && data, data, error, isLoading }; }; /** From f42ba08c2174b5cf2ba929d0041ed036e033da35 Mon Sep 17 00:00:00 2001 From: Kimi Kuru Date: Wed, 17 Jul 2024 09:45:15 +0300 Subject: [PATCH 04/14] Add translations for Jira integration alert --- web/src/i18n/en.ts | 1 + web/src/i18n/fi.ts | 3 ++- web/src/jira/components/JiraIntegrationAlert.tsx | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/web/src/i18n/en.ts b/web/src/i18n/en.ts index d2016d4f..78628f05 100644 --- a/web/src/i18n/en.ts +++ b/web/src/i18n/en.ts @@ -24,6 +24,7 @@ const en = { jiraDisconnect: "Disconnect from Jira", showWeekend: "Show Weekend", hideWeekend: "Hide Weekend", + hide: "Hide", }, dimensionNames: { product: "Product", diff --git a/web/src/i18n/fi.ts b/web/src/i18n/fi.ts index 800e7abe..de5b7cba 100644 --- a/web/src/i18n/fi.ts +++ b/web/src/i18n/fi.ts @@ -24,6 +24,7 @@ const fi = { jiraDisconnect: "Katkaise Jira-yhteys", showWeekend: "Näytä Viikonloppu", hideWeekend: "Piilota Viikonloppu", + hide: "Piilota", }, dimensionNames: { product: "Tuote", @@ -114,7 +115,7 @@ const fi = { recent: "Viimeaikaiset", }, connectNotification: - "Jira-integraation on lisätty Keijoon. Yhdistä Jiraan saadaksesi mm. tikettien otsikot Jirasta.", + "Jira-integraatio on lisätty Keijoon. Yhdistä Jiraan saadaksesi mm. tikettien otsikot Jirasta.", }, }; diff --git a/web/src/jira/components/JiraIntegrationAlert.tsx b/web/src/jira/components/JiraIntegrationAlert.tsx index a2a203de..d19e0be4 100644 --- a/web/src/jira/components/JiraIntegrationAlert.tsx +++ b/web/src/jira/components/JiraIntegrationAlert.tsx @@ -13,10 +13,10 @@ export const JiraIntegrationAlert = ({ onConnect, onHide }: JiraIntegrationAlert action={ <> } From fdb0639544656ba72ba1eb27a13c5284a13802d3 Mon Sep 17 00:00:00 2001 From: Kimi Kuru Date: Thu, 18 Jul 2024 13:53:41 +0300 Subject: [PATCH 05/14] Edit jira translations --- web/src/i18n/en.ts | 2 +- web/src/i18n/fi.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/web/src/i18n/en.ts b/web/src/i18n/en.ts index 78628f05..47bce3d8 100644 --- a/web/src/i18n/en.ts +++ b/web/src/i18n/en.ts @@ -115,7 +115,7 @@ const en = { recent: "Recent", }, connectNotification: - "Jira Integration has been added to Keijo. Connect Jira to get features such as issue summaries.", + "Jira Integration has been added to Keijo. Connect Jira to get new features such as issue summaries and new issue search.", }, }; diff --git a/web/src/i18n/fi.ts b/web/src/i18n/fi.ts index de5b7cba..0f060a89 100644 --- a/web/src/i18n/fi.ts +++ b/web/src/i18n/fi.ts @@ -115,7 +115,7 @@ const fi = { recent: "Viimeaikaiset", }, connectNotification: - "Jira-integraatio on lisätty Keijoon. Yhdistä Jiraan saadaksesi mm. tikettien otsikot Jirasta.", + "Jira-integraatio on lisätty Keijoon. Yhdistämällä Jiraan saat käyttöösi muun muassa tikettien otsikot ja sen myötä uudistuneen tikettien hakutoiminnon.", }, }; From b23255fa0df8aaa1ea2f0de27d968f8b75f04144 Mon Sep 17 00:00:00 2001 From: Kimi Kuru Date: Thu, 18 Jul 2024 16:41:31 +0300 Subject: [PATCH 06/14] Add info dialog when connecting to Jira --- web/src/components/entry-dialog/EntryForm.tsx | 2 - web/src/components/settings/SettingsMenu.tsx | 9 ++-- web/src/i18n/en.ts | 6 +++ web/src/i18n/fi.ts | 6 +++ web/src/jira/components/JiraInfoDialog.tsx | 30 ++++++++++++ .../jira/components/JiraIntegrationAlert.tsx | 49 ++++++++++++------- 6 files changed, 80 insertions(+), 22 deletions(-) create mode 100644 web/src/jira/components/JiraInfoDialog.tsx diff --git a/web/src/components/entry-dialog/EntryForm.tsx b/web/src/components/entry-dialog/EntryForm.tsx index 4b3fe540..1636f08b 100644 --- a/web/src/components/entry-dialog/EntryForm.tsx +++ b/web/src/components/entry-dialog/EntryForm.tsx @@ -38,7 +38,6 @@ import { useIsJiraAuthenticated } from "../../jira/jiraApi"; import JiraIssueComboBox from "../../jira/components/JiraIssueComboBox"; import { JiraIntegrationAlert } from "../../jira/components/JiraIntegrationAlert"; import { useMutation, useQuery } from "@apollo/client"; -import { connectToJira } from "../../jira/jiraUtils"; export type EntryFormProps = { form: UseFormReturn; @@ -148,7 +147,6 @@ const EntryForm = () => { {data && !data.getMySettings.jiraNotificationIgnore && !isJiraAuth && !isLoading ? ( updateSettings({ variables: { settings: { jiraNotificationIgnore: true } } }) } diff --git a/web/src/components/settings/SettingsMenu.tsx b/web/src/components/settings/SettingsMenu.tsx index 6c4a48f1..cc86d60f 100644 --- a/web/src/components/settings/SettingsMenu.tsx +++ b/web/src/components/settings/SettingsMenu.tsx @@ -7,7 +7,9 @@ import MenuItem from "@mui/material/MenuItem"; import { useTranslation } from "react-i18next"; import { generatePath, useLocation, useNavigate } from "react-router-dom"; import { useIsJiraAuthenticated } from "../../jira/jiraApi"; -import { connectToJira, disconnectJira } from "../../jira/jiraUtils"; +import { disconnectJira } from "../../jira/jiraUtils"; +import { JiraInfoDialog } from "../../jira/components/JiraInfoDialog"; +import { useState } from "react"; type SettingsMenuProps = { anchor: HTMLElement | null; @@ -19,6 +21,7 @@ const SettingsMenu = ({ anchor, onClose }: SettingsMenuProps) => { const navigate = useNavigate(); const location = useLocation(); const { isJiraAuth } = useIsJiraAuthenticated(); + const [infoDialogOpen, setInfoDialogOpen] = useState(false); const handleSetDefaultValues = () => { onClose(); @@ -26,8 +29,7 @@ const SettingsMenu = ({ anchor, onClose }: SettingsMenuProps) => { }; const handleConnectToJira = () => { - onClose(); - connectToJira(); + setInfoDialogOpen(true); }; const handleDisconnectJira = () => { @@ -63,6 +65,7 @@ const SettingsMenu = ({ anchor, onClose }: SettingsMenuProps) => { {t("controls.jiraConnect")} )} + setInfoDialogOpen(false)} /> ); }; diff --git a/web/src/i18n/en.ts b/web/src/i18n/en.ts index 47bce3d8..44a6874e 100644 --- a/web/src/i18n/en.ts +++ b/web/src/i18n/en.ts @@ -116,6 +116,12 @@ const en = { }, connectNotification: "Jira Integration has been added to Keijo. Connect Jira to get new features such as issue summaries and new issue search.", + infoDialog: { + title: "Keijo-Jira", + // Site could also be set dynamically from server or simply by .atlassian.net + content: + "You will be redirected to authorize Keijo to use Jira. Login on Atlassian site and choose to authorize site funidata.atlassian.net from the dropdown.", + }, }, }; diff --git a/web/src/i18n/fi.ts b/web/src/i18n/fi.ts index 0f060a89..f5046d17 100644 --- a/web/src/i18n/fi.ts +++ b/web/src/i18n/fi.ts @@ -116,6 +116,12 @@ const fi = { }, connectNotification: "Jira-integraatio on lisätty Keijoon. Yhdistämällä Jiraan saat käyttöösi muun muassa tikettien otsikot ja sen myötä uudistuneen tikettien hakutoiminnon.", + infoDialog: { + title: "Keijo-Jira", + // Site could also be set dynamically from server or simply by .atlassian.net + content: + "Sinut ohjataan valtuuttamaan Jira-integraatio käyttäjälläsi. Kirjaudu Atlassianin sivulla ja valitse valikosta Keijolle oikeudet sivulle funidata.atlassian.net.", + }, }, }; diff --git a/web/src/jira/components/JiraInfoDialog.tsx b/web/src/jira/components/JiraInfoDialog.tsx new file mode 100644 index 00000000..c4e0d4cf --- /dev/null +++ b/web/src/jira/components/JiraInfoDialog.tsx @@ -0,0 +1,30 @@ +import Button from "@mui/material/Button"; +import Dialog from "@mui/material/Dialog"; +import DialogActions from "@mui/material/DialogActions"; +import DialogContent from "@mui/material/DialogContent"; +import DialogContentText from "@mui/material/DialogContentText"; +import DialogTitle from "@mui/material/DialogTitle"; +import { t } from "i18next"; +import { connectToJira } from "../jiraUtils"; + +type JiraInfoDialogProps = { + open: boolean; + handleClose: () => void; +}; + +export const JiraInfoDialog = ({ open, handleClose }: JiraInfoDialogProps) => { + return ( + + {t("jira.infoDialog.title")} + + {t("jira.infoDialog.content")} + + + + + + + ); +}; diff --git a/web/src/jira/components/JiraIntegrationAlert.tsx b/web/src/jira/components/JiraIntegrationAlert.tsx index d19e0be4..326c7c6b 100644 --- a/web/src/jira/components/JiraIntegrationAlert.tsx +++ b/web/src/jira/components/JiraIntegrationAlert.tsx @@ -1,27 +1,42 @@ import { Alert, Button } from "@mui/material"; import { t } from "i18next"; +import { JiraInfoDialog } from "./JiraInfoDialog"; +import { useState } from "react"; type JiraIntegrationAlertProps = { - onConnect: () => void; onHide: () => void; }; -export const JiraIntegrationAlert = ({ onConnect, onHide }: JiraIntegrationAlertProps) => { +export const JiraIntegrationAlert = ({ onHide }: JiraIntegrationAlertProps) => { + const [infoDialogOpen, setInfoDialogOpen] = useState(false); return ( - - - - - } - > - {t("jira.connectNotification")} - + <> + + + + + } + > + {t("jira.connectNotification")} + + { + setInfoDialogOpen(false); + }} + /> + ); }; From 5cc80f136b239c311153fa288f830bcf74c212d2 Mon Sep 17 00:00:00 2001 From: Kimi Kuru Date: Wed, 7 Aug 2024 09:45:59 +0300 Subject: [PATCH 07/14] Edit integration alert translations --- web/src/i18n/en.ts | 2 +- web/src/i18n/fi.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/web/src/i18n/en.ts b/web/src/i18n/en.ts index 44a6874e..3aca957c 100644 --- a/web/src/i18n/en.ts +++ b/web/src/i18n/en.ts @@ -120,7 +120,7 @@ const en = { title: "Keijo-Jira", // Site could also be set dynamically from server or simply by .atlassian.net content: - "You will be redirected to authorize Keijo to use Jira. Login on Atlassian site and choose to authorize site funidata.atlassian.net from the dropdown.", + "You will be redirected to authorize Keijo to use Jira. Login on Atlassian site and choose to authorize appropriate site e.g., funidata.atlassian.net from the dropdown.", }, }, }; diff --git a/web/src/i18n/fi.ts b/web/src/i18n/fi.ts index f5046d17..a680ce2e 100644 --- a/web/src/i18n/fi.ts +++ b/web/src/i18n/fi.ts @@ -120,7 +120,7 @@ const fi = { title: "Keijo-Jira", // Site could also be set dynamically from server or simply by .atlassian.net content: - "Sinut ohjataan valtuuttamaan Jira-integraatio käyttäjälläsi. Kirjaudu Atlassianin sivulla ja valitse valikosta Keijolle oikeudet sivulle funidata.atlassian.net.", + "Sinut ohjataan valtuuttamaan Jira-integraatio käyttäjälläsi. Kirjaudu Atlassianin sivulla ja valitse valikosta Keijolle oikeudet käytettävälle sivulle esim. funidata.atlassian.net.", }, }, }; From 9ebb2ce0887c43de86056c86220b1d7d39a3bf7e Mon Sep 17 00:00:00 2001 From: Kimi Kuru Date: Fri, 16 Aug 2024 13:50:19 +0300 Subject: [PATCH 08/14] Add JiraInfoDialog to AppMenu --- web/src/components/layout/AppMenu.tsx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/web/src/components/layout/AppMenu.tsx b/web/src/components/layout/AppMenu.tsx index 21a9221d..3ba84c92 100644 --- a/web/src/components/layout/AppMenu.tsx +++ b/web/src/components/layout/AppMenu.tsx @@ -25,6 +25,7 @@ import useDarkMode from "../../theme/useDarkMode"; import LabelledIconButton from "../LabelledIconButton"; import { keijoJiraApiUrl } from "../../jira/jiraConfig"; import { useIsJiraAuthenticated } from "../../jira/jiraApi"; +import { JiraInfoDialog } from "../../jira/components/JiraInfoDialog"; const AppMenuButton = () => { const navigate = useNavigate(); @@ -38,6 +39,12 @@ const AppMenuButton = () => { const { isJiraAuth } = useIsJiraAuthenticated(); + const [infoDialogOpen, setInfoDialogOpen] = useState(false); + + const handleConnectToJira = () => { + setInfoDialogOpen(true); + }; + const toggleMenu = () => { setMenuOpen((prev) => !prev); }; @@ -47,11 +54,6 @@ const AppMenuButton = () => { document.documentElement.lang = languageCode; }; - const handleConnectToJira = () => { - toggleMenu(); - window.location.href = keijoJiraApiUrl; - }; - const handleDisconnectJira = () => { toggleMenu(); window.location.href = keijoJiraApiUrl + "/remove-session"; @@ -139,6 +141,7 @@ const AppMenuButton = () => { + setInfoDialogOpen(false)} /> ); }; From d505c38bc0319537e33b34f158ae5abf4124715f Mon Sep 17 00:00:00 2001 From: Kimi Kuru Date: Fri, 16 Aug 2024 13:52:30 +0300 Subject: [PATCH 09/14] Adjust e2e tests to click dialog confirm when connecting to Jira --- e2e/tests/controls.mobile.spec.ts | 1 + e2e/tests/controls.spec.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/e2e/tests/controls.mobile.spec.ts b/e2e/tests/controls.mobile.spec.ts index 18df5c1c..4fa6bc7e 100644 --- a/e2e/tests/controls.mobile.spec.ts +++ b/e2e/tests/controls.mobile.spec.ts @@ -49,6 +49,7 @@ test.describe("Connect Jira Mobile", () => { test("Connect to Jira", async ({ page, t }) => { await page.getByRole("banner").getByLabel(t("controls.openMenu")).click(); await page.getByRole("button", { name: t("controls.jiraConnect") }).click(); + await page.getByRole("button", { name: t("controls.jiraConnect") }).click(); await expect(page).toHaveURL(/.*id\.atlassian\.com\/login.*/); }); diff --git a/e2e/tests/controls.spec.ts b/e2e/tests/controls.spec.ts index aa5b2342..52febeb1 100644 --- a/e2e/tests/controls.spec.ts +++ b/e2e/tests/controls.spec.ts @@ -49,6 +49,7 @@ test.describe("Connect Jira", () => { test("Connect to Jira", async ({ page, t }) => { await page.getByLabel(t("controls.settingsMenu")).click(); await page.getByRole("menuitem", { name: t("controls.jiraConnect") }).click(); + await page.getByRole("button", { name: t("controls.jiraConnect") }).click(); await expect(page).toHaveURL(/.*id\.atlassian\.com\/login.*/); }); From 32268d45c3e802a717dbcc1192f5a30059201b9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joonas=20H=C3=A4kkinen?= Date: Fri, 18 Oct 2024 15:08:52 +0300 Subject: [PATCH 10/14] Improved button layout for Jira integration alert --- .../jira/components/JiraIntegrationAlert.tsx | 36 +++++++++---------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/web/src/jira/components/JiraIntegrationAlert.tsx b/web/src/jira/components/JiraIntegrationAlert.tsx index 326c7c6b..b2505cee 100644 --- a/web/src/jira/components/JiraIntegrationAlert.tsx +++ b/web/src/jira/components/JiraIntegrationAlert.tsx @@ -1,7 +1,7 @@ -import { Alert, Button } from "@mui/material"; +import { Alert, Box, Button, useMediaQuery, useTheme } from "@mui/material"; import { t } from "i18next"; -import { JiraInfoDialog } from "./JiraInfoDialog"; import { useState } from "react"; +import { JiraInfoDialog } from "./JiraInfoDialog"; type JiraIntegrationAlertProps = { onHide: () => void; @@ -9,27 +9,23 @@ type JiraIntegrationAlertProps = { export const JiraIntegrationAlert = ({ onHide }: JiraIntegrationAlertProps) => { const [infoDialogOpen, setInfoDialogOpen] = useState(false); + const theme = useTheme(); + const mobile = useMediaQuery(theme.breakpoints.down("md")); + return ( <> - - - - - } - > + {t("jira.connectNotification")} + + + Date: Fri, 18 Oct 2024 15:44:10 +0300 Subject: [PATCH 11/14] Add some guidance to Jira integration alert --- web/src/i18n/en.ts | 7 +++++-- web/src/i18n/fi.ts | 7 +++++-- web/src/jira/components/JiraIntegrationAlert.tsx | 6 ++++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/web/src/i18n/en.ts b/web/src/i18n/en.ts index 3aca957c..c8c9a212 100644 --- a/web/src/i18n/en.ts +++ b/web/src/i18n/en.ts @@ -114,8 +114,11 @@ const en = { all: "All", recent: "Recent", }, - connectNotification: - "Jira Integration has been added to Keijo. Connect Jira to get new features such as issue summaries and new issue search.", + connectNotificationTitle: "New: Jira Integration", + connectNotification1: + "Keijo now supports reading issue data from Jira to make issue selection easier. You have to connect Keijo to Jira using your own Atlassian account to enable these features.", + connectNotification2: + "If you hide this notification, you can always connect later via the settings menu.", infoDialog: { title: "Keijo-Jira", // Site could also be set dynamically from server or simply by .atlassian.net diff --git a/web/src/i18n/fi.ts b/web/src/i18n/fi.ts index a680ce2e..a9d2c23b 100644 --- a/web/src/i18n/fi.ts +++ b/web/src/i18n/fi.ts @@ -114,8 +114,11 @@ const fi = { all: "Kaikki", recent: "Viimeaikaiset", }, - connectNotification: - "Jira-integraatio on lisätty Keijoon. Yhdistämällä Jiraan saat käyttöösi muun muassa tikettien otsikot ja sen myötä uudistuneen tikettien hakutoiminnon.", + connectNotificationTitle: "Uutta: Jira-integraatio", + connectNotification1: + "Keijo voi lukea tikettien tietoja Jirasta kirjausten helpottamiseksi. Voit ottaa Jira-ominaisuudet käyttöön yhdistämällä Keijon Jiraan henkilökohtaisen Atlassian-tilisi kautta.", + connectNotification2: + "Voit myös sulkea tämän huomautuksen ja halutessasi yhdistää Jiraan myöhemmin asetusvalikon kautta.", infoDialog: { title: "Keijo-Jira", // Site could also be set dynamically from server or simply by .atlassian.net diff --git a/web/src/jira/components/JiraIntegrationAlert.tsx b/web/src/jira/components/JiraIntegrationAlert.tsx index b2505cee..813825d3 100644 --- a/web/src/jira/components/JiraIntegrationAlert.tsx +++ b/web/src/jira/components/JiraIntegrationAlert.tsx @@ -1,4 +1,4 @@ -import { Alert, Box, Button, useMediaQuery, useTheme } from "@mui/material"; +import { Alert, AlertTitle, Box, Button, useMediaQuery, useTheme } from "@mui/material"; import { t } from "i18next"; import { useState } from "react"; import { JiraInfoDialog } from "./JiraInfoDialog"; @@ -15,7 +15,9 @@ export const JiraIntegrationAlert = ({ onHide }: JiraIntegrationAlertProps) => { return ( <> - {t("jira.connectNotification")} + {t("jira.connectNotificationTitle")} + {t("jira.connectNotification1")} + {t("jira.connectNotification2")} - + From 836ded26eaec6f8d056c171c373a6b7ac3593adb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joonas=20H=C3=A4kkinen?= Date: Fri, 18 Oct 2024 15:53:40 +0300 Subject: [PATCH 14/14] Remove unused translation --- web/src/i18n/en.ts | 1 - web/src/i18n/fi.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/web/src/i18n/en.ts b/web/src/i18n/en.ts index c8c9a212..ac8f5115 100644 --- a/web/src/i18n/en.ts +++ b/web/src/i18n/en.ts @@ -24,7 +24,6 @@ const en = { jiraDisconnect: "Disconnect from Jira", showWeekend: "Show Weekend", hideWeekend: "Hide Weekend", - hide: "Hide", }, dimensionNames: { product: "Product", diff --git a/web/src/i18n/fi.ts b/web/src/i18n/fi.ts index a9d2c23b..f1f57158 100644 --- a/web/src/i18n/fi.ts +++ b/web/src/i18n/fi.ts @@ -24,7 +24,6 @@ const fi = { jiraDisconnect: "Katkaise Jira-yhteys", showWeekend: "Näytä Viikonloppu", hideWeekend: "Piilota Viikonloppu", - hide: "Piilota", }, dimensionNames: { product: "Tuote",