Feat: support action cable (#665)

* upgrade deps

* may connect server via cable
This commit is contained in:
an-lee
2024-06-09 14:07:30 +08:00
committed by GitHub
parent bfcd0be80f
commit 14a44752b1
12 changed files with 306 additions and 113 deletions

View File

@@ -0,0 +1 @@
export * from "./notifications_channel";

View File

@@ -0,0 +1,49 @@
import { toast } from "@/renderer/components/ui";
import { type Consumer } from "@rails/actioncable";
export class NoticiationsChannel {
private consumer: Consumer;
constructor(consumer: Consumer) {
this.consumer = consumer;
}
subscribe() {
this.consumer.subscriptions.create(
{ channel: "NotificationsChannel" },
{
received(data) {
if (typeof data === "string") {
toast.info(data);
} else {
switch (data?.type) {
case "success":
toast.success(data.message);
break;
case "error":
toast.error(data.message);
break;
case "info":
toast.info(data.message);
break;
case "warning":
toast.warning(data.message);
break;
default:
toast.message(data.message);
break;
}
}
if (data.id) {
this.markAsSeen([data.id]);
}
},
markAsSeen(ids: number[]) {
this.consumer.perform("mark_as_seen", { ids });
},
}
);
}
}

View File

@@ -0,0 +1 @@
export * from './channels';

View File

@@ -14,6 +14,7 @@ import {
DropdownMenuSubTrigger,
DropdownMenuItem,
Separator,
toast,
} from "@renderer/components/ui";
import {
SettingsIcon,
@@ -34,12 +35,19 @@ import { useLocation, Link } from "react-router-dom";
import { t } from "i18next";
import { Preferences } from "@renderer/components";
import { AppSettingsProviderContext } from "@renderer/context";
import { useContext } from "react";
import { useContext, useEffect } from "react";
import { NoticiationsChannel } from "@/renderer/cables";
export const Sidebar = () => {
const location = useLocation();
const activeTab = location.pathname;
const { EnjoyApp } = useContext(AppSettingsProviderContext);
const { EnjoyApp, cable } = useContext(AppSettingsProviderContext);
useEffect(() => {
console.log("Subscrbing ->");
const channel = new NoticiationsChannel(cable);
channel.subscribe();
}, []);
return (
<div
@@ -170,7 +178,9 @@ export const Sidebar = () => {
className="w-full xl:justify-start px-2 xl:px-4"
>
<HelpCircleIcon className="h-5 w-5" />
<span className="ml-2 hidden xl:block">{t("sidebar.help")}</span>
<span className="ml-2 hidden xl:block">
{t("sidebar.help")}
</span>
</Button>
</DropdownMenuTrigger>

View File

@@ -3,6 +3,7 @@ import { WEB_API_URL, LANGUAGES } from "@/constants";
import { Client } from "@/api";
import i18n from "@renderer/i18n";
import ahoy from "ahoy.js";
import { type Consumer, createConsumer } from "@rails/actioncable";
type AppSettingsProviderState = {
webApi: Client;
@@ -23,6 +24,7 @@ type AppSettingsProviderState = {
switchLearningLanguage?: (lang: string) => void;
proxy?: ProxyConfigType;
setProxy?: (config: ProxyConfigType) => Promise<void>;
cable?: Consumer;
ahoy?: typeof ahoy;
};
@@ -43,6 +45,7 @@ export const AppSettingsProvider = ({
const [version, setVersion] = useState<string>("");
const [apiUrl, setApiUrl] = useState<string>(WEB_API_URL);
const [webApi, setWebApi] = useState<Client>(null);
const [cable, setCable] = useState<Consumer>();
const [user, setUser] = useState<UserType | null>(null);
const [libraryPath, setLibraryPath] = useState("");
const [language, setLanguage] = useState<"en" | "zh-CN">();
@@ -145,6 +148,7 @@ export const AppSettingsProvider = ({
const login = (user: UserType) => {
setUser(user);
EnjoyApp.settings.setUser(user);
createCable(user.accessToken);
};
const logout = () => {
@@ -173,6 +177,12 @@ export const AppSettingsProvider = ({
});
};
const createCable = async (token: string) => {
const wsUrl = await EnjoyApp.app.wsUrl();
const consumer = createConsumer(wsUrl + "/cable?token=" + token);
setCable(consumer);
};
return (
<AppSettingsProviderContext.Provider
value={{
@@ -195,6 +205,7 @@ export const AppSettingsProvider = ({
setProxy: setProxyConfigHandler,
initialized: Boolean(user && libraryPath),
ahoy,
cable,
}}
>
{children}