Skip to content

Commit

Permalink
chore: redirect to instance url
Browse files Browse the repository at this point in the history
  • Loading branch information
boojack committed Dec 24, 2023
1 parent 7c9798b commit 764d776
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 75 deletions.
2 changes: 1 addition & 1 deletion frontend/extension/package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
9 changes: 2 additions & 7 deletions frontend/extension/src/background.ts
Original file line number Diff line number Diff line change
@@ -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\/(.+)/;
Expand All @@ -13,12 +12,8 @@ chrome.webRequest.onBeforeRequest.addListener(

const shortcutName = getShortcutNameFromUrl(param.url);
if (shortcutName) {
const shortcuts = (await storage.getItem<Shortcut[]>("shortcuts")) || [];
const shortcut = shortcuts.find((shortcut) => shortcut.name === shortcutName);
if (!shortcut) {
return;
}
return chrome.tabs.update({ url: shortcut.link });
const instanceUrl = (await storage.getItem<string>("domain")) || "";
return chrome.tabs.update({ url: `${instanceUrl}/s/${shortcutName}` });
}
})();
},
Expand Down
Original file line number Diff line number Diff line change
@@ -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<State>({
name: "",
title: "",
Expand All @@ -54,7 +42,7 @@ const CreateShortcutsButton = () => {
const tab = tabs[0];
setState((state) => ({
...state,
name: generateName(),
name: "",
title: tab.title || "",
link: tab.url || "",
}));
Expand Down Expand Up @@ -94,25 +82,16 @@ const CreateShortcutsButton = () => {

setIsLoading(true);
try {
const {
data: { shortcut },
} = await axios.post<CreateShortcutResponse>(
`${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) {
Expand Down Expand Up @@ -171,4 +150,4 @@ const CreateShortcutsButton = () => {
);
};

export default CreateShortcutsButton;
export default CreateShortcutButton;
20 changes: 6 additions & 14 deletions frontend/extension/src/components/PullShortcutsButton.tsx
Original file line number Diff line number Diff line change
@@ -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<ListShortcutsResponse>(`${domain}/api/v2/shortcuts`, {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
setShortcuts(shortcuts);
await shortcutStore.fetchShortcutList(instanceUrl, accessToken);
if (!silence) {
toast.success("Shortcuts pulled");
}
Expand Down
22 changes: 15 additions & 7 deletions frontend/extension/src/components/ShortcutsContainer.tsx
Original file line number Diff line number Diff line change
@@ -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<Shortcut[]>("shortcuts", (v) => (v ? v : []));
const shortcuts = useShortcutStore().getShortcutList();

return (
<div className={classNames("w-full grid grid-cols-2 gap-2")}>
{shortcuts.map((shortcut) => {
return <ShortcutView key={shortcut.id} shortcut={shortcut} />;
})}
<div>
<div className="w-full flex flex-row justify-start items-center mb-4">
<a className="bg-blue-100 dark:bg-blue-500 dark:opacity-70 py-2 px-3 rounded-full border dark:border-blue-600 flex flex-row justify-start items-center cursor-pointer shadow">
<Icon.AlertCircle className="w-4 h-auto" />
<span className="mx-1 text-sm">Please make sure you have signed in your instance.</span>
</a>
</div>
<div className={classNames("w-full grid grid-cols-2 gap-2")}>
{shortcuts.map((shortcut) => {
return <ShortcutView key={shortcut.id} shortcut={shortcut} />;
})}
</div>
</div>
);
};
Expand Down
9 changes: 5 additions & 4 deletions frontend/extension/src/options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -38,7 +38,8 @@ const IndexOptions = () => {
domain,
accessToken,
});
const [shortcuts] = useStorage<Shortcut[]>("shortcuts", []);
const shortcutStore = useShortcutStore();
const shortcuts = shortcutStore.getShortcutList();
const isInitialized = domain && accessToken;

useEffect(() => {
Expand Down Expand Up @@ -66,7 +67,7 @@ const IndexOptions = () => {
};

return (
<div className="w-full">
<div className="w-full px-4">
<div className="w-full flex flex-row justify-center items-center">
<a
className="bg-yellow-100 dark:bg-yellow-500 dark:opacity-70 mt-12 py-2 px-3 rounded-full border dark:border-yellow-600 flex flex-row justify-start items-center cursor-pointer shadow hover:underline hover:text-blue-600"
Expand All @@ -93,7 +94,7 @@ const IndexOptions = () => {
<span className="dark:text-gray-400">Instance URL</span>
{domain !== "" && (
<a
className="text-sm flex flex-row justify-start items-center dark:text-gray-400 hover:underline hover:text-blue-600"
className="text-sm flex flex-row justify-start items-center underline text-blue-600 hover:opacity-80"
href={domain}
target="_blank"
>
Expand Down
26 changes: 18 additions & 8 deletions frontend/extension/src/popup.tsx
Original file line number Diff line number Diff line change
@@ -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<string>("domain", "");
const [instanceUrl] = useStorage<string>("domain", "");
const [accessToken] = useStorage<string>("access_token", "");
const [shortcuts] = useStorage<Shortcut[]>("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();
Expand All @@ -41,7 +51,7 @@ const IndexPopup = () => {
</>
)}
</div>
<div>{isInitialized && <CreateShortcutsButton />}</div>
<div>{isInitialized && <CreateShortcutButton />}</div>
</div>

<div className="w-full mt-4">
Expand Down Expand Up @@ -75,8 +85,8 @@ const IndexPopup = () => {
</div>
<div className="flex flex-row justify-end items-center">
<a
className="text-sm flex flex-row justify-start items-center text-gray-500 dark:text-gray-400 hover:underline hover:text-blue-600"
href={domain}
className="text-sm flex flex-row justify-start items-center underline text-blue-600 hover:opacity-80"
href={instanceUrl}
target="_blank"
>
<span className="mr-1">Go to my Slash</span>
Expand Down
55 changes: 55 additions & 0 deletions frontend/extension/src/store/shortcut.ts
Original file line number Diff line number Diff line change
@@ -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<number, Shortcut>;
}

const getDefaultState = (): State => {
return {
shortcutMapById: {},
};
};

const useShortcutStore = create(
combine(getDefaultState(), (set, get) => ({
fetchShortcutList: async (instanceUrl: string, accessToken: string) => {
const {
data: { shortcuts },
} = await axios.get<ListShortcutsResponse>(`${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<CreateShortcutResponse>(`${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;

0 comments on commit 764d776

Please sign in to comment.