From 764d7765240efec3c313f388b90761a12fb110c3 Mon Sep 17 00:00:00 2001 From: Steven Date: Sun, 24 Dec 2023 09:50:10 +0800 Subject: [PATCH] chore: redirect to instance url --- frontend/extension/package.json | 2 +- frontend/extension/src/background.ts | 9 +-- ...utsButton.tsx => CreateShortcutButton.tsx} | 47 +++++----------- .../src/components/PullShortcutsButton.tsx | 20 ++----- .../src/components/ShortcutsContainer.tsx | 22 +++++--- frontend/extension/src/options.tsx | 9 +-- frontend/extension/src/popup.tsx | 26 ++++++--- frontend/extension/src/store/shortcut.ts | 55 +++++++++++++++++++ 8 files changed, 115 insertions(+), 75 deletions(-) rename frontend/extension/src/components/{CreateShortcutsButton.tsx => CreateShortcutButton.tsx} (80%) create mode 100644 frontend/extension/src/store/shortcut.ts diff --git a/frontend/extension/package.json b/frontend/extension/package.json index e2109adc..ea3bfac3 100644 --- a/frontend/extension/package.json +++ b/frontend/extension/package.json @@ -1,7 +1,7 @@ { "name": "slash-extension", "displayName": "Slash", - "version": "1.0.2", + "version": "1.0.3", "description": "An open source, self-hosted bookmarks and link sharing platform. Save and share your links very easily.", "scripts": { "dev": "plasmo dev", diff --git a/frontend/extension/src/background.ts b/frontend/extension/src/background.ts index 793c41a7..b252bebb 100644 --- a/frontend/extension/src/background.ts +++ b/frontend/extension/src/background.ts @@ -1,5 +1,4 @@ import { Storage } from "@plasmohq/storage"; -import type { Shortcut } from "@/types/proto/api/v2/shortcut_service"; const storage = new Storage(); const urlRegex = /https?:\/\/s\/(.+)/; @@ -13,12 +12,8 @@ chrome.webRequest.onBeforeRequest.addListener( const shortcutName = getShortcutNameFromUrl(param.url); if (shortcutName) { - const shortcuts = (await storage.getItem("shortcuts")) || []; - const shortcut = shortcuts.find((shortcut) => shortcut.name === shortcutName); - if (!shortcut) { - return; - } - return chrome.tabs.update({ url: shortcut.link }); + const instanceUrl = (await storage.getItem("domain")) || ""; + return chrome.tabs.update({ url: `${instanceUrl}/s/${shortcutName}` }); } })(); }, diff --git a/frontend/extension/src/components/CreateShortcutsButton.tsx b/frontend/extension/src/components/CreateShortcutButton.tsx similarity index 80% rename from frontend/extension/src/components/CreateShortcutsButton.tsx rename to frontend/extension/src/components/CreateShortcutButton.tsx index 8a64df5b..ce54161f 100644 --- a/frontend/extension/src/components/CreateShortcutsButton.tsx +++ b/frontend/extension/src/components/CreateShortcutButton.tsx @@ -1,34 +1,22 @@ import { Button, IconButton, Input, Modal, ModalDialog } from "@mui/joy"; import { useStorage } from "@plasmohq/storage/hook"; -import axios from "axios"; import { useEffect, useState } from "react"; import { toast } from "react-hot-toast"; +import useShortcutStore from "@/store/shortcut"; import { Visibility } from "@/types/proto/api/v2/common"; -import { CreateShortcutResponse, OpenGraphMetadata } from "@/types/proto/api/v2/shortcut_service"; +import { Shortcut } from "@/types/proto/api/v2/shortcut_service"; import Icon from "./Icon"; -const generateName = (length = 8) => { - let result = ""; - const characters = "abcdefghijklmnopqrstuvwxyz0123456789"; - const charactersLength = characters.length; - let counter = 0; - while (counter < length) { - result += characters.charAt(Math.floor(Math.random() * charactersLength)); - counter += 1; - } - return result; -}; - interface State { name: string; title: string; link: string; } -const CreateShortcutsButton = () => { - const [domain] = useStorage("domain"); +const CreateShortcutButton = () => { + const [instanceUrl] = useStorage("domain"); const [accessToken] = useStorage("access_token"); - const [shortcuts, setShortcuts] = useStorage("shortcuts"); + const shortcutStore = useShortcutStore(); const [state, setState] = useState({ name: "", title: "", @@ -54,7 +42,7 @@ const CreateShortcutsButton = () => { const tab = tabs[0]; setState((state) => ({ ...state, - name: generateName(), + name: "", title: tab.title || "", link: tab.url || "", })); @@ -94,25 +82,16 @@ const CreateShortcutsButton = () => { setIsLoading(true); try { - const { - data: { shortcut }, - } = await axios.post( - `${domain}/api/v2/shortcuts`, - { + await shortcutStore.createShortcut( + instanceUrl, + accessToken, + Shortcut.fromPartial({ name: state.name, title: state.title, link: state.link, - visibility: Visibility.PRIVATE, - ogMetadata: OpenGraphMetadata.fromPartial({}), - }, - { - headers: { - Authorization: `Bearer ${accessToken}`, - }, - } + visibility: Visibility.PUBLIC, + }) ); - - setShortcuts([shortcut, ...shortcuts]); toast.success("Shortcut created successfully"); setShowModal(false); } catch (error: any) { @@ -171,4 +150,4 @@ const CreateShortcutsButton = () => { ); }; -export default CreateShortcutsButton; +export default CreateShortcutButton; diff --git a/frontend/extension/src/components/PullShortcutsButton.tsx b/frontend/extension/src/components/PullShortcutsButton.tsx index 8f027673..c00f11b4 100644 --- a/frontend/extension/src/components/PullShortcutsButton.tsx +++ b/frontend/extension/src/components/PullShortcutsButton.tsx @@ -1,32 +1,24 @@ import { IconButton } from "@mui/joy"; import { useStorage } from "@plasmohq/storage/hook"; -import axios from "axios"; import { useEffect } from "react"; import { toast } from "react-hot-toast"; -import { ListShortcutsResponse } from "@/types/proto/api/v2/shortcut_service"; +import useShortcutStore from "@/store/shortcut"; import Icon from "./Icon"; const PullShortcutsButton = () => { - const [domain] = useStorage("domain"); + const [instanceUrl] = useStorage("domain"); const [accessToken] = useStorage("access_token"); - const [, setShortcuts] = useStorage("shortcuts"); + const shortcutStore = useShortcutStore(); useEffect(() => { - if (domain && accessToken) { + if (instanceUrl && accessToken) { handlePullShortcuts(true); } - }, [domain, accessToken]); + }, [instanceUrl, accessToken]); const handlePullShortcuts = async (silence = false) => { try { - const { - data: { shortcuts }, - } = await axios.get(`${domain}/api/v2/shortcuts`, { - headers: { - Authorization: `Bearer ${accessToken}`, - }, - }); - setShortcuts(shortcuts); + await shortcutStore.fetchShortcutList(instanceUrl, accessToken); if (!silence) { toast.success("Shortcuts pulled"); } diff --git a/frontend/extension/src/components/ShortcutsContainer.tsx b/frontend/extension/src/components/ShortcutsContainer.tsx index 54cd32b7..a81c5bdb 100644 --- a/frontend/extension/src/components/ShortcutsContainer.tsx +++ b/frontend/extension/src/components/ShortcutsContainer.tsx @@ -1,16 +1,24 @@ -import { useStorage } from "@plasmohq/storage/hook"; import classNames from "classnames"; -import type { Shortcut } from "@/types/proto/api/v2/shortcut_service"; +import useShortcutStore from "@/store/shortcut"; +import Icon from "./Icon"; import ShortcutView from "./ShortcutView"; const ShortcutsContainer = () => { - const [shortcuts] = useStorage("shortcuts", (v) => (v ? v : [])); + const shortcuts = useShortcutStore().getShortcutList(); return ( -
- {shortcuts.map((shortcut) => { - return ; - })} +
+ +
+ {shortcuts.map((shortcut) => { + return ; + })} +
); }; diff --git a/frontend/extension/src/options.tsx b/frontend/extension/src/options.tsx index 7aeb7d74..cffc5a45 100644 --- a/frontend/extension/src/options.tsx +++ b/frontend/extension/src/options.tsx @@ -2,12 +2,12 @@ import { Button, CssVarsProvider, Divider, Input, Select, Option } from "@mui/jo import { useStorage } from "@plasmohq/storage/hook"; import { useEffect, useState } from "react"; import { Toaster, toast } from "react-hot-toast"; -import type { Shortcut } from "@/types/proto/api/v2/shortcut_service"; import Icon from "./components/Icon"; import Logo from "./components/Logo"; import PullShortcutsButton from "./components/PullShortcutsButton"; import ShortcutsContainer from "./components/ShortcutsContainer"; import useColorTheme from "./hooks/useColorTheme"; +import useShortcutStore from "./store/shortcut"; import "./style.css"; interface SettingState { @@ -38,7 +38,8 @@ const IndexOptions = () => { domain, accessToken, }); - const [shortcuts] = useStorage("shortcuts", []); + const shortcutStore = useShortcutStore(); + const shortcuts = shortcutStore.getShortcutList(); const isInitialized = domain && accessToken; useEffect(() => { @@ -66,7 +67,7 @@ const IndexOptions = () => { }; return ( -
+
{ Instance URL {domain !== "" && ( diff --git a/frontend/extension/src/popup.tsx b/frontend/extension/src/popup.tsx index 46187b36..9e02b269 100644 --- a/frontend/extension/src/popup.tsx +++ b/frontend/extension/src/popup.tsx @@ -1,21 +1,31 @@ import { Button, CssVarsProvider, Divider, IconButton } from "@mui/joy"; import { useStorage } from "@plasmohq/storage/hook"; +import { useEffect } from "react"; import { Toaster } from "react-hot-toast"; -import CreateShortcutsButton from "@/components/CreateShortcutsButton"; +import CreateShortcutButton from "@/components/CreateShortcutButton"; import Icon from "@/components/Icon"; import Logo from "@/components/Logo"; import PullShortcutsButton from "@/components/PullShortcutsButton"; import ShortcutsContainer from "@/components/ShortcutsContainer"; -import type { Shortcut } from "@/types/proto/api/v2/shortcut_service"; import useColorTheme from "./hooks/useColorTheme"; +import useShortcutStore from "./store/shortcut"; import "./style.css"; const IndexPopup = () => { useColorTheme(); - const [domain] = useStorage("domain", ""); + const [instanceUrl] = useStorage("domain", ""); const [accessToken] = useStorage("access_token", ""); - const [shortcuts] = useStorage("shortcuts", []); - const isInitialized = domain && accessToken; + const shortcutStore = useShortcutStore(); + const shortcuts = shortcutStore.getShortcutList(); + const isInitialized = instanceUrl && accessToken; + + useEffect(() => { + if (!isInitialized) { + return; + } + + shortcutStore.fetchShortcutList(instanceUrl, accessToken); + }, [isInitialized]); const handleSettingButtonClick = () => { chrome.runtime.openOptionsPage(); @@ -41,7 +51,7 @@ const IndexPopup = () => { )}
-
{isInitialized && }
+
{isInitialized && }
@@ -75,8 +85,8 @@ const IndexPopup = () => {
Go to my Slash diff --git a/frontend/extension/src/store/shortcut.ts b/frontend/extension/src/store/shortcut.ts new file mode 100644 index 00000000..ca10af03 --- /dev/null +++ b/frontend/extension/src/store/shortcut.ts @@ -0,0 +1,55 @@ +import axios from "axios"; +import { create } from "zustand"; +import { combine } from "zustand/middleware"; +import { CreateShortcutResponse, ListShortcutsResponse, Shortcut } from "@/types/proto/api/v2/shortcut_service"; + +interface State { + shortcutMapById: Record; +} + +const getDefaultState = (): State => { + return { + shortcutMapById: {}, + }; +}; + +const useShortcutStore = create( + combine(getDefaultState(), (set, get) => ({ + fetchShortcutList: async (instanceUrl: string, accessToken: string) => { + const { + data: { shortcuts }, + } = await axios.get(`${instanceUrl}/api/v2/shortcuts`, { + headers: { + Authorization: `Bearer ${accessToken}`, + }, + }); + const shortcutMap = get().shortcutMapById; + shortcuts.forEach((shortcut) => { + shortcutMap[shortcut.id] = shortcut; + }); + set({ shortcutMapById: shortcutMap }); + return shortcuts; + }, + getShortcutList: () => { + return Object.values(get().shortcutMapById); + }, + createShortcut: async (instanceUrl: string, accessToken: string, create: Shortcut) => { + const { + data: { shortcut }, + } = await axios.post(`${instanceUrl}/api/v2/shortcuts`, create, { + headers: { + Authorization: `Bearer ${accessToken}`, + }, + }); + if (!shortcut) { + throw new Error(`Failed to create shortcut`); + } + const shortcutMap = get().shortcutMapById; + shortcutMap[shortcut.id] = shortcut; + set({ shortcutMapById: shortcutMap }); + return shortcut; + }, + })) +); + +export default useShortcutStore;