diff --git a/frontend/src/Components/MiddleTruncate.tsx b/frontend/src/Components/MiddleTruncate.tsx
new file mode 100644
index 0000000000..f635b0bc9c
--- /dev/null
+++ b/frontend/src/Components/MiddleTruncate.tsx
@@ -0,0 +1,63 @@
+import React, { useEffect, useRef, useState } from 'react';
+import useMeasure from 'Helpers/Hooks/useMeasure';
+
+interface MiddleTruncateProps {
+ text: string;
+}
+
+function getTruncatedText(text: string, length: number) {
+ return `${text.slice(0, length)}...${text.slice(text.length - length)}`;
+}
+
+function MiddleTruncate({ text }: MiddleTruncateProps) {
+ const [containerRef, { width: containerWidth }] = useMeasure();
+ const [textRef, { width: textWidth }] = useMeasure();
+ const [truncatedText, setTruncatedText] = useState(text);
+ const truncatedTextRef = useRef(text);
+
+ useEffect(() => {
+ setTruncatedText(text);
+ }, [text]);
+
+ useEffect(() => {
+ if (!containerWidth || !textWidth) {
+ return;
+ }
+
+ if (textWidth <= containerWidth) {
+ return;
+ }
+
+ const characterLength = textWidth / text.length;
+ const charactersToRemove =
+ Math.ceil(text.length - containerWidth / characterLength) + 3;
+ let length = Math.ceil(text.length / 2 - charactersToRemove / 2);
+
+ let updatedText = getTruncatedText(text, length);
+
+ // Make sure if the text is still too long, we keep reducing the length
+ // each time we re-run this.
+ while (
+ updatedText.length >= truncatedTextRef.current.length &&
+ length > 10
+ ) {
+ length--;
+ updatedText = getTruncatedText(text, length);
+ }
+
+ // Store the value in the ref so we can compare it in the next render,
+ // without triggering this effect every time we change the text.
+ truncatedTextRef.current = updatedText;
+ setTruncatedText(updatedText);
+ }, [text, truncatedTextRef, containerWidth, textWidth]);
+
+ return (
+
+ );
+}
+
+export default MiddleTruncate;
diff --git a/frontend/src/Settings/Profiles/Release/ReleaseProfileRow.css b/frontend/src/Settings/Profiles/Release/ReleaseProfileItem.css
similarity index 100%
rename from frontend/src/Settings/Profiles/Release/ReleaseProfileRow.css
rename to frontend/src/Settings/Profiles/Release/ReleaseProfileItem.css
diff --git a/frontend/src/Settings/Profiles/Release/ReleaseProfileRow.css.d.ts b/frontend/src/Settings/Profiles/Release/ReleaseProfileItem.css.d.ts
similarity index 100%
rename from frontend/src/Settings/Profiles/Release/ReleaseProfileRow.css.d.ts
rename to frontend/src/Settings/Profiles/Release/ReleaseProfileItem.css.d.ts
diff --git a/frontend/src/Settings/Profiles/Release/ReleaseProfileRow.tsx b/frontend/src/Settings/Profiles/Release/ReleaseProfileItem.tsx
similarity index 91%
rename from frontend/src/Settings/Profiles/Release/ReleaseProfileRow.tsx
rename to frontend/src/Settings/Profiles/Release/ReleaseProfileItem.tsx
index c2ad9f4b8f..58a7bd13fa 100644
--- a/frontend/src/Settings/Profiles/Release/ReleaseProfileRow.tsx
+++ b/frontend/src/Settings/Profiles/Release/ReleaseProfileItem.tsx
@@ -3,6 +3,7 @@ import { useDispatch } from 'react-redux';
import { Tag } from 'App/State/TagsAppState';
import Card from 'Components/Card';
import Label from 'Components/Label';
+import MiddleTruncate from 'Components/MiddleTruncate';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import TagList from 'Components/TagList';
import useModalOpenState from 'Helpers/Hooks/useModalOpenState';
@@ -12,14 +13,14 @@ import Indexer from 'typings/Indexer';
import ReleaseProfile from 'typings/Settings/ReleaseProfile';
import translate from 'Utilities/String/translate';
import EditReleaseProfileModal from './EditReleaseProfileModal';
-import styles from './ReleaseProfileRow.css';
+import styles from './ReleaseProfileItem.css';
interface ReleaseProfileProps extends ReleaseProfile {
tagList: Tag[];
indexerList: Indexer[];
}
-function ReleaseProfileRow(props: ReleaseProfileProps) {
+function ReleaseProfileItem(props: ReleaseProfileProps) {
const {
id,
name,
@@ -69,7 +70,7 @@ function ReleaseProfileRow(props: ReleaseProfileProps) {
return (
);
})}
@@ -83,7 +84,7 @@ function ReleaseProfileRow(props: ReleaseProfileProps) {
return (
);
})}
@@ -127,4 +128,4 @@ function ReleaseProfileRow(props: ReleaseProfileProps) {
);
}
-export default ReleaseProfileRow;
+export default ReleaseProfileItem;
diff --git a/frontend/src/Settings/Profiles/Release/ReleaseProfiles.css b/frontend/src/Settings/Profiles/Release/ReleaseProfiles.css
index 43f17b9dc7..c8ec63e78f 100644
--- a/frontend/src/Settings/Profiles/Release/ReleaseProfiles.css
+++ b/frontend/src/Settings/Profiles/Release/ReleaseProfiles.css
@@ -4,7 +4,7 @@
}
.addReleaseProfile {
- composes: releaseProfile from '~./ReleaseProfileRow.css';
+ composes: releaseProfile from '~./ReleaseProfileItem.css';
background-color: var(--cardAlternateBackgroundColor);
color: var(--gray);
diff --git a/frontend/src/Settings/Profiles/Release/ReleaseProfiles.tsx b/frontend/src/Settings/Profiles/Release/ReleaseProfiles.tsx
index bf0b47a586..c0a34a46ce 100644
--- a/frontend/src/Settings/Profiles/Release/ReleaseProfiles.tsx
+++ b/frontend/src/Settings/Profiles/Release/ReleaseProfiles.tsx
@@ -8,13 +8,13 @@ import Icon from 'Components/Icon';
import PageSectionContent from 'Components/Page/PageSectionContent';
import useModalOpenState from 'Helpers/Hooks/useModalOpenState';
import { icons } from 'Helpers/Props';
-import ReleaseProfileRow from 'Settings/Profiles/Release/ReleaseProfileRow';
import { fetchIndexers } from 'Store/Actions/Settings/indexers';
import { fetchReleaseProfiles } from 'Store/Actions/Settings/releaseProfiles';
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
import createTagsSelector from 'Store/Selectors/createTagsSelector';
import translate from 'Utilities/String/translate';
import EditReleaseProfileModal from './EditReleaseProfileModal';
+import ReleaseProfileItem from './ReleaseProfileItem';
import styles from './ReleaseProfiles.css';
function ReleaseProfiles() {
@@ -59,7 +59,7 @@ function ReleaseProfiles() {
{items.map((item) => {
return (
-