aboutsummaryrefslogtreecommitdiff
path: root/FrontEnd/src
diff options
context:
space:
mode:
Diffstat (limited to 'FrontEnd/src')
-rw-r--r--FrontEnd/src/App.tsx4
-rw-r--r--FrontEnd/src/views/center/TimelineBoard.tsx62
-rw-r--r--FrontEnd/src/views/center/TimelineCreateDialog.tsx8
-rw-r--r--FrontEnd/src/views/home/TimelineListView.tsx12
-rw-r--r--FrontEnd/src/views/search/index.tsx16
-rw-r--r--FrontEnd/src/views/timeline/Timeline.tsx2
-rw-r--r--FrontEnd/src/views/timeline/TimelineCard.tsx6
-rw-r--r--FrontEnd/src/views/timeline/TimelineDeleteDialog.tsx9
-rw-r--r--FrontEnd/src/views/timeline/TimelineMember.tsx12
-rw-r--r--FrontEnd/src/views/timeline/TimelinePostContentView.tsx11
-rw-r--r--FrontEnd/src/views/timeline/TimelinePostEdit.tsx7
-rw-r--r--FrontEnd/src/views/timeline/TimelinePostView.tsx2
-rw-r--r--FrontEnd/src/views/timeline/TimelinePropertyChangeDialog.tsx2
-rw-r--r--FrontEnd/src/views/timeline/index.tsx1
14 files changed, 89 insertions, 65 deletions
diff --git a/FrontEnd/src/App.tsx b/FrontEnd/src/App.tsx
index 5e61848a..ab7ebae9 100644
--- a/FrontEnd/src/App.tsx
+++ b/FrontEnd/src/App.tsx
@@ -34,10 +34,10 @@ function App(): ReactElement | null {
<Route path="/login" element={<Login />} />
<Route path="/settings" element={<Settings />} />
<Route path="/about" element={<About />} />
- <Route path="/:owner" element={<TimelinePage />} />
- <Route path="/:owner/:timeline" element={<TimelinePage />} />
<Route path="/search" element={<Search />} />
<Route path="/admin" element={<Admin />} />
+ <Route path="/:owner" element={<TimelinePage />} />
+ <Route path="/:owner/:timeline" element={<TimelinePage />} />
<Route element={<NoMatch />} />
</Routes>
<AlertHost />
diff --git a/FrontEnd/src/views/center/TimelineBoard.tsx b/FrontEnd/src/views/center/TimelineBoard.tsx
index 8c1f5fac..f8dc4bfd 100644
--- a/FrontEnd/src/views/center/TimelineBoard.tsx
+++ b/FrontEnd/src/views/center/TimelineBoard.tsx
@@ -5,7 +5,6 @@ import { Link } from "react-router-dom";
import { HttpTimelineInfo } from "@/http/timeline";
import TimelineLogo from "../common/TimelineLogo";
-import UserTimelineLogo from "../common/UserTimelineLogo";
import LoadFailReload from "../common/LoadFailReload";
import FlatButton from "../common/button/FlatButton";
import Card from "../common/Card";
@@ -34,21 +33,15 @@ const TimelineBoardItem: React.FC<TimelineBoardItemProps> = ({
offset,
actions,
}) => {
- const { name, title } = timeline;
- const isPersonal = name.startsWith("@");
- const url = isPersonal
- ? `/users/${timeline.owner.username}`
- : `/timelines/${name}`;
+ const { title } = timeline;
const content = (
<>
- {isPersonal ? (
- <UserTimelineLogo className="icon" />
- ) : (
- <TimelineLogo className="icon" />
- )}
+ <TimelineLogo className="icon" />
<span className="title">{title}</span>
- <small className="ms-2 cru-color-secondary">{name}</small>
+ <small className="ms-2 cru-color-secondary">
+ {timeline.owner.username}/{timeline.nameV2}
+ </small>
<span className="flex-grow-1"></span>
{actions != null ? (
<div className="right">
@@ -89,7 +82,10 @@ const TimelineBoardItem: React.FC<TimelineBoardItemProps> = ({
};
return actions == null ? (
- <Link to={url} className="timeline-board-item">
+ <Link
+ to={`${timeline.owner.username}/${timeline.nameV2}`}
+ className="timeline-board-item"
+ >
{content}
</Link>
) : (
@@ -103,8 +99,13 @@ interface TimelineBoardItemContainerProps {
timelines: HttpTimelineInfo[];
editHandler?: {
// offset may exceed index range plusing index.
- onMove: (timeline: string, index: number, offset: number) => void;
- onDelete: (timeline: string) => void;
+ onMove: (
+ owner: string,
+ timeline: string,
+ index: number,
+ offset: number
+ ) => void;
+ onDelete: (owner: string, timeline: string) => void;
};
}
@@ -155,7 +156,7 @@ const TimelineBoardItemContainer: React.FC<TimelineBoardItemContainerProps> = ({
return (
<TimelineBoardItem
- key={timeline.name}
+ key={`${timeline.owner.username}/${timeline.nameV2}`}
timeline={timeline}
offset={offset}
arbitraryOffset={arbitraryOffset}
@@ -163,7 +164,10 @@ const TimelineBoardItemContainer: React.FC<TimelineBoardItemContainerProps> = ({
editHandler != null
? {
onDelete: () => {
- editHandler.onDelete(timeline.name);
+ editHandler.onDelete(
+ timeline.owner.username,
+ timeline.nameV2
+ );
},
onMove: {
start: (e) => {
@@ -188,7 +192,8 @@ const TimelineBoardItemContainer: React.FC<TimelineBoardItemContainerProps> = ({
moveState.offset / height
);
editHandler.onMove(
- timeline.name,
+ timeline.owner.username,
+ timeline.nameV2,
moveState.index,
offsetCount
);
@@ -213,8 +218,13 @@ interface TimelineBoardUIProps {
onReload: () => void;
className?: string;
editHandler?: {
- onMove: (timeline: string, index: number, offset: number) => void;
- onDelete: (timeline: string) => void;
+ onMove: (
+ owner: string,
+ timeline: string,
+ index: number,
+ offset: number
+ ) => void;
+ onDelete: (owner: string, timeline: string) => void;
};
}
@@ -267,13 +277,13 @@ const TimelineBoardUI: React.FC<TimelineBoardUIProps> = (props) => {
editHandler && editing
? {
onDelete: editHandler.onDelete,
- onMove: (timeline, index, offset) => {
+ onMove: (owner, timeline, index, offset) => {
if (index + offset >= timelines.length) {
offset = timelines.length - index - 1;
} else if (index + offset < 0) {
offset = -index;
}
- editHandler.onMove(timeline, index, offset);
+ editHandler.onMove(owner, timeline, index, offset);
},
}
: undefined
@@ -339,7 +349,7 @@ const TimelineBoard: React.FC<TimelineBoardProps> = ({
editHandler={
typeof timelines === "object" && editHandler != null
? {
- onMove: (timeline, index, offset) => {
+ onMove: (owner, timeline, index, offset) => {
const newTimelines = timelines.slice();
const [t] = newTimelines.splice(index, 1);
newTimelines.splice(index + offset, 0, t);
@@ -348,10 +358,12 @@ const TimelineBoard: React.FC<TimelineBoardProps> = ({
setTimelines(timelines);
});
},
- onDelete: (timeline) => {
+ onDelete: (owner, timeline) => {
const newTimelines = timelines.slice();
newTimelines.splice(
- timelines.findIndex((t) => t.name === timeline),
+ timelines.findIndex(
+ (t) => t.owner.username === owner && t.nameV2 === timeline
+ ),
1
);
setTimelines(newTimelines);
diff --git a/FrontEnd/src/views/center/TimelineCreateDialog.tsx b/FrontEnd/src/views/center/TimelineCreateDialog.tsx
index d3b30575..2afc7221 100644
--- a/FrontEnd/src/views/center/TimelineCreateDialog.tsx
+++ b/FrontEnd/src/views/center/TimelineCreateDialog.tsx
@@ -2,9 +2,11 @@ import React from "react";
import { useNavigate } from "react-router-dom";
import { validateTimelineName } from "@/services/timeline";
-import OperationDialog from "../common/dailog/OperationDialog";
import { getHttpTimelineClient, HttpTimelineInfo } from "@/http/timeline";
+import OperationDialog from "../common/dailog/OperationDialog";
+import { useUserLoggedIn } from "@/services/user";
+
interface TimelineCreateDialogProps {
open: boolean;
close: () => void;
@@ -13,6 +15,8 @@ interface TimelineCreateDialogProps {
const TimelineCreateDialog: React.FC<TimelineCreateDialogProps> = (props) => {
const navigate = useNavigate();
+ const user = useUserLoggedIn();
+
return (
<OperationDialog
open={props.open}
@@ -43,7 +47,7 @@ const TimelineCreateDialog: React.FC<TimelineCreateDialogProps> = (props) => {
getHttpTimelineClient().postTimeline({ name })
}
onSuccessAndClose={(timeline: HttpTimelineInfo) => {
- navigate(`timelines/${timeline.name}`);
+ navigate(`${user.username}/${timeline.nameV2}`);
}}
failurePrompt={(e) => `${e as string}`}
/>
diff --git a/FrontEnd/src/views/home/TimelineListView.tsx b/FrontEnd/src/views/home/TimelineListView.tsx
index 95c3c367..2f283e1c 100644
--- a/FrontEnd/src/views/home/TimelineListView.tsx
+++ b/FrontEnd/src/views/home/TimelineListView.tsx
@@ -11,14 +11,6 @@ interface TimelineListItemProps {
}
const TimelineListItem: React.FC<TimelineListItemProps> = ({ timeline }) => {
- const url = React.useMemo(
- () =>
- timeline.name.startsWith("@")
- ? `/users/${timeline.owner.username}`
- : `/timelines/${timeline.name}`,
- [timeline]
- );
-
return (
<div className="home-timeline-list-item home-timeline-list-item-timeline">
<svg className="home-timeline-list-item-line" viewBox="0 0 120 100">
@@ -34,7 +26,7 @@ const TimelineListItem: React.FC<TimelineListItemProps> = ({ timeline }) => {
<small className="text-secondary">{timeline.description}</small>
</div>
</div>
- <Link to={url}>
+ <Link to={`${timeline.owner.username}/${timeline.nameV2}`}>
<i className="icon-button bi-arrow-right ms-3" />
</Link>
</div>
@@ -91,7 +83,7 @@ const TimelineListView: React.FC<TimelineListViewProps> = ({
<h3>{convertI18nText(headerText, t)}</h3>
</div>
{timelines != null
- ? timelines.map((t) => <TimelineListItem key={t.name} timeline={t} />)
+ ? timelines.map((t) => <TimelineListItem key={t.nameV2} timeline={t} />)
: null}
<TimelineListArrow />
</div>
diff --git a/FrontEnd/src/views/search/index.tsx b/FrontEnd/src/views/search/index.tsx
index 60eb6306..e1d3222d 100644
--- a/FrontEnd/src/views/search/index.tsx
+++ b/FrontEnd/src/views/search/index.tsx
@@ -15,16 +15,15 @@ import "./index.css";
const TimelineSearchResultItemView: React.FC<{
timeline: HttpTimelineInfo;
}> = ({ timeline }) => {
- const link = timeline.name.startsWith("@")
- ? `users/${timeline.owner.username}`
- : `timelines/${timeline.name}`;
-
return (
<div className="timeline-search-result-item my-2 p-3">
<h4>
- <Link to={link} className="mb-2 text-primary">
+ <Link
+ to={`${timeline.owner.username}/${timeline.nameV2}`}
+ className="mb-2 text-primary"
+ >
{timeline.title}
- <small className="ms-3 text-secondary">{timeline.name}</small>
+ <small className="ms-3 text-secondary">{timeline.nameV2}</small>
</Link>
</h4>
<div>
@@ -117,7 +116,10 @@ const SearchPage: React.FC = () => {
return <div>{t("searchPage.noResult")}</div>;
}
return state.map((t) => (
- <TimelineSearchResultItemView key={t.name} timeline={t} />
+ <TimelineSearchResultItemView
+ key={`${t.owner.username}/${t.nameV2}`}
+ timeline={t}
+ />
));
}
}
diff --git a/FrontEnd/src/views/timeline/Timeline.tsx b/FrontEnd/src/views/timeline/Timeline.tsx
index 4738c705..e8ed9fe5 100644
--- a/FrontEnd/src/views/timeline/Timeline.tsx
+++ b/FrontEnd/src/views/timeline/Timeline.tsx
@@ -114,7 +114,7 @@ const Timeline: React.FC<TimelineProps> = (props) => {
subscribe = false;
};
}
- }, [timelineName, reloadKey, onTimelineLoaded]);
+ }, [timelineOwner, timelineName, reloadKey, onTimelineLoaded]);
switch (state) {
case "loading":
diff --git a/FrontEnd/src/views/timeline/TimelineCard.tsx b/FrontEnd/src/views/timeline/TimelineCard.tsx
index 156c581e..dcf5e870 100644
--- a/FrontEnd/src/views/timeline/TimelineCard.tsx
+++ b/FrontEnd/src/views/timeline/TimelineCard.tsx
@@ -54,7 +54,7 @@ const TimelineCard: React.FC<TimelinePageCardProps> = (props) => {
<>
<h3 className="cru-color-primary d-inline-block align-middle">
{timeline.title}
- <small className="ms-3 cru-color-secondary">{timeline.name}</small>
+ <small className="ms-3 cru-color-secondary">{timeline.nameV2}</small>
</h3>
<div>
<UserAvatar
@@ -80,7 +80,7 @@ const TimelineCard: React.FC<TimelinePageCardProps> = (props) => {
user?.hasHighlightTimelineAdministrationPermission
? () => {
getHttpHighlightClient()
- [timeline.isHighlight ? "delete" : "put"](timeline.name)
+ [timeline.isHighlight ? "delete" : "put"](timeline.nameV2)
.then(onReload, () => {
pushAlert({
message: timeline.isHighlight
@@ -101,7 +101,7 @@ const TimelineCard: React.FC<TimelinePageCardProps> = (props) => {
)}
onClick={() => {
getHttpBookmarkClient()
- [timeline.isBookmark ? "delete" : "put"](timeline.name)
+ [timeline.isBookmark ? "delete" : "put"](timeline.nameV2)
.then(onReload, () => {
pushAlert({
message: timeline.isBookmark
diff --git a/FrontEnd/src/views/timeline/TimelineDeleteDialog.tsx b/FrontEnd/src/views/timeline/TimelineDeleteDialog.tsx
index 606584eb..1b7a2cc1 100644
--- a/FrontEnd/src/views/timeline/TimelineDeleteDialog.tsx
+++ b/FrontEnd/src/views/timeline/TimelineDeleteDialog.tsx
@@ -26,7 +26,7 @@ const TimelineDeleteDialog: React.FC<TimelineDeleteDialog> = (props) => {
inputPrompt={() => {
return (
<Trans i18nKey="timeline.deleteDialog.inputPrompt">
- 0<code className="mx-2">{{ name: timeline.name }}</code>2
+ 0<code className="mx-2">{{ name: timeline.nameV2 }}</code>2
</Trans>
);
}}
@@ -36,14 +36,17 @@ const TimelineDeleteDialog: React.FC<TimelineDeleteDialog> = (props) => {
},
]}
inputValidator={([value]) => {
- if (value !== timeline.name) {
+ if (value !== timeline.nameV2) {
return { 0: "timeline.deleteDialog.notMatch" };
} else {
return null;
}
}}
onProcess={() => {
- return getHttpTimelineClient().deleteTimeline(timeline.name);
+ return getHttpTimelineClient().deleteTimeline(
+ timeline.owner.username,
+ timeline.nameV2
+ );
}}
onSuccessAndClose={() => {
navigate("/", { replace: true });
diff --git a/FrontEnd/src/views/timeline/TimelineMember.tsx b/FrontEnd/src/views/timeline/TimelineMember.tsx
index 59d4c371..27355081 100644
--- a/FrontEnd/src/views/timeline/TimelineMember.tsx
+++ b/FrontEnd/src/views/timeline/TimelineMember.tsx
@@ -116,7 +116,11 @@ const TimelineMemberUserSearch: React.FC<{
add
onAction={() => {
void getHttpTimelineClient()
- .memberPut(timeline.name, user.username)
+ .memberPut(
+ timeline.owner.username,
+ timeline.nameV2,
+ user.username
+ )
.then(() => {
setUserSearchText("");
setUserSearchState({ type: "init" });
@@ -160,7 +164,11 @@ const TimelineMember: React.FC<TimelineMemberProps> = (props) => {
timeline.manageable && index !== 0
? () => {
void getHttpTimelineClient()
- .memberDelete(timeline.name, member.username)
+ .memberDelete(
+ timeline.owner.username,
+ timeline.nameV2,
+ member.username
+ )
.then(onChange);
}
: undefined
diff --git a/FrontEnd/src/views/timeline/TimelinePostContentView.tsx b/FrontEnd/src/views/timeline/TimelinePostContentView.tsx
index 607b72c9..88cd756a 100644
--- a/FrontEnd/src/views/timeline/TimelinePostContentView.tsx
+++ b/FrontEnd/src/views/timeline/TimelinePostContentView.tsx
@@ -27,7 +27,7 @@ const TextView: React.FC<TimelinePostContentViewProps> = (props) => {
setError(null);
void getHttpTimelineClient()
- .getPostDataAsString(post.timelineName, post.id)
+ .getPostDataAsString(post.timelineOwnerV2, post.timelineNameV2, post.id)
.then(
(data) => {
if (subscribe) setText(data);
@@ -46,7 +46,7 @@ const TextView: React.FC<TimelinePostContentViewProps> = (props) => {
return () => {
subscribe = false;
};
- }, [post.timelineName, post.id, reloadKey]);
+ }, [post.timelineOwnerV2, post.timelineNameV2, post.id, reloadKey]);
if (error != null) {
return (
@@ -75,7 +75,8 @@ const ImageView: React.FC<TimelinePostContentViewProps> = (props) => {
return (
<img
src={getHttpTimelineClient().generatePostDataUrl(
- post.timelineName,
+ post.timelineOwnerV2,
+ post.timelineNameV2,
post.id
)}
className={classnames(className, "timeline-content-image")}
@@ -110,7 +111,7 @@ const MarkdownView: React.FC<TimelinePostContentViewProps> = (props) => {
setError(null);
void getHttpTimelineClient()
- .getPostDataAsString(post.timelineName, post.id)
+ .getPostDataAsString(post.timelineOwnerV2, post.timelineNameV2, post.id)
.then(
(data) => {
if (subscribe) setMarkdown(data);
@@ -129,7 +130,7 @@ const MarkdownView: React.FC<TimelinePostContentViewProps> = (props) => {
return () => {
subscribe = false;
};
- }, [post.timelineName, post.id, reloadKey]);
+ }, [post.timelineOwnerV2, post.timelineNameV2, post.id, reloadKey]);
const markdownHtml = React.useMemo<string | null>(() => {
if (markdown == null) return null;
diff --git a/FrontEnd/src/views/timeline/TimelinePostEdit.tsx b/FrontEnd/src/views/timeline/TimelinePostEdit.tsx
index cd61b4a7..cca73a12 100644
--- a/FrontEnd/src/views/timeline/TimelinePostEdit.tsx
+++ b/FrontEnd/src/views/timeline/TimelinePostEdit.tsx
@@ -129,7 +129,7 @@ const TimelinePostEdit: React.FC<TimelinePostEditProps> = (props) => {
const [text, setText] = React.useState<string>("");
const [image, setImage] = React.useState<File | null>(null);
- const draftTextLocalStorageKey = `timeline.${timeline.name}.postDraft.text`;
+ const draftTextLocalStorageKey = `timeline.${timeline.owner.username}.${timeline.nameV2}.postDraft.text`;
React.useEffect(() => {
setText(window.localStorage.getItem(draftTextLocalStorageKey) ?? "");
@@ -173,7 +173,7 @@ const TimelinePostEdit: React.FC<TimelinePostEditProps> = (props) => {
}
getHttpTimelineClient()
- .postPost(timeline.name, {
+ .postPost(timeline.owner.username, timeline.nameV2, {
dataList: [requestData],
})
.then(
@@ -199,7 +199,8 @@ const TimelinePostEdit: React.FC<TimelinePostEditProps> = (props) => {
<MarkdownPostEdit
className="cru-fill-parent"
onClose={() => setShowMarkdown(false)}
- timeline={timeline.name}
+ owner={timeline.owner.username}
+ timeline={timeline.nameV2}
onPosted={onPosted}
onPostError={onPostError}
/>
diff --git a/FrontEnd/src/views/timeline/TimelinePostView.tsx b/FrontEnd/src/views/timeline/TimelinePostView.tsx
index 086176f8..40c6a484 100644
--- a/FrontEnd/src/views/timeline/TimelinePostView.tsx
+++ b/FrontEnd/src/views/timeline/TimelinePostView.tsx
@@ -134,7 +134,7 @@ const TimelinePostView: React.FC<TimelinePostViewProps> = (props) => {
}}
onConfirm={() => {
void getHttpTimelineClient()
- .deletePost(post.timelineName, post.id)
+ .deletePost(post.timelineOwnerV2, post.timelineNameV2, post.id)
.then(onDeleted, () => {
pushAlert({
type: "danger",
diff --git a/FrontEnd/src/views/timeline/TimelinePropertyChangeDialog.tsx b/FrontEnd/src/views/timeline/TimelinePropertyChangeDialog.tsx
index cd5c46da..18f557c6 100644
--- a/FrontEnd/src/views/timeline/TimelinePropertyChangeDialog.tsx
+++ b/FrontEnd/src/views/timeline/TimelinePropertyChangeDialog.tsx
@@ -78,7 +78,7 @@ const TimelinePropertyChangeDialog: React.FC<
req.color = nc;
}
return getHttpTimelineClient()
- .patchTimeline(timeline.name, req)
+ .patchTimeline(timeline.owner.username, timeline.nameV2, req)
.then(onChange);
}}
/>
diff --git a/FrontEnd/src/views/timeline/index.tsx b/FrontEnd/src/views/timeline/index.tsx
index 4faf8af8..3bd3ae3c 100644
--- a/FrontEnd/src/views/timeline/index.tsx
+++ b/FrontEnd/src/views/timeline/index.tsx
@@ -71,6 +71,7 @@ const TimelinePage: React.FC = () => {
) : null}
<div className="container">
<Timeline
+ timelineOwner={ownerUsername}
timelineName={timelineName}
reloadKey={reloadKey}
onReload={reload}