chore: update store types

This commit is contained in:
boojack 2022-05-19 18:32:49 +08:00
parent bc22f69ac5
commit 6fe1db42b5
46 changed files with 353 additions and 318 deletions

View File

@ -38,7 +38,7 @@ const AboutSiteDialog: React.FC<Props> = ({ destroy }: Props) => {
</div>
<div className="dialog-content-container">
<p>
Memos is an open source, quickly self-hosted alternative to <a href="https://flomoapp.com">flomo</a>.
Memos is an <i>open source</i>, <i>self-hosted</i> knowledge base that works with local SQLite.
</p>
<br />
<p>

View File

@ -44,7 +44,7 @@ const ConfirmResetOpenIdDialog: React.FC<Props> = ({ destroy }: Props) => {
</div>
<div className="dialog-content-container">
<p className="warn-text">
The existing API will be invalidated and a new one will be generated, are you sure you want to reset?
The existing API will be invalidated and a new one will be generated, are you sure you want to reset?
</p>
<div className="btns-container">
<span className="btn cancel-btn" onClick={handleCloseBtnClick}>

View File

@ -4,20 +4,21 @@ import { formatMemoContent } from "./Memo";
import Only from "./common/OnlyWhen";
import "../less/daily-memo.less";
interface DailyMemo extends FormattedMemo {
interface DailyMemo extends Memo {
createdAtStr: string;
timeStr: string;
}
interface Props {
memo: Model.Memo;
memo: Memo;
}
const DailyMemo: React.FC<Props> = (props: Props) => {
const { memo: propsMemo } = props;
const memo: DailyMemo = {
...propsMemo,
createdAtStr: utils.getDateTimeString(propsMemo.createdAt),
timeStr: utils.getTimeString(propsMemo.createdAt),
createdAtStr: utils.getDateTimeString(propsMemo.createdTs),
timeStr: utils.getTimeString(propsMemo.createdTs),
};
const imageUrls = Array.from(memo.content.match(IMAGE_URL_REG) ?? []);

View File

@ -20,7 +20,7 @@ const weekdayChineseStrArray = ["周日", "周一", "周二", "周三", "周四"
const DailyMemoDiaryDialog: React.FC<Props> = (props: Props) => {
const loadingState = useLoading();
const [memos, setMemos] = useState<Model.Memo[]>([]);
const [memos, setMemos] = useState<Memo[]>([]);
const [currentDateStamp, setCurrentDateStamp] = useState(utils.getDateStampByDate(utils.getDateString(props.currentDateStamp)));
const [showDatePicker, toggleShowDatePicker] = useToggle(false);
const memosElRef = useRef<HTMLDivElement>(null);
@ -32,10 +32,10 @@ const DailyMemoDiaryDialog: React.FC<Props> = (props: Props) => {
.getState()
.memos.filter(
(a) =>
utils.getTimeStampByDate(a.createdAt) >= currentDateStamp &&
utils.getTimeStampByDate(a.createdAt) < currentDateStamp + DAILY_TIMESTAMP
utils.getTimeStampByDate(a.createdTs) >= currentDateStamp &&
utils.getTimeStampByDate(a.createdTs) < currentDateStamp + DAILY_TIMESTAMP
)
.sort((a, b) => utils.getTimeStampByDate(a.createdAt) - utils.getTimeStampByDate(b.createdAt));
.sort((a, b) => utils.getTimeStampByDate(a.createdTs) - utils.getTimeStampByDate(b.createdTs));
setMemos(dailyMemos);
loadingState.setFinish();
};
@ -115,7 +115,7 @@ const DailyMemoDiaryDialog: React.FC<Props> = (props: Props) => {
) : (
<div className="dailymemos-wrapper">
{memos.map((memo) => (
<DailyMemo key={`${memo.id}-${memo.updatedAt}`} memo={memo} />
<DailyMemo key={`${memo.id}-${memo.updatedTs}`} memo={memo} />
))}
</div>
)}

View File

@ -9,16 +9,16 @@ import { formatMemoContent } from "./Memo";
import "../less/memo.less";
interface Props {
memo: Model.Memo;
handleDeletedMemoAction: (memoId: string) => void;
memo: Memo;
handleDeletedMemoAction: (memoId: MemoId) => void;
}
const DeletedMemo: React.FC<Props> = (props: Props) => {
const { memo: propsMemo, handleDeletedMemoAction } = props;
const memo: FormattedMemo = {
const memo = {
...propsMemo,
createdAtStr: utils.getDateTimeString(propsMemo.createdAt),
deletedAtStr: utils.getDateTimeString(propsMemo.updatedAt ?? Date.now()),
createdAtStr: utils.getDateTimeString(propsMemo.createdTs),
deletedAtStr: utils.getDateTimeString(propsMemo.updatedTs ?? Date.now()),
};
const [showConfirmDeleteBtn, toggleConfirmDeleteBtn] = useToggle(false);
const imageUrls = Array.from(memo.content.match(IMAGE_URL_REG) ?? []);

View File

@ -1,6 +1,6 @@
import { memo } from "react";
import { escape } from "lodash-es";
import { IMAGE_URL_REG, LINK_REG, MEMO_LINK_REG, TAG_REG } from "../helpers/consts";
import { IMAGE_URL_REG, LINK_REG, MEMO_LINK_REG, TAG_REG, UNKNOWN_ID } from "../helpers/consts";
import { parseMarkedToHtml, parseRawTextToHtml } from "../helpers/marked";
import utils from "../helpers/utils";
import useToggle from "../hooks/useToggle";
@ -13,14 +13,14 @@ import toastHelper from "./Toast";
import "../less/memo.less";
interface Props {
memo: Model.Memo;
memo: Memo;
}
const Memo: React.FC<Props> = (props: Props) => {
const { memo: propsMemo } = props;
const memo: FormattedMemo = {
const memo = {
...propsMemo,
createdAtStr: utils.getDateTimeString(propsMemo.createdAt),
createdAtStr: utils.getDateTimeString(propsMemo.createdTs),
};
const [showConfirmDeleteBtn, toggleConfirmDeleteBtn] = useToggle(false);
const imageUrls = Array.from(memo.content.match(IMAGE_URL_REG) ?? []);
@ -31,17 +31,17 @@ const Memo: React.FC<Props> = (props: Props) => {
const handleTogglePinMemoBtnClick = async () => {
try {
if (memo.rowStatus === "ARCHIVED") {
if (memo.pinned) {
await memoService.unpinMemo(memo.id);
memoService.editMemo({
...memo,
rowStatus: "NORMAL",
pinned: false,
});
} else {
await memoService.pinMemo(memo.id);
memoService.editMemo({
...memo,
rowStatus: "ARCHIVED",
pinned: true,
});
}
} catch (error) {
@ -66,7 +66,7 @@ const Memo: React.FC<Props> = (props: Props) => {
}
if (globalStateService.getState().editMemoId === memo.id) {
globalStateService.setEditMemoId("");
globalStateService.setEditMemoId(UNKNOWN_ID);
}
} else {
toggleConfirmDeleteBtn();
@ -88,7 +88,7 @@ const Memo: React.FC<Props> = (props: Props) => {
if (targetEl.className === "memo-link-text") {
const memoId = targetEl.dataset?.value;
const memoTemp = memoService.getMemoById(memoId ?? "");
const memoTemp = memoService.getMemoById(Number(memoId) ?? UNKNOWN_ID);
if (memoTemp) {
showMemoCardDialog(memoTemp);
@ -102,11 +102,11 @@ const Memo: React.FC<Props> = (props: Props) => {
};
return (
<div className={`memo-wrapper ${"memos-" + memo.id} ${memo.rowStatus}`} onMouseLeave={handleMouseLeaveMemoWrapper}>
<div className={`memo-wrapper ${"memos-" + memo.id} ${memo.pinned ? "pinned" : ""}`} onMouseLeave={handleMouseLeaveMemoWrapper}>
<div className="memo-top-wrapper">
<span className="time-text" onClick={handleShowMemoStoryDialog}>
{memo.createdAtStr}
<Only when={memo.rowStatus === "ARCHIVED"}>
<Only when={memo.pinned}>
<span className="ml-2">PINNED</span>
</Only>
</span>
@ -120,7 +120,7 @@ const Memo: React.FC<Props> = (props: Props) => {
View Story
</span>
<span className="btn" onClick={handleTogglePinMemoBtnClick}>
{memo.rowStatus === "NORMAL" ? "Pin" : "Unpin"}
{memo.pinned ? "Unpin" : "Pin"}
</span>
<span className="btn" onClick={handleMarkMemoClick}>
Mark

View File

@ -1,5 +1,5 @@
import { useState, useEffect, useCallback } from "react";
import { IMAGE_URL_REG, MEMO_LINK_REG } from "../helpers/consts";
import { IMAGE_URL_REG, MEMO_LINK_REG, UNKNOWN_ID } from "../helpers/consts";
import utils from "../helpers/utils";
import { globalStateService, memoService } from "../services";
import { parseHtmlToRawText } from "../helpers/marked";
@ -11,18 +11,18 @@ import Image from "./Image";
import "../less/memo-card-dialog.less";
import "../less/memo-content.less";
interface LinkedMemo extends FormattedMemo {
interface LinkedMemo extends Memo {
createdAtStr: string;
dateStr: string;
}
interface Props extends DialogProps {
memo: Model.Memo;
memo: Memo;
}
const MemoCardDialog: React.FC<Props> = (props: Props) => {
const [memo, setMemo] = useState<FormattedMemo>({
const [memo, setMemo] = useState<Memo>({
...props.memo,
createdAtStr: utils.getDateTimeString(props.memo.createdAt),
});
const [linkMemos, setLinkMemos] = useState<LinkedMemo[]>([]);
const [linkedMemos, setLinkedMemos] = useState<LinkedMemo[]>([]);
@ -36,12 +36,12 @@ const MemoCardDialog: React.FC<Props> = (props: Props) => {
for (const matchRes of matchedArr) {
if (matchRes && matchRes.length === 3) {
const id = matchRes[2];
const memoTemp = memoService.getMemoById(id);
const memoTemp = memoService.getMemoById(Number(id));
if (memoTemp) {
linkMemos.push({
...memoTemp,
createdAtStr: utils.getDateTimeString(memoTemp.createdAt),
dateStr: utils.getDateString(memoTemp.createdAt),
createdAtStr: utils.getDateTimeString(memoTemp.createdTs),
dateStr: utils.getDateString(memoTemp.createdTs),
});
}
}
@ -51,11 +51,11 @@ const MemoCardDialog: React.FC<Props> = (props: Props) => {
const linkedMemos = await memoService.getLinkedMemos(memo.id);
setLinkedMemos(
linkedMemos
.sort((a, b) => utils.getTimeStampByDate(b.createdAt) - utils.getTimeStampByDate(a.createdAt))
.sort((a, b) => utils.getTimeStampByDate(b.createdTs) - utils.getTimeStampByDate(a.createdTs))
.map((m) => ({
...m,
createdAtStr: utils.getDateTimeString(m.createdAt),
dateStr: utils.getDateString(m.createdAt),
createdAtStr: utils.getDateTimeString(m.createdTs),
dateStr: utils.getDateString(m.createdTs),
}))
);
} catch (error) {
@ -71,12 +71,12 @@ const MemoCardDialog: React.FC<Props> = (props: Props) => {
if (targetEl.className === "memo-link-text") {
const nextMemoId = targetEl.dataset?.value;
const memoTemp = memoService.getMemoById(nextMemoId ?? "");
const memoTemp = memoService.getMemoById(Number(nextMemoId) ?? UNKNOWN_ID);
if (memoTemp) {
const nextMemo = {
...memoTemp,
createdAtStr: utils.getDateTimeString(memoTemp.createdAt),
createdAtStr: utils.getDateTimeString(memoTemp.createdTs),
};
setLinkMemos([]);
setLinkedMemos([]);
@ -88,7 +88,7 @@ const MemoCardDialog: React.FC<Props> = (props: Props) => {
}
}, []);
const handleLinkedMemoClick = useCallback((memo: FormattedMemo) => {
const handleLinkedMemoClick = useCallback((memo: Memo) => {
setLinkMemos([]);
setLinkedMemos([]);
setMemo(memo);
@ -103,7 +103,7 @@ const MemoCardDialog: React.FC<Props> = (props: Props) => {
<>
<div className="memo-card-container">
<div className="header-container">
<p className="time-text">{memo.createdAtStr}</p>
<p className="time-text">{utils.getDateTimeString(memo.createdTs)}</p>
<div className="btns-container">
<button className="btn edit-btn" onClick={handleEditMemoBtnClick}>
<img className="icon-img" src="/icons/edit.svg" />
@ -179,7 +179,7 @@ const MemoCardDialog: React.FC<Props> = (props: Props) => {
);
};
export default function showMemoCardDialog(memo: Model.Memo): void {
export default function showMemoCardDialog(memo: Memo): void {
showDialog(
{
className: "memo-card-dialog",

View File

@ -1,7 +1,7 @@
import React, { useCallback, useContext, useEffect, useMemo, useRef } from "react";
import appContext from "../stores/appContext";
import { globalStateService, locationService, memoService, resourceService } from "../services";
import utils from "../helpers/utils";
import { UNKNOWN_ID } from "../helpers/consts";
import { storage } from "../helpers/storage";
import useToggle from "../hooks/useToggle";
import toastHelper from "./Toast";
@ -53,14 +53,14 @@ const MemoEditor: React.FC<Props> = () => {
const tagSeletorRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (globalState.markMemoId) {
if (globalState.markMemoId !== UNKNOWN_ID) {
const editorCurrentValue = editorRef.current?.getContent();
const memoLinkText = `${editorCurrentValue ? "\n" : ""}Mark: [@MEMO](${globalState.markMemoId})`;
editorRef.current?.insertText(memoLinkText);
globalStateService.setMarkMemoId("");
globalStateService.setMarkMemoId(UNKNOWN_ID);
}
if (globalState.editMemoId && globalState.editMemoId !== prevGlobalStateRef.current.editMemoId) {
if (globalState.editMemoId !== UNKNOWN_ID && globalState.editMemoId !== prevGlobalStateRef.current.editMemoId) {
const editMemo = memoService.getMemoById(globalState.editMemoId);
if (editMemo) {
editorRef.current?.setContent(editMemo.content ?? "");
@ -147,15 +147,15 @@ const MemoEditor: React.FC<Props> = () => {
const { editMemoId } = globalStateService.getState();
try {
if (editMemoId) {
if (editMemoId !== UNKNOWN_ID) {
const prevMemo = memoService.getMemoById(editMemoId);
if (prevMemo && prevMemo.content !== content) {
const editedMemo = await memoService.updateMemo(prevMemo.id, content);
editedMemo.updatedAt = utils.getDateTimeString(Date.now());
editedMemo.createdTs = Date.now();
memoService.editMemo(editedMemo);
}
globalStateService.setEditMemoId("");
globalStateService.setEditMemoId(UNKNOWN_ID);
} else {
const newMemo = await memoService.createMemo(content);
memoService.pushMemo(newMemo);
@ -169,7 +169,7 @@ const MemoEditor: React.FC<Props> = () => {
}, []);
const handleCancelBtnClick = useCallback(() => {
globalStateService.setEditMemoId("");
globalStateService.setEditMemoId(UNKNOWN_ID);
editorRef.current?.setContent("");
setEditorContentCache("");
}, []);
@ -259,7 +259,7 @@ const MemoEditor: React.FC<Props> = () => {
}
}, []);
const isEditing = Boolean(globalState.editMemoId);
const isEditing = globalState.editMemoId !== UNKNOWN_ID;
const editorConfig = useMemo(
() => ({

View File

@ -53,7 +53,7 @@ const MemoList: React.FC<Props> = () => {
if (
duration &&
duration.from < duration.to &&
(utils.getTimeStampByDate(memo.createdAt) < duration.from || utils.getTimeStampByDate(memo.createdAt) > duration.to)
(utils.getTimeStampByDate(memo.createdTs) < duration.from || utils.getTimeStampByDate(memo.createdTs) > duration.to)
) {
shouldShow = false;
}
@ -76,8 +76,8 @@ const MemoList: React.FC<Props> = () => {
})
: memos;
const pinnedMemos = shownMemos.filter((m) => m.rowStatus === "ARCHIVED");
const unpinnedMemos = shownMemos.filter((m) => m.rowStatus === "NORMAL");
const pinnedMemos = shownMemos.filter((m) => m.pinned);
const unpinnedMemos = shownMemos.filter((m) => !m.pinned);
const sortedMemos = pinnedMemos.concat(unpinnedMemos);
useEffect(() => {
@ -112,7 +112,7 @@ const MemoList: React.FC<Props> = () => {
return (
<div className={`memo-list-container ${isFetching ? "" : "completed"}`} onClick={handleMemoListClick} ref={wrapperElement}>
{sortedMemos.map((memo) => (
<Memo key={`${memo.id}-${memo.updatedAt}`} memo={memo} />
<Memo key={`${memo.id}-${memo.updatedTs}`} memo={memo} />
))}
<div className="status-text-container">
<p className="status-text">

View File

@ -11,7 +11,7 @@ interface Props extends DialogProps {}
const MemoTrashDialog: React.FC<Props> = (props: Props) => {
const { destroy } = props;
const loadingState = useLoading();
const [deletedMemos, setDeletedMemos] = useState<Model.Memo[]>([]);
const [deletedMemos, setDeletedMemos] = useState<Memo[]>([]);
useEffect(() => {
memoService.fetchAllMemos();
@ -31,7 +31,7 @@ const MemoTrashDialog: React.FC<Props> = (props: Props) => {
locationService.clearQuery();
}, []);
const handleDeletedMemoAction = useCallback((memoId: string) => {
const handleDeletedMemoAction = useCallback((memoId: MemoId) => {
setDeletedMemos((deletedMemos) => deletedMemos.filter((memo) => memo.id !== memoId));
}, []);
@ -58,7 +58,7 @@ const MemoTrashDialog: React.FC<Props> = (props: Props) => {
) : (
<div className="deleted-memos-container">
{deletedMemos.map((memo) => (
<DeletedMemo key={`${memo.id}-${memo.updatedAt}`} memo={memo} handleDeletedMemoAction={handleDeletedMemoAction} />
<DeletedMemo key={`${memo.id}-${memo.updatedTs}`} memo={memo} handleDeletedMemoAction={handleDeletedMemoAction} />
))}
</div>
)}

View File

@ -16,7 +16,7 @@ const PreferencesSection: React.FC<Props> = () => {
createUserEmail: "",
createUserPassword: "",
});
const [userList, setUserList] = useState<Model.User[]>([]);
const [userList, setUserList] = useState<User[]>([]);
useEffect(() => {
fetchUserList();
@ -47,7 +47,7 @@ const PreferencesSection: React.FC<Props> = () => {
return;
}
const userCreate: API.UserCreate = {
const userCreate: UserCreate = {
email: state.createUserEmail,
password: state.createUserPassword,
role: "USER",
@ -83,10 +83,18 @@ const PreferencesSection: React.FC<Props> = () => {
</div>
</div>
<p className="title-text">Member list</p>
<div className="member-container field-container">
<span className="field-text">ID</span>
<span className="field-text">EMAIL</span>
</div>
{userList.map((user) => (
<div key={user.id} className="user-container">
<div key={user.id} className="member-container">
<span className="field-text id-text">{user.id}</span>
<span className="field-text">{user.email}</span>
<span className="field-text email-text">{user.email}</span>
{/* TODO */}
{/* <div className="buttons-container">
<span>delete</span>
</div> */}
</div>
))}
</div>

View File

@ -1,7 +1,6 @@
import { useContext, useState } from "react";
import appContext from "../../stores/appContext";
import { userService } from "../../services";
import utils from "../../helpers/utils";
import { validate, ValidatorConfig } from "../../helpers/validator";
import toastHelper from "../Toast";
import showChangePasswordDialog from "../ChangePasswordDialog";
@ -19,7 +18,7 @@ interface Props {}
const MyAccountSection: React.FC<Props> = () => {
const { userState } = useContext(appContext);
const user = userState.user as Model.User;
const user = userState.user as User;
const [username, setUsername] = useState<string>(user.name);
const openAPIRoute = `${window.location.origin}/h/${user.openId}/memo`;
@ -69,10 +68,6 @@ const MyAccountSection: React.FC<Props> = () => {
<span className="normal-text">Email:</span>
<span className="normal-text">{user.email}</span>
</label>
<label className="form-label">
<span className="normal-text">Created at:</span>
<span className="normal-text">{utils.getDateString(user.createdAt)}</span>
</label>
<label className="form-label input-form-label username-label">
<span className="normal-text">Username:</span>
<input type="text" value={username} onChange={handleUsernameChanged} />

View File

@ -10,7 +10,7 @@ const PreferencesSection: React.FC<Props> = () => {
const formatedMemos = memoService.getState().memos.map((m) => {
return {
content: m.content,
createdAt: m.createdAt,
createdTs: m.createdTs,
};
});
@ -33,7 +33,7 @@ const PreferencesSection: React.FC<Props> = () => {
const reader = new FileReader();
reader.readAsText(fileInputEl.files[0]);
reader.onload = async (event) => {
const memoList = JSON.parse(event.target?.result as string) as Model.Memo[];
const memoList = JSON.parse(event.target?.result as string) as Memo[];
if (!Array.isArray(memoList)) {
toastHelper.error("Unexpected data type.");
}
@ -42,7 +42,7 @@ const PreferencesSection: React.FC<Props> = () => {
for (const memo of memoList) {
const content = memo.content || "";
const createdAt = memo.createdAt || utils.getDateTimeString(Date.now());
const createdAt = utils.getDateTimeString(memo.createdTs || Date.now());
try {
await memoService.importMemo(content, createdAt);

View File

@ -10,15 +10,15 @@ import toastHelper from "./Toast";
import "../less/share-memo-image-dialog.less";
interface Props extends DialogProps {
memo: Model.Memo;
memo: Memo;
}
const ShareMemoImageDialog: React.FC<Props> = (props: Props) => {
const { memo: propsMemo, destroy } = props;
const { user: userinfo } = userService.getState();
const memo: FormattedMemo = {
const memo = {
...propsMemo,
createdAtStr: utils.getDateTimeString(propsMemo.createdAt),
createdAtStr: utils.getDateTimeString(propsMemo.createdTs),
};
const memoImgUrls = Array.from(memo.content.match(IMAGE_URL_REG) ?? []);
@ -106,7 +106,7 @@ const ShareMemoImageDialog: React.FC<Props> = (props: Props) => {
);
};
export default function showShareMemoImageDialog(memo: Model.Memo): void {
export default function showShareMemoImageDialog(memo: Memo): void {
showDialog(
{
className: "share-memo-image-dialog",

View File

@ -20,10 +20,10 @@ const ShortcutList: React.FC<Props> = () => {
const loadingState = useLoading();
const pinnedShortcuts = shortcuts
.filter((s) => s.rowStatus === "ARCHIVED")
.sort((a, b) => utils.getTimeStampByDate(b.createdAt) - utils.getTimeStampByDate(a.createdAt));
.sort((a, b) => utils.getTimeStampByDate(b.createdTs) - utils.getTimeStampByDate(a.createdTs));
const unpinnedShortcuts = shortcuts
.filter((s) => s.rowStatus === "NORMAL")
.sort((a, b) => utils.getTimeStampByDate(b.createdAt) - utils.getTimeStampByDate(a.createdAt));
.sort((a, b) => utils.getTimeStampByDate(b.createdTs) - utils.getTimeStampByDate(a.createdTs));
const sortedShortcuts = pinnedShortcuts.concat(unpinnedShortcuts);
useEffect(() => {
@ -55,7 +55,7 @@ const ShortcutList: React.FC<Props> = () => {
};
interface ShortcutContainerProps {
shortcut: Model.Shortcut;
shortcut: Shortcut;
isActive: boolean;
}

View File

@ -17,7 +17,7 @@ const Sidebar: React.FC<Props> = () => {
memoState: { memos, tags },
userState: { user },
} = useContext(appContext);
const createdDays = user ? Math.ceil((Date.now() - utils.getTimeStampByDate(user.createdAt)) / 1000 / 3600 / 24) : 0;
const createdDays = user ? Math.ceil((Date.now() - utils.getTimeStampByDate(user.createdTs)) / 1000 / 3600 / 24) : 0;
const handleMyAccountBtnClick = () => {
showSettingDialog();

View File

@ -77,7 +77,7 @@ const TagList: React.FC<Props> = () => {
))}
<Only when={tags.length < 5 && memoService.initialized}>
<p className="tag-tip-container">
Enter <span className="code-text">#Tag </span> to create a tag
Enter <span className="code-text">#tag </span> to create a tag
</p>
</Only>
</div>

View File

@ -1,5 +1,3 @@
import utils from "./utils";
type ResponseObject<T> = {
data: T;
error?: string;
@ -42,29 +40,14 @@ async function request<T>(config: RequestConfig): Promise<T> {
namespace api {
export function getSystemStatus() {
return request<API.SystemStatus>({
return request<SystemStatus>({
method: "GET",
url: "/api/status",
});
}
export function getUserList() {
return request<Model.User[]>({
method: "GET",
url: "/api/user",
});
}
export function createUser(userCreate: API.UserCreate) {
return request<Model.User[]>({
method: "POST",
url: "/api/user",
data: userCreate,
});
}
export function login(email: string, password: string) {
return request<Model.User>({
return request<User>({
method: "POST",
url: "/api/auth/login",
data: {
@ -75,7 +58,7 @@ namespace api {
}
export function signup(email: string, password: string, role: UserRole) {
return request<Model.User>({
return request<User>({
method: "POST",
url: "/api/auth/signup",
data: {
@ -94,70 +77,89 @@ namespace api {
});
}
export function getUserInfo() {
return request<Model.User>({
export function createUser(userCreate: UserCreate) {
return request<User[]>({
method: "POST",
url: "/api/user",
data: userCreate,
});
}
export function getUser() {
return request<User>({
method: "GET",
url: "/api/user/me",
});
}
export function updateUserinfo(userinfo: Partial<{ name: string; password: string; resetOpenId: boolean }>) {
return request<Model.User>({
method: "PATCH",
url: "/api/user/me",
data: userinfo,
export function getUserList() {
return request<User[]>({
method: "GET",
url: "/api/user",
});
}
export function resetOpenId() {
return request<string>({
method: "POST",
url: "/api/user/open_id/new",
export function patchUser(userPatch: UserPatch) {
return request<User>({
method: "PATCH",
url: "/api/user/me",
data: userPatch,
});
}
export function getMyMemos() {
return request<Model.Memo[]>({
return request<Memo[]>({
method: "GET",
url: "/api/memo",
});
}
export function getMyDeletedMemos() {
return request<Model.Memo[]>({
export function getMyArchivedMemos() {
return request<Memo[]>({
method: "GET",
url: "/api/memo?rowStatus=HIDDEN",
url: "/api/memo?rowStatus=ARCHIVED",
});
}
export function createMemo(content: string, createdAt?: string) {
const data: any = {
content,
};
if (createdAt) {
const createdTms = utils.getTimeStampByDate(createdAt);
data.createdTs = Math.floor(createdTms / 1000);
}
return request<Model.Memo>({
export function createMemo(memoCreate: MemoCreate) {
return request<Memo>({
method: "POST",
url: "/api/memo",
data: data,
data: memoCreate,
});
}
export function updateMemo(memoId: string, content: string) {
return request<Model.Memo>({
export function patchMemo(memoPatch: MemoPatch) {
return request<Memo>({
method: "PATCH",
url: `/api/memo/${memoId}`,
url: `/api/memo/${memoPatch.id}`,
data: {
content,
memoPatch,
},
});
}
export function pinMemo(memoId: string) {
export function pinMemo(memoId: MemoId) {
return request({
method: "POST",
url: `/api/memo/${memoId}/organizer`,
data: {
pinned: true,
},
});
}
export function unpinMemo(memoId: MemoId) {
return request({
method: "POST",
url: `/api/memo/${memoId}/organizer`,
data: {
pinned: false,
},
});
}
export function archiveMemo(memoId: MemoId) {
return request({
method: "PATCH",
url: `/api/memo/${memoId}`,
@ -167,27 +169,7 @@ namespace api {
});
}
export function unpinMemo(shortcutId: string) {
return request({
method: "PATCH",
url: `/api/memo/${shortcutId}`,
data: {
rowStatus: "NORMAL",
},
});
}
export function hideMemo(memoId: string) {
return request({
method: "PATCH",
url: `/api/memo/${memoId}`,
data: {
rowStatus: "HIDDEN",
},
});
}
export function restoreMemo(memoId: string) {
export function restoreMemo(memoId: MemoId) {
return request({
method: "PATCH",
url: `/api/memo/${memoId}`,
@ -197,7 +179,7 @@ namespace api {
});
}
export function deleteMemo(memoId: string) {
export function deleteMemo(memoId: MemoId) {
return request({
method: "DELETE",
url: `/api/memo/${memoId}`,
@ -205,14 +187,14 @@ namespace api {
}
export function getMyShortcuts() {
return request<Model.Shortcut[]>({
return request<Shortcut[]>({
method: "GET",
url: "/api/shortcut",
});
}
export function createShortcut(title: string, payload: string) {
return request<Model.Shortcut>({
return request<Shortcut>({
method: "POST",
url: "/api/shortcut",
data: {
@ -223,7 +205,7 @@ namespace api {
}
export function updateShortcut(shortcutId: string, title: string, payload: string) {
return request<Model.Shortcut>({
return request<Shortcut>({
method: "PATCH",
url: `/api/shortcut/${shortcutId}`,
data: {
@ -261,7 +243,7 @@ namespace api {
}
export function uploadFile(formData: FormData) {
return request<Model.Resource>({
return request<Resource>({
method: "POST",
url: "/api/resource",
data: formData,

View File

@ -1,3 +1,6 @@
// UNKNOWN_ID is the symbol for unknown id
export const UNKNOWN_ID = -1;
// default animation duration
export const ANIMATION_DURATION = 200;

View File

@ -90,7 +90,7 @@ export const getDefaultFilter = (): BaseFilter => {
};
};
export const checkShouldShowMemoWithFilters = (memo: Model.Memo, filters: Filter[]) => {
export const checkShouldShowMemoWithFilters = (memo: Memo, filters: Filter[]) => {
let shouldShow = true;
for (const f of filters) {
@ -106,7 +106,7 @@ export const checkShouldShowMemoWithFilters = (memo: Model.Memo, filters: Filter
return shouldShow;
};
export const checkShouldShowMemo = (memo: Model.Memo, filter: Filter) => {
export const checkShouldShowMemo = (memo: Memo, filter: Filter) => {
const {
type,
value: { operator, value },

View File

@ -83,8 +83,8 @@ namespace utils {
return Array.from(new Set(data));
}
export function dedupeObjectWithId<T extends { id: string }>(data: T[]): T[] {
const idSet = new Set<string>();
export function dedupeObjectWithId<T extends { id: string | number }>(data: T[]): T[] {
const idSet = new Set<string | number>();
const result = [];
for (const d of data) {

View File

@ -9,7 +9,7 @@
@apply border-gray-200;
}
&.ARCHIVED {
&.pinned {
@apply border-gray-200 border-2;
}

View File

@ -25,15 +25,29 @@
}
}
> .user-container {
@apply w-full mb-4 grid grid-cols-5;
> .field-container {
> .field-text {
@apply text-gray-400 text-sm;
}
}
> .member-container {
@apply w-full grid grid-cols-5 border-b py-2;
> .field-text {
@apply text-base mr-4 w-16;
@apply text-base pl-2 mr-4 w-16;
&.id-text {
@apply font-mono;
@apply font-mono text-gray-600;
}
&.email-text {
@apply col-span-3;
}
}
> .buttons-container {
@apply col-span-1;
}
}
}

View File

@ -42,7 +42,7 @@
> .shortcut-container {
.flex(row, space-between, center);
@apply w-full h-10 py-0 px-4 mt-1 rounded-lg text-sm cursor-pointer select-none shrink-0;
@apply w-full h-10 py-0 px-4 mt-2 rounded-lg text-base cursor-pointer select-none shrink-0;
&:hover {
background-color: @bg-gray;

View File

@ -5,14 +5,21 @@
@apply w-full h-full bg-white;
> .page-container {
@apply w-80 max-w-full p-4 -mt-16;
@apply w-80 max-w-full py-4 -mt-16;
> .page-header-container {
.flex(row, space-between, center);
@apply w-full mb-4;
@apply flex flex-col justify-start items-start w-full mb-4;
> .title-text {
@apply text-2xl;
> .icon-text {
@apply text-4xl;
}
}
> .slogan-text {
@apply mt-2 text-sm text-gray-600;
}
}
@ -22,7 +29,7 @@
> .form-item-container {
.flex(column, flex-start, flex-start);
@apply relative w-full text-base my-2;
@apply relative w-full text-base mt-2;
> .normal-text {
@apply absolute top-3 left-3 px-1 leading-10 flex-shrink-0 text-base cursor-text text-gray-400 bg-transparent transition-all select-none;
@ -36,7 +43,7 @@
@apply py-2;
> input {
@apply w-full py-3 px-3 text-base rounded-lg border border-solid border-gray-400;
@apply w-full py-3 px-3 text-base shadow-inner rounded-lg border border-solid border-gray-400;
}
&:hover {
@ -51,22 +58,14 @@
@apply w-full mt-2;
> .btn {
@apply px-1 py-2 text-sm rounded;
&:hover {
@apply opacity-80;
}
&.disabled {
@apply text-gray-400 cursor-not-allowed;
}
@apply px-1 py-2 text-sm rounded hover:opacity-80;
&.signin-btn {
@apply bg-green-600 text-white px-3;
@apply bg-green-600 text-white px-3 shadow;
}
&.requesting {
@apply cursor-wait opacity-80;
}
&.requesting {
@apply cursor-wait opacity-80;
}
}

View File

@ -27,7 +27,7 @@
.tag-item-container {
.flex(row, space-between, center);
@apply w-full h-10 py-0 px-4 rounded-lg text-sm shrink-0 select-none cursor-pointer;
@apply w-full h-10 py-0 px-4 rounded-lg text-base shrink-0 select-none cursor-pointer;
&:hover {
background-color: @bg-gray;

View File

@ -17,7 +17,7 @@ const validateConfig: ValidatorConfig = {
const Signin: React.FC<Props> = () => {
const pageLoadingState = useLoading(true);
const [siteOwner, setSiteOwner] = useState<Model.User>();
const [siteOwner, setSiteOwner] = useState<User>();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const actionBtnLoadingState = useLoading(false);
@ -128,12 +128,15 @@ const Signin: React.FC<Props> = () => {
};
return (
<div className="page-wrapper signin">
<div className={`page-wrapper signin ${pageLoadingState.isLoading ? "hidden" : ""}`}>
<div className="page-container">
<div className="page-header-container">
<p className="title-text">
<span className="icon-text"></span> Memos
</p>
<p className="slogan-text">
An <i>open source</i>, <i>self-hosted</i> knowledge base that works with local SQLite.
</p>
</div>
<div className="page-content-container">
<div className="form-item-container input-form-container">
@ -150,7 +153,7 @@ const Signin: React.FC<Props> = () => {
Login as Guest
</button>
<span className="split-text">/</span>
{siteOwner || pageLoadingState.isLoading ? (
{siteOwner ? (
<button
className={`btn signin-btn ${actionBtnLoadingState.isLoading ? "requesting" : ""}`}
onClick={() => handleSigninBtnsClick()}
@ -167,7 +170,7 @@ const Signin: React.FC<Props> = () => {
)}
</div>
<p className="tip-text">
{siteOwner || pageLoadingState.isLoading
{siteOwner
? "If you don't have an account, please contact the site owner or login as guest."
: "You are registering as the site owner."}
</p>

View File

@ -18,7 +18,7 @@ class GlobalStateService {
return appStore.getState().globalState;
};
public setEditMemoId = (editMemoId: string) => {
public setEditMemoId = (editMemoId: MemoId) => {
appStore.dispatch({
type: "SET_EDIT_MEMO_ID",
payload: {
@ -27,7 +27,7 @@ class GlobalStateService {
});
};
public setMarkMemoId = (markMemoId: string) => {
public setMarkMemoId = (markMemoId: MemoId) => {
appStore.dispatch({
type: "SET_MARK_MEMO_ID",
payload: {

View File

@ -17,7 +17,7 @@ class MemoService {
}
const data = await api.getMyMemos();
const memos: Model.Memo[] = data.filter((m) => m.rowStatus !== "HIDDEN").map((m) => this.convertResponseModelMemo(m));
const memos: Memo[] = data.filter((m) => m.rowStatus !== "ARCHIVED").map((m) => this.convertResponseModelMemo(m));
appStore.dispatch({
type: "SET_MEMOS",
payload: {
@ -37,14 +37,14 @@ class MemoService {
return false;
}
const data = await api.getMyDeletedMemos();
const deletedMemos: Model.Memo[] = data.map((m) => {
const data = await api.getMyArchivedMemos();
const deletedMemos: Memo[] = data.map((m) => {
return this.convertResponseModelMemo(m);
});
return deletedMemos;
}
public pushMemo(memo: Model.Memo) {
public pushMemo(memo: Memo) {
appStore.dispatch({
type: "INSERT_MEMO",
payload: {
@ -55,7 +55,7 @@ class MemoService {
});
}
public getMemoById(id: string) {
public getMemoById(id: MemoId) {
for (const m of this.getState().memos) {
if (m.id === id) {
return m;
@ -65,8 +65,8 @@ class MemoService {
return null;
}
public async hideMemoById(id: string) {
await api.hideMemo(id);
public async hideMemoById(id: MemoId) {
await api.archiveMemo(id);
appStore.dispatch({
type: "DELETE_MEMO_BY_ID",
payload: {
@ -75,17 +75,17 @@ class MemoService {
});
}
public async restoreMemoById(id: string) {
public async restoreMemoById(id: MemoId) {
await api.restoreMemo(id);
memoService.clearMemos();
memoService.fetchAllMemos();
}
public async deleteMemoById(id: string) {
public async deleteMemoById(id: MemoId) {
await api.deleteMemo(id);
}
public editMemo(memo: Model.Memo) {
public editMemo(memo: Memo) {
appStore.dispatch({
type: "EDIT_MEMO",
payload: memo,
@ -118,39 +118,48 @@ class MemoService {
});
}
public async getLinkedMemos(memoId: string): Promise<Model.Memo[]> {
public async getLinkedMemos(memoId: MemoId): Promise<Memo[]> {
const { memos } = this.getState();
return memos.filter((m) => m.content.includes(memoId));
return memos.filter((m) => m.content.includes(`${memoId}`));
}
public async createMemo(content: string): Promise<Model.Memo> {
const memo = await api.createMemo(content);
public async createMemo(content: string): Promise<Memo> {
const memo = await api.createMemo({
content,
});
return this.convertResponseModelMemo(memo);
}
public async updateMemo(memoId: string, content: string): Promise<Model.Memo> {
const memo = await api.updateMemo(memoId, content);
public async updateMemo(memoId: MemoId, content: string): Promise<Memo> {
const memo = await api.patchMemo({
id: memoId,
content,
});
return this.convertResponseModelMemo(memo);
}
public async pinMemo(memoId: string) {
public async pinMemo(memoId: MemoId) {
await api.pinMemo(memoId);
}
public async unpinMemo(memoId: string) {
public async unpinMemo(memoId: MemoId) {
await api.unpinMemo(memoId);
}
public async importMemo(content: string, createdAt: string) {
await api.createMemo(content, createdAt);
const createdTs = Math.floor(utils.getTimeStampByDate(createdAt) / 1000);
await api.createMemo({
content,
createdTs,
});
}
private convertResponseModelMemo(memo: Model.Memo): Model.Memo {
private convertResponseModelMemo(memo: Memo): Memo {
return {
...memo,
id: String(memo.id),
createdAt: utils.getDataStringWithTs(memo.createdTs),
updatedAt: utils.getDataStringWithTs(memo.updatedTs),
createdTs: memo.createdTs * 1000,
updatedTs: memo.updatedTs * 1000,
};
}
}

View File

@ -1,7 +1,6 @@
import userService from "./userService";
import api from "../helpers/api";
import appStore from "../stores/appStore";
import utils from "../helpers/utils";
class ShortcutService {
public getState() {
@ -33,7 +32,7 @@ class ShortcutService {
return null;
}
public pushShortcut(shortcut: Model.Shortcut) {
public pushShortcut(shortcut: Shortcut) {
appStore.dispatch({
type: "INSERT_SHORTCUT",
payload: {
@ -44,7 +43,7 @@ class ShortcutService {
});
}
public editShortcut(shortcut: Model.Shortcut) {
public editShortcut(shortcut: Shortcut) {
appStore.dispatch({
type: "UPDATE_SHORTCUT",
payload: shortcut,
@ -79,12 +78,11 @@ class ShortcutService {
await api.unpinShortcut(shortcutId);
}
public convertResponseModelShortcut(shortcut: Model.Shortcut): Model.Shortcut {
public convertResponseModelShortcut(shortcut: Shortcut): Shortcut {
return {
...shortcut,
id: String(shortcut.id),
createdAt: utils.getDataStringWithTs(shortcut.createdTs),
updatedAt: utils.getDataStringWithTs(shortcut.updatedTs),
createdTs: shortcut.createdTs * 1000,
updatedTs: shortcut.updatedTs * 1000,
};
}
}

View File

@ -1,5 +1,4 @@
import api from "../helpers/api";
import utils from "../helpers/utils";
import appStore from "../stores/appStore";
class UserService {
@ -8,7 +7,7 @@ class UserService {
}
public async doSignIn() {
const user = await api.getUserInfo();
const user = await api.getUser();
if (user) {
appStore.dispatch({
type: "LOGIN",
@ -33,19 +32,19 @@ class UserService {
}
public async updateUsername(name: string): Promise<void> {
await api.updateUserinfo({
await api.patchUser({
name,
});
}
public async updatePassword(password: string): Promise<void> {
await api.updateUserinfo({
await api.patchUser({
password,
});
}
public async resetOpenId(): Promise<string> {
const user = await api.updateUserinfo({
const user = await api.patchUser({
resetOpenId: true,
});
appStore.dispatch({
@ -55,11 +54,11 @@ class UserService {
return user.openId;
}
private convertResponseModelUser(user: Model.User): Model.User {
private convertResponseModelUser(user: User): User {
return {
...user,
createdAt: utils.getDataStringWithTs(user.createdTs),
updatedAt: utils.getDataStringWithTs(user.updatedTs),
createdTs: user.createdTs * 1000,
updatedTs: user.updatedTs * 1000,
};
}
}

View File

@ -1,3 +1,5 @@
import { UNKNOWN_ID } from "../helpers/consts";
export interface AppSetting {
shouldSplitMemoWord: boolean;
shouldHideImageUrl: boolean;
@ -5,21 +7,21 @@ export interface AppSetting {
}
export interface State extends AppSetting {
markMemoId: string;
editMemoId: string;
markMemoId: MemoId;
editMemoId: MemoId;
}
interface SetMarkMemoIdAction {
type: "SET_MARK_MEMO_ID";
payload: {
markMemoId: string;
markMemoId: MemoId;
};
}
interface SetEditMemoIdAction {
type: "SET_EDIT_MEMO_ID";
payload: {
editMemoId: string;
editMemoId: MemoId;
};
}
@ -65,8 +67,8 @@ export function reducer(state: State, action: Actions) {
}
export const defaultState: State = {
markMemoId: "",
editMemoId: "",
markMemoId: UNKNOWN_ID,
editMemoId: UNKNOWN_ID,
shouldSplitMemoWord: true,
shouldHideImageUrl: true,
shouldUseMarkdownParser: true,

View File

@ -1,14 +1,14 @@
import utils from "../helpers/utils";
export interface State {
memos: Model.Memo[];
memos: Memo[];
tags: string[];
}
interface SetMemosAction {
type: "SET_MEMOS";
payload: {
memos: Model.Memo[];
memos: Memo[];
};
}
@ -22,20 +22,20 @@ interface SetTagsAction {
interface InsertMemoAction {
type: "INSERT_MEMO";
payload: {
memo: Model.Memo;
memo: Memo;
};
}
interface DeleteMemoByIdAction {
type: "DELETE_MEMO_BY_ID";
payload: {
id: string;
id: MemoId;
};
}
interface EditMemoByIdAction {
type: "EDIT_MEMO";
payload: Model.Memo;
payload: Memo;
}
export type Actions = SetMemosAction | SetTagsAction | InsertMemoAction | DeleteMemoByIdAction | EditMemoByIdAction;
@ -43,9 +43,7 @@ export type Actions = SetMemosAction | SetTagsAction | InsertMemoAction | Delete
export function reducer(state: State, action: Actions): State {
switch (action.type) {
case "SET_MEMOS": {
const memos = utils.dedupeObjectWithId(
action.payload.memos.sort((a, b) => utils.getTimeStampByDate(b.createdAt) - utils.getTimeStampByDate(a.createdAt))
);
const memos = utils.dedupeObjectWithId(action.payload.memos.sort((a, b) => b.createdTs - a.createdTs));
return {
...state,
@ -59,10 +57,7 @@ export function reducer(state: State, action: Actions): State {
};
}
case "INSERT_MEMO": {
const memos = utils.dedupeObjectWithId(
[action.payload.memo, ...state.memos].sort((a, b) => utils.getTimeStampByDate(b.createdAt) - utils.getTimeStampByDate(a.createdAt))
);
const memos = utils.dedupeObjectWithId([action.payload.memo, ...state.memos].sort((a, b) => b.createdTs - a.createdTs));
return {
...state,
memos,

View File

@ -1,20 +1,20 @@
import utils from "../helpers/utils";
export interface State {
shortcuts: Model.Shortcut[];
shortcuts: Shortcut[];
}
interface SetShortcutsAction {
type: "SET_SHORTCUTS";
payload: {
shortcuts: Model.Shortcut[];
shortcuts: Shortcut[];
};
}
interface InsertShortcutAction {
type: "INSERT_SHORTCUT";
payload: {
shortcut: Model.Shortcut;
shortcut: Shortcut;
};
}
@ -27,7 +27,7 @@ interface DeleteShortcutByIdAction {
interface UpdateShortcutAction {
type: "UPDATE_SHORTCUT";
payload: Model.Shortcut;
payload: Shortcut;
}
export type Actions = SetShortcutsAction | InsertShortcutAction | DeleteShortcutByIdAction | UpdateShortcutAction;
@ -37,8 +37,8 @@ export function reducer(state: State, action: Actions): State {
case "SET_SHORTCUTS": {
const shortcuts = utils.dedupeObjectWithId(
action.payload.shortcuts
.sort((a, b) => utils.getTimeStampByDate(b.createdAt) - utils.getTimeStampByDate(a.createdAt))
.sort((a, b) => utils.getTimeStampByDate(b.updatedAt) - utils.getTimeStampByDate(a.updatedAt))
.sort((a, b) => utils.getTimeStampByDate(b.createdTs) - utils.getTimeStampByDate(a.createdTs))
.sort((a, b) => utils.getTimeStampByDate(b.updatedTs) - utils.getTimeStampByDate(a.updatedTs))
);
return {
@ -49,7 +49,7 @@ export function reducer(state: State, action: Actions): State {
case "INSERT_SHORTCUT": {
const shortcuts = utils.dedupeObjectWithId(
[action.payload.shortcut, ...state.shortcuts].sort(
(a, b) => utils.getTimeStampByDate(b.createdAt) - utils.getTimeStampByDate(a.createdAt)
(a, b) => utils.getTimeStampByDate(b.createdTs) - utils.getTimeStampByDate(a.createdTs)
)
);

View File

@ -1,5 +1,5 @@
export interface State {
user: Model.User | null;
user: User | null;
}
interface SignInAction {

View File

@ -1,13 +0,0 @@
declare namespace API {
interface SystemStatus {
owner: Model.User;
profile: Profile;
}
interface UserCreate {
email: string;
password: string;
name: string;
role: UserRole;
}
}

View File

@ -1,37 +0,0 @@
type UserRole = "OWNER" | "USER";
declare namespace Model {
interface BaseModel {
id: string;
createdTs: number;
updatedTs: number;
createdAt: string;
updatedAt: string;
}
interface User extends BaseModel {
role: UserRole;
email: string;
name: string;
openId: string;
}
interface Memo extends BaseModel {
content: string;
rowStatus: "NORMAL" | "ARCHIVED" | "HIDDEN";
}
interface Shortcut extends BaseModel {
title: string;
payload: string;
rowStatus: "NORMAL" | "ARCHIVED";
}
interface Resource extends BaseModel {
filename: string;
type: string;
size: string;
createdAt: string;
}
}

View File

@ -1,4 +0,0 @@
interface Profile {
mode: string;
version: string;
}

1
web/src/types/modules/common.d.ts vendored Normal file
View File

@ -0,0 +1 @@
type RowStatus = "NORMAL" | "ARCHIVED";

24
web/src/types/modules/memo.d.ts vendored Normal file
View File

@ -0,0 +1,24 @@
type MemoId = number;
interface Memo {
id: MemoId;
creatorId: UserId;
createdTs: TimeStamp;
updatedTs: TimeStamp;
rowStatus: RowStatus;
content: string;
pinned: boolean;
}
interface MemoCreate {
content: string;
createdTs?: TimeStamp;
}
interface MemoPatch {
id: MemoId;
content?: string;
rowStatus?: RowStatus;
}

12
web/src/types/modules/resource.d.ts vendored Normal file
View File

@ -0,0 +1,12 @@
type ResourceId = number;
interface Resource {
id: string;
createdTs: TimeStamp;
updatedTs: TimeStamp;
filename: string;
type: string;
size: string;
}

12
web/src/types/modules/shortcut.d.ts vendored Normal file
View File

@ -0,0 +1,12 @@
type ShortcutId = number;
interface Shortcut {
id: string;
rowStatus: RowStatus;
createdTs: TimeStamp;
updatedTs: TimeStamp;
title: string;
payload: string;
}

9
web/src/types/modules/system.d.ts vendored Normal file
View File

@ -0,0 +1,9 @@
interface Profile {
mode: string;
version: string;
}
interface SystemStatus {
owner: User;
profile: Profile;
}

28
web/src/types/modules/user.d.ts vendored Normal file
View File

@ -0,0 +1,28 @@
type UserId = number;
type UserRole = "OWNER" | "USER";
interface User {
id: UserId;
createdTs: TimeStamp;
updatedTs: TimeStamp;
rowStatus: RowStatus;
role: UserRole;
email: string;
name: string;
openId: string;
}
interface UserCreate {
email: string;
password: string;
name: string;
role: UserRole;
}
interface UserPatch {
name?: string;
password?: string;
resetOpenId?: boolean;
}

View File

@ -5,8 +5,3 @@ interface DialogProps {
interface DialogCallback {
destroy: FunctionType;
}
interface FormattedMemo extends Model.Memo {
createdAtStr: string;
deletedAtStr?: string;
}