From 551e086de035ad5520075964218e6a07f7b00179 Mon Sep 17 00:00:00 2001 From: "D. Ror" Date: Thu, 11 Apr 2024 13:05:04 -0400 Subject: [PATCH 1/3] [WordCard] Prevent vern and button/icon overlap (#2963) --- src/components/WordCard/index.tsx | 65 +++++++++++++++++-------------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/src/components/WordCard/index.tsx b/src/components/WordCard/index.tsx index 99d39e3f5b..b23dfd3daf 100644 --- a/src/components/WordCard/index.tsx +++ b/src/components/WordCard/index.tsx @@ -3,6 +3,7 @@ import { Badge, Card, CardContent, + CardHeader, IconButton, Typography, } from "@mui/material"; @@ -42,39 +43,45 @@ export default function WordCard(props: WordCardProps): ReactElement { } }, [editedBy, provenance]); + /* Vernacular */ + const title = ( + + {word.vernacular} + + ); + + /* Icons/buttons beside vernacular */ + const action = ( + <> + {/* Condensed audio, note, flag */} + {!full && ( + <> + + {!!note.text && } + {flag.active && } + + )} + {/* Button for expand/condense */} + t.palette.grey[900] }} /> + ) : ( + t.palette.grey[600] }} /> + ) + } + onClick={() => setFull(!full)} + /> + + ); + return ( t.palette.grey[300], minWidth: "200px" }} > - - {/* Vernacular */} - - {word.vernacular} - - -
- {/* Condensed audio, note, flag */} - {!full && ( - <> - - {!!note.text && } - {flag.active && } - - )} - {/* Button for expand/condense */} - t.palette.grey[900] }} /> - ) : ( - t.palette.grey[600] }} /> - ) - } - onClick={() => setFull(!full)} - /> -
- + + {/* Expanded audio, note, flag */} {full && ( <> From 82f73c4412ce21bd0645a500b47293614f101e4a Mon Sep 17 00:00:00 2001 From: Jim Grady Date: Thu, 11 Apr 2024 20:58:32 -0400 Subject: [PATCH 2/3] Edits to README for standalone installer (#3055) --- installer/README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/installer/README.md b/installer/README.md index 06ab5c9cf9..8096138605 100644 --- a/installer/README.md +++ b/installer/README.md @@ -130,11 +130,12 @@ web browsers used to enter and cleanup the data. Having a secure connection prev to override their security settings. _The Combine_ refreshes its certificate when it is connected to the Internet via a wired Ethernet connection. A -certificate will be valid for a time between 60 and 90 days. You can use `combinectl` to view when your current -certificate will expire, for example: +certificate will be valid for a time between 60 and 90 days. You can use the command `combinectl cert` to view when your +current certificate will expire, for example: ```console - +$combinectl cert +Web certificate expires at Jul 8 08:54:11 2024 GMT ``` ## Advanced Installation Options @@ -155,6 +156,6 @@ To run `combine-installer.run` with options, the option list must be started wit | Command | Effect | | ------------------------------------------ | ------------------------------------------------------------ | -| `./combine-installer.run -- v1.16.0` | Install version `v1.16.0` of _The Combine_. | -| `./combine-installer.run -- update v2.1.0` | Update an existing Combine installation to version `v2.1.0` | +| `./combine-installer.run -- v1.1.6` | Install version `v1.1.6` of _The Combine_. | +| `./combine-installer.run -- update v1.2.1` | Update an existing Combine installation to version `v1.2.1` | | `./combine-installer.run -- restart` | Restart the current installation process from the beginning. | From dea7e6c1aa28208ef4b18b496b5d457ebd4e584a Mon Sep 17 00:00:00 2001 From: "D. Ror" Date: Mon, 15 Apr 2024 13:24:31 -0400 Subject: [PATCH 3/3] [MergeDups] Show (read-only) note on entries with a note (#2960) --- .../EntryNote.tsx => Buttons/NoteButton.tsx} | 6 +++--- src/components/Buttons/index.ts | 2 ++ .../tests/NoteButton.test.tsx} | 14 +++++++------- .../DataEntryTable/EntryCellComponents/index.ts | 1 - .../DataEntry/DataEntryTable/NewEntry/index.tsx | 4 ++-- .../DataEntry/DataEntryTable/RecentEntry.tsx | 4 ++-- .../DataEntryTable/tests/RecentEntry.test.tsx | 8 ++++---- src/components/Dialogs/CancelConfirmDialog.tsx | 2 +- src/components/WordCard/index.tsx | 11 +++++++---- .../CharInv/CharacterDetail/FindAndReplace.tsx | 2 +- .../CharInv/CharacterDetail/tests/index.test.tsx | 2 +- src/goals/CharacterInventory/CharInvCompleted.tsx | 2 +- .../MergeDupsStep/MergeDragDrop/DropWord.tsx | 7 ++++++- src/goals/MergeDuplicates/MergeDupsTreeTypes.ts | 15 ++++++++++++--- .../ReviewEntriesTable/Cells/FlagCell.tsx | 2 +- 15 files changed, 50 insertions(+), 32 deletions(-) rename src/components/{DataEntry/DataEntryTable/EntryCellComponents/EntryNote.tsx => Buttons/NoteButton.tsx} (88%) rename src/components/{DataEntry/DataEntryTable/EntryCellComponents/tests/EntryNote.test.tsx => Buttons/tests/NoteButton.test.tsx} (69%) diff --git a/src/components/DataEntry/DataEntryTable/EntryCellComponents/EntryNote.tsx b/src/components/Buttons/NoteButton.tsx similarity index 88% rename from src/components/DataEntry/DataEntryTable/EntryCellComponents/EntryNote.tsx rename to src/components/Buttons/NoteButton.tsx index f8486d3de3..8492e48f77 100644 --- a/src/components/DataEntry/DataEntryTable/EntryCellComponents/EntryNote.tsx +++ b/src/components/Buttons/NoteButton.tsx @@ -1,10 +1,10 @@ import { AddComment, Comment } from "@mui/icons-material"; import { type ReactElement, useState } from "react"; -import { IconButtonWithTooltip } from "components/Buttons"; +import IconButtonWithTooltip from "components/Buttons/IconButtonWithTooltip"; import { EditTextDialog } from "components/Dialogs"; -interface EntryNoteProps { +interface NoteButtonProps { buttonId?: string; disabled?: boolean; noteText: string; @@ -12,7 +12,7 @@ interface EntryNoteProps { } /** A note adding/editing/viewing button */ -export default function EntryNote(props: EntryNoteProps): ReactElement { +export default function NoteButton(props: NoteButtonProps): ReactElement { const [noteOpen, setNoteOpen] = useState(false); return ( diff --git a/src/components/Buttons/index.ts b/src/components/Buttons/index.ts index 4f50683ce9..d808ac4278 100644 --- a/src/components/Buttons/index.ts +++ b/src/components/Buttons/index.ts @@ -5,6 +5,7 @@ import FlagButton from "components/Buttons/FlagButton"; import IconButtonWithTooltip from "components/Buttons/IconButtonWithTooltip"; import LoadingButton from "components/Buttons/LoadingButton"; import LoadingDoneButton from "components/Buttons/LoadingDoneButton"; +import NoteButton from "components/Buttons/NoteButton"; import PartOfSpeechButton from "components/Buttons/PartOfSpeechButton"; import UndoButton from "components/Buttons/UndoButton"; @@ -16,6 +17,7 @@ export { IconButtonWithTooltip, LoadingButton, LoadingDoneButton, + NoteButton, PartOfSpeechButton, UndoButton, }; diff --git a/src/components/DataEntry/DataEntryTable/EntryCellComponents/tests/EntryNote.test.tsx b/src/components/Buttons/tests/NoteButton.test.tsx similarity index 69% rename from src/components/DataEntry/DataEntryTable/EntryCellComponents/tests/EntryNote.test.tsx rename to src/components/Buttons/tests/NoteButton.test.tsx index cf68712390..fc27f4b932 100644 --- a/src/components/DataEntry/DataEntryTable/EntryCellComponents/tests/EntryNote.test.tsx +++ b/src/components/Buttons/tests/NoteButton.test.tsx @@ -1,12 +1,12 @@ import { AddComment, Comment } from "@mui/icons-material"; import { - ReactTestInstance, - ReactTestRenderer, + type ReactTestInstance, + type ReactTestRenderer, act, create, } from "react-test-renderer"; -import EntryNote from "components/DataEntry/DataEntryTable/EntryCellComponents/EntryNote"; +import NoteButton from "components/Buttons/NoteButton"; const mockText = "Test text"; @@ -16,20 +16,20 @@ let testHandle: ReactTestInstance; async function renderWithText(text: string): Promise { await act(async () => { testMaster = create( - + ); }); testHandle = testMaster.root; } -describe("DeleteEntry", () => { - it("renders without note", async () => { +describe("NoteButton", () => { + it("renders without text", async () => { await renderWithText(""); expect(testHandle.findAllByType(AddComment).length).toBe(1); expect(testHandle.findAllByType(Comment).length).toBe(0); }); - it("renders with note", async () => { + it("renders with text", async () => { await renderWithText(mockText); expect(testHandle.findAllByType(AddComment).length).toBe(0); expect(testHandle.findAllByType(Comment).length).toBe(1); diff --git a/src/components/DataEntry/DataEntryTable/EntryCellComponents/index.ts b/src/components/DataEntry/DataEntryTable/EntryCellComponents/index.ts index 696118ff17..a1df342d01 100644 --- a/src/components/DataEntry/DataEntryTable/EntryCellComponents/index.ts +++ b/src/components/DataEntry/DataEntryTable/EntryCellComponents/index.ts @@ -1,4 +1,3 @@ export { default as DeleteEntry } from "components/DataEntry/DataEntryTable/EntryCellComponents/DeleteEntry"; -export { default as EntryNote } from "components/DataEntry/DataEntryTable/EntryCellComponents/EntryNote"; export { default as GlossWithSuggestions } from "components/DataEntry/DataEntryTable/EntryCellComponents/GlossWithSuggestions"; export { default as VernWithSuggestions } from "components/DataEntry/DataEntryTable/EntryCellComponents/VernWithSuggestions"; diff --git a/src/components/DataEntry/DataEntryTable/NewEntry/index.tsx b/src/components/DataEntry/DataEntryTable/NewEntry/index.tsx index 08478b014c..03035fb334 100644 --- a/src/components/DataEntry/DataEntryTable/NewEntry/index.tsx +++ b/src/components/DataEntry/DataEntryTable/NewEntry/index.tsx @@ -12,10 +12,10 @@ import { useTranslation } from "react-i18next"; import { useSelector } from "react-redux"; import { Pronunciation, Word, WritingSystem } from "api/models"; +import { NoteButton } from "components/Buttons"; import { focusInput } from "components/DataEntry/DataEntryTable"; import { DeleteEntry, - EntryNote, GlossWithSuggestions, VernWithSuggestions, } from "components/DataEntry/DataEntryTable/EntryCellComponents"; @@ -301,7 +301,7 @@ export default function NewEntry(props: NewEntryProps): ReactElement { {!selectedDup?.id && ( // note is not available if user selected to modify an exiting entry - - { it("disables buttons if changing", async () => { await renderWithWord(mockWord); const vern = testHandle.findByType(VernWithSuggestions); - const note = testHandle.findByType(EntryNote); + const note = testHandle.findByType(NoteButton); const audio = testHandle.findByType(PronunciationsBackend); const del = testHandle.findByType(DeleteEntry); @@ -140,7 +140,7 @@ describe("ExistingEntry", () => { it("disables buttons if changing", async () => { await renderWithWord(mockWord); const gloss = testHandle.findByType(GlossWithSuggestions); - const note = testHandle.findByType(EntryNote); + const note = testHandle.findByType(NoteButton); const audio = testHandle.findByType(PronunciationsBackend); const del = testHandle.findByType(DeleteEntry); @@ -185,7 +185,7 @@ describe("ExistingEntry", () => { describe("note", () => { it("updates text", async () => { await renderWithWord(mockWord); - testHandle = testHandle.findByType(EntryNote).findByType(EditTextDialog); + testHandle = testHandle.findByType(NoteButton).findByType(EditTextDialog); await act(async () => { testHandle.props.updateText(mockText); }); diff --git a/src/components/Dialogs/CancelConfirmDialog.tsx b/src/components/Dialogs/CancelConfirmDialog.tsx index 22d93aa9b2..a45585befa 100644 --- a/src/components/Dialogs/CancelConfirmDialog.tsx +++ b/src/components/Dialogs/CancelConfirmDialog.tsx @@ -9,7 +9,7 @@ import { import { type ReactElement, useState } from "react"; import { useTranslation } from "react-i18next"; -import LoadingButton from "components/Buttons/LoadingButton"; +import { LoadingButton } from "components/Buttons"; interface CancelConfirmDialogProps { open: boolean; diff --git a/src/components/WordCard/index.tsx b/src/components/WordCard/index.tsx index b23dfd3daf..f5249ea85a 100644 --- a/src/components/WordCard/index.tsx +++ b/src/components/WordCard/index.tsx @@ -12,8 +12,11 @@ import { useTranslation } from "react-i18next"; import { Word } from "api/models"; import { getUser } from "backend"; -import { FlagButton, IconButtonWithTooltip } from "components/Buttons"; -import { EntryNote } from "components/DataEntry/DataEntryTable/EntryCellComponents"; +import { + FlagButton, + IconButtonWithTooltip, + NoteButton, +} from "components/Buttons"; import { PronunciationsBackend } from "components/Pronunciations/PronunciationsBackend"; import SenseCard from "components/WordCard/SenseCard"; import SummarySenseCard from "components/WordCard/SummarySenseCard"; @@ -57,7 +60,7 @@ export default function WordCard(props: WordCardProps): ReactElement { {!full && ( <> - {!!note.text && } + {!!note.text && } {flag.active && } )} @@ -90,7 +93,7 @@ export default function WordCard(props: WordCardProps): ReactElement { )} {!!note.text && (
- + {note.text}
)} diff --git a/src/goals/CharacterInventory/CharInv/CharacterDetail/FindAndReplace.tsx b/src/goals/CharacterInventory/CharInv/CharacterDetail/FindAndReplace.tsx index bf1cc71b72..8371abb47c 100644 --- a/src/goals/CharacterInventory/CharInv/CharacterDetail/FindAndReplace.tsx +++ b/src/goals/CharacterInventory/CharInv/CharacterDetail/FindAndReplace.tsx @@ -3,7 +3,7 @@ import { type ReactElement, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { toast } from "react-toastify"; -import CancelConfirmDialog from "components/Dialogs/CancelConfirmDialog"; +import { CancelConfirmDialog } from "components/Dialogs"; import { findAndReplace } from "goals/CharacterInventory/Redux/CharacterInventoryActions"; import { useAppDispatch } from "types/hooks"; import { TextFieldWithFont } from "utilities/fontComponents"; diff --git a/src/goals/CharacterInventory/CharInv/CharacterDetail/tests/index.test.tsx b/src/goals/CharacterInventory/CharInv/CharacterDetail/tests/index.test.tsx index 0bdc68eb3e..ae2ec6da1f 100644 --- a/src/goals/CharacterInventory/CharInv/CharacterDetail/tests/index.test.tsx +++ b/src/goals/CharacterInventory/CharInv/CharacterDetail/tests/index.test.tsx @@ -2,7 +2,7 @@ import { Provider } from "react-redux"; import { type ReactTestRenderer, act, create } from "react-test-renderer"; import configureMockStore from "redux-mock-store"; -import CancelConfirmDialog from "components/Dialogs/CancelConfirmDialog"; +import { CancelConfirmDialog } from "components/Dialogs"; import CharacterDetail from "goals/CharacterInventory/CharInv/CharacterDetail"; import { buttonIdCancel, diff --git a/src/goals/CharacterInventory/CharInvCompleted.tsx b/src/goals/CharacterInventory/CharInvCompleted.tsx index aac80f322b..d41459e538 100644 --- a/src/goals/CharacterInventory/CharInvCompleted.tsx +++ b/src/goals/CharacterInventory/CharInvCompleted.tsx @@ -5,7 +5,7 @@ import { useTranslation } from "react-i18next"; import { type Word } from "api/models"; import { areInFrontier, getWord, revertWords } from "backend"; -import UndoButton from "components/Buttons/UndoButton"; +import { UndoButton } from "components/Buttons"; import WordCard from "components/WordCard"; import CharacterStatusText from "goals/CharacterInventory/CharInv/CharacterList/CharacterStatusText"; import { diff --git a/src/goals/MergeDuplicates/MergeDupsStep/MergeDragDrop/DropWord.tsx b/src/goals/MergeDuplicates/MergeDupsStep/MergeDragDrop/DropWord.tsx index eaf7341e21..ba67568825 100644 --- a/src/goals/MergeDuplicates/MergeDupsStep/MergeDragDrop/DropWord.tsx +++ b/src/goals/MergeDuplicates/MergeDupsStep/MergeDragDrop/DropWord.tsx @@ -12,7 +12,11 @@ import { Droppable } from "react-beautiful-dnd"; import { useTranslation } from "react-i18next"; import { Flag, ProtectReason, ReasonType } from "api/models"; -import { FlagButton, IconButtonWithTooltip } from "components/Buttons"; +import { + FlagButton, + IconButtonWithTooltip, + NoteButton, +} from "components/Buttons"; import MultilineTooltipTitle from "components/MultilineTooltipTitle"; import DragSense from "goals/MergeDuplicates/MergeDupsStep/MergeDragDrop/DragSense"; import { MergeTreeWord } from "goals/MergeDuplicates/MergeDupsTreeTypes"; @@ -227,6 +231,7 @@ export function DropWordCardHeader( text={} /> )} + {treeWord.note.text ? : null} ; vern: string; flag: Flag; + note: Note; protected: boolean; } @@ -54,6 +61,7 @@ export function newMergeTreeWord( vern, sensesGuids: sensesGuids ?? {}, flag: newFlag(), + note: newNote(), protected: false, }; } @@ -76,7 +84,8 @@ export function convertWordToMergeTreeWord(word: Word): MergeTreeWord { word.senses.forEach((sense) => { mergeTreeWord.sensesGuids[v4()] = [sense.guid]; }); - mergeTreeWord.flag = word.flag; + mergeTreeWord.flag = { ...word.flag }; + mergeTreeWord.note = { ...word.note }; mergeTreeWord.protected = word.accessibility === Status.Protected; return mergeTreeWord; } diff --git a/src/goals/ReviewEntries/ReviewEntriesTable/Cells/FlagCell.tsx b/src/goals/ReviewEntries/ReviewEntriesTable/Cells/FlagCell.tsx index 65873058ca..a4cb688bf7 100644 --- a/src/goals/ReviewEntries/ReviewEntriesTable/Cells/FlagCell.tsx +++ b/src/goals/ReviewEntries/ReviewEntriesTable/Cells/FlagCell.tsx @@ -1,6 +1,6 @@ import { type ReactElement } from "react"; -import FlagButton from "components/Buttons/FlagButton"; +import { FlagButton } from "components/Buttons"; import { type CellProps } from "goals/ReviewEntries/ReviewEntriesTable/Cells/CellTypes"; export default function FlagCell(props: CellProps): ReactElement {