add error handling for failed requests
This commit is contained in:
parent
72c9650f71
commit
00f7ca72a5
9 changed files with 233 additions and 106 deletions
|
@ -1,18 +1,18 @@
|
|||
<script>
|
||||
import { overlayStore } from "../../stores";
|
||||
import { methods, remoteSignal } from "../../request";
|
||||
import { methods, remoteSignal, responseOk } from "../../request";
|
||||
import RpcErrorDisplay from "../rpc/RpcErrorDisplay.svelte";
|
||||
import Modal from "./Modal.svelte";
|
||||
|
||||
let communityName = "";
|
||||
let createButtonEnabled = true;
|
||||
let response;
|
||||
export let close = () => {};
|
||||
|
||||
const create = async () => {
|
||||
createButtonEnabled = false;
|
||||
const { ok } = await remoteSignal(methods.createCommunity, communityName);
|
||||
if (!ok) {
|
||||
overlayStore.toast("Couldn't create community");
|
||||
}
|
||||
response = await remoteSignal(methods.createCommunity, communityName);
|
||||
createButtonEnabled = true;
|
||||
if (responseOk(response))
|
||||
close();
|
||||
};
|
||||
</script>
|
||||
|
@ -21,6 +21,8 @@
|
|||
<span class="h4" slot="header">Create Community</span>
|
||||
|
||||
<svelte:fragment slot="content">
|
||||
<RpcErrorDisplay response={response} />
|
||||
<RpcErrorDisplay validationIndex={0} response={response} />
|
||||
<label class="input-label">
|
||||
Community Name
|
||||
<input class="input full-width" minlength="1" maxlength="32" bind:value={ communityName } />
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
<script>
|
||||
import { overlayStore, OverlayType } from "../../stores";
|
||||
import { methods, remoteCall } from "../../request";
|
||||
import { methods, remoteCall, responseOk } from "../../request";
|
||||
import Modal from "./Modal.svelte";
|
||||
import RpcErrorDisplay from "../rpc/RpcErrorDisplay.svelte";
|
||||
|
||||
let username = "";
|
||||
let password = "";
|
||||
let buttonsEnabled = true;
|
||||
let pendingOtherOpen = false;
|
||||
let response;
|
||||
export let close = () => {};
|
||||
|
||||
const create = async () => {
|
||||
buttonsEnabled = false;
|
||||
const { ok } = await remoteCall(methods.createUser, username, password);
|
||||
if (ok) {
|
||||
response = await remoteCall(methods.createUser, username, password);
|
||||
if (responseOk(response)) {
|
||||
overlayStore.toast("Account created");
|
||||
loginInstead();
|
||||
} else {
|
||||
overlayStore.toast("Couldn't create account");
|
||||
buttonsEnabled = true;
|
||||
return;
|
||||
}
|
||||
};
|
||||
const loginInstead = () => {
|
||||
|
@ -42,6 +42,9 @@
|
|||
<span class="h4" slot="header">Create an Account</span>
|
||||
|
||||
<svelte:fragment slot="content">
|
||||
<RpcErrorDisplay response={response} />
|
||||
|
||||
<RpcErrorDisplay validationIndex={0} response={response} />
|
||||
<label class="input-label">
|
||||
Username
|
||||
<input class="input full-width" minlength="1" maxlength="32" bind:value={ username } />
|
||||
|
@ -49,6 +52,7 @@
|
|||
|
||||
<div class="separator" />
|
||||
|
||||
<RpcErrorDisplay validationIndex={1} response={response} />
|
||||
<label class="input-label">
|
||||
Password
|
||||
<input class="input full-width" minlength="8" type="password" bind:value={ password } />
|
||||
|
@ -56,7 +60,7 @@
|
|||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="footer">
|
||||
<button class="button modal-secondary-action" on:click="{ loginInstead }">Log in instead</button>
|
||||
<button class="button modal-secondary-action" on:click="{ loginInstead }" disabled="{ !buttonsEnabled }">Log in instead</button>
|
||||
<button class="button button-accent modal-primary-action" on:click="{ create }" disabled="{ !buttonsEnabled }">Create</button>
|
||||
</svelte:fragment>
|
||||
</Modal>
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
<script>
|
||||
import { overlayStore } from "../../stores";
|
||||
import { methods, remoteSignal } from "../../request";
|
||||
import { methods, remoteSignal, responseOk } from "../../request";
|
||||
import RpcErrorDisplay from "../rpc/RpcErrorDisplay.svelte";
|
||||
import Modal from "./Modal.svelte";
|
||||
|
||||
let channelName = "";
|
||||
let createButtonEnabled = true;
|
||||
let response;
|
||||
export let close = () => {};
|
||||
export let community = null;
|
||||
|
||||
const create = async () => {
|
||||
createButtonEnabled = false;
|
||||
const { ok } = await remoteSignal(methods.createChannel, channelName, community.id !== -1 ? community.id : null);
|
||||
if (!ok) {
|
||||
overlayStore.toast("Couldn't create channel");
|
||||
}
|
||||
response = await remoteSignal(methods.createChannel, channelName, community.id !== -1 ? community.id : null);
|
||||
createButtonEnabled = true;
|
||||
if (responseOk(response))
|
||||
close();
|
||||
};
|
||||
</script>
|
||||
|
@ -27,6 +27,8 @@
|
|||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="content">
|
||||
<RpcErrorDisplay response={response} />
|
||||
<RpcErrorDisplay validationIndex={0} response={response} />
|
||||
<label class="input-label">
|
||||
Channel Name
|
||||
<input class="input full-width" minlength="1" maxlength="32" bind:value={ channelName } />
|
||||
|
|
|
@ -1,27 +1,29 @@
|
|||
<script>
|
||||
import { overlayStore } from "../../stores";
|
||||
import { methods, remoteSignal } from "../../request";
|
||||
import { getMessageFromResponse, methods, remoteSignal, responseOk } from "../../request";
|
||||
import Modal from "./Modal.svelte";
|
||||
import RpcErrorDisplay from "../rpc/RpcErrorDisplay.svelte";
|
||||
|
||||
export let channel;
|
||||
|
||||
let channelName = channel.name;
|
||||
let buttonsEnabled = true;
|
||||
let response;
|
||||
export let close = () => {};
|
||||
|
||||
const save = async () => {
|
||||
buttonsEnabled = false;
|
||||
const { ok } = await remoteSignal(methods.updateChannelName, channel.id, channelName);
|
||||
if (!ok) {
|
||||
overlayStore.toast("Couldn't edit channel");
|
||||
}
|
||||
response = await remoteSignal(methods.updateChannelName, channel.id, channelName);
|
||||
buttonsEnabled = true;
|
||||
if (responseOk(response)) {
|
||||
close();
|
||||
}
|
||||
};
|
||||
const deleteChannel = async () => {
|
||||
buttonsEnabled = false;
|
||||
const { ok } = await remoteSignal(methods.deleteChannel, channel.id);
|
||||
if (!ok) {
|
||||
overlayStore.toast("Couldn't delete channel");
|
||||
const res = await remoteSignal(methods.deleteChannel, channel.id);
|
||||
if (!responseOk(res)) {
|
||||
overlayStore.toast(`Couldn't delete channel: ${getMessageFromResponse(res)}`);
|
||||
}
|
||||
close();
|
||||
};
|
||||
|
@ -37,8 +39,10 @@
|
|||
<span class="h4" slot="header">Edit Channel</span>
|
||||
|
||||
<svelte:fragment slot="content">
|
||||
<RpcErrorDisplay response={response} />
|
||||
<RpcErrorDisplay validationIndex={1} response={response} />
|
||||
<label class="input-label">
|
||||
Channel Name
|
||||
<span>Channel Name</span>
|
||||
<input class="input full-width" minlength="1" maxlength="32" bind:value={ channelName } />
|
||||
</label>
|
||||
</svelte:fragment>
|
||||
|
|
|
@ -1,27 +1,28 @@
|
|||
<script>
|
||||
import { overlayStore } from "../../stores";
|
||||
import { methods, remoteSignal } from "../../request";
|
||||
import { getMessageFromResponse, methods, remoteSignal, responseOk } from "../../request";
|
||||
import Modal from "./Modal.svelte";
|
||||
import RpcErrorDisplay from "../rpc/RpcErrorDisplay.svelte";
|
||||
|
||||
export let message;
|
||||
|
||||
let messageContent = message.content;
|
||||
let buttonsEnabled = true;
|
||||
let response;
|
||||
export let close = () => {};
|
||||
|
||||
const save = async () => {
|
||||
buttonsEnabled = false;
|
||||
const { ok } = await remoteSignal(methods.updateMessageContent, message.id, messageContent);
|
||||
if (!ok) {
|
||||
overlayStore.toast("Couldn't edit message");
|
||||
}
|
||||
response = await remoteSignal(methods.updateMessageContent, message.id, messageContent);
|
||||
buttonsEnabled = true;
|
||||
if (responseOk(response))
|
||||
close();
|
||||
};
|
||||
const deleteMessage = async () => {
|
||||
buttonsEnabled = false;
|
||||
const { ok } = await remoteSignal(methods.deleteMessage, message.id);
|
||||
if (!ok) {
|
||||
overlayStore.toast("Couldn't delete message");
|
||||
const res = await remoteSignal(methods.deleteMessage, message.id);
|
||||
if (!responseOk(res)) {
|
||||
overlayStore.toast(`Couldn't delete message: ${getMessageFromResponse(res)}`);
|
||||
}
|
||||
close();
|
||||
};
|
||||
|
@ -37,6 +38,8 @@
|
|||
<span class="h4" slot="header">Edit Message</span>
|
||||
|
||||
<svelte:fragment slot="content">
|
||||
<RpcErrorDisplay response={response} />
|
||||
<RpcErrorDisplay validationIndex={1} response={response} />
|
||||
<label class="input-label">
|
||||
Content
|
||||
<input class="input full-width" minlength="1" bind:value={ messageContent } />
|
||||
|
|
|
@ -1,29 +1,25 @@
|
|||
<script>
|
||||
import { overlayStore, OverlayType } from "../../stores";
|
||||
import { remoteCall } from "../../request";
|
||||
import { remoteCall, responseOk } from "../../request";
|
||||
import { authWithToken } from "../../auth";
|
||||
import { methods } from "../../request";
|
||||
import Modal from "./Modal.svelte";
|
||||
import RpcErrorDisplay from "../rpc/RpcErrorDisplay.svelte";
|
||||
|
||||
let username = "";
|
||||
let password = "";
|
||||
let buttonsEnabled = true;
|
||||
let pendingOtherOpen = false;
|
||||
let response;
|
||||
export let close = () => {};
|
||||
|
||||
const login = async () => {
|
||||
buttonsEnabled = false;
|
||||
const { ok, json } = await remoteCall(methods.loginUser, username, password);
|
||||
if (ok && json && json.token) {
|
||||
authWithToken(json.token, true);
|
||||
response = await remoteCall(methods.loginUser, username, password);
|
||||
if (responseOk(response) && response.data && response.data.token) {
|
||||
authWithToken(response.data.token, true);
|
||||
} else {
|
||||
if (json && json.code && json.code === 6002) { // 6002 is the code for bad login
|
||||
overlayStore.toast("Invalid username or password");
|
||||
} else {
|
||||
overlayStore.toast("Couldn't log in");
|
||||
}
|
||||
buttonsEnabled = true;
|
||||
return;
|
||||
}
|
||||
};
|
||||
const createAccountInstead = () => {
|
||||
|
@ -47,6 +43,9 @@
|
|||
<span class="h4" slot="header">Welcome back!</span>
|
||||
|
||||
<svelte:fragment slot="content">
|
||||
<RpcErrorDisplay response={response} />
|
||||
|
||||
<RpcErrorDisplay validationIndex={0} response={response} />
|
||||
<label class="input-label">
|
||||
Username
|
||||
<input class="input full-width" minlength="1" maxlength="32" bind:value={ username } />
|
||||
|
@ -54,6 +53,7 @@
|
|||
|
||||
<div class="separator" />
|
||||
|
||||
<RpcErrorDisplay validationIndex={1} response={response} />
|
||||
<label class="input-label">
|
||||
Password
|
||||
<input class="input full-width" minlength="8" type="password" bind:value={ password } />
|
||||
|
@ -61,7 +61,7 @@
|
|||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="footer">
|
||||
<button class="button modal-secondary-action" on:click="{ createAccountInstead }">Create an account instead</button>
|
||||
<button class="button modal-secondary-action" on:click="{ createAccountInstead }" disabled="{ !buttonsEnabled }">Create an account instead</button>
|
||||
<button class="button button-accent modal-primary-action" on:click="{ login }" disabled="{ !buttonsEnabled }">Log In</button>
|
||||
</svelte:fragment>
|
||||
</Modal>
|
||||
|
|
41
frontend/src/components/rpc/RpcErrorDisplay.svelte
Normal file
41
frontend/src/components/rpc/RpcErrorDisplay.svelte
Normal file
|
@ -0,0 +1,41 @@
|
|||
<script>
|
||||
import { getErrorFromResponse } from "../../request";
|
||||
|
||||
export let response = null;
|
||||
export let validationIndex = -1;
|
||||
|
||||
let message = null;
|
||||
|
||||
$: {
|
||||
const error = getErrorFromResponse(response);
|
||||
if (error) {
|
||||
if (validationIndex >= 0) {
|
||||
if (error.validationErrors) {
|
||||
const found = error.validationErrors.find(e => e.index === validationIndex);
|
||||
if (found) {
|
||||
message = found.msg;
|
||||
}
|
||||
} else {
|
||||
message = null;
|
||||
}
|
||||
} else {
|
||||
if (error.validationErrors) {
|
||||
message = null;
|
||||
} else {
|
||||
message = error.message;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
span {
|
||||
color: var(--red-1);
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
{#if message}
|
||||
<span>{ message }</span>
|
||||
{/if}
|
|
@ -29,34 +29,71 @@ export const methods = {
|
|||
getCommunityChannels: withCacheable(method(405, true)),
|
||||
};
|
||||
|
||||
export function compatibleFetch(endpoint, options) {
|
||||
if (window.fetch && typeof window.fetch === "function") {
|
||||
return fetch(endpoint, options);
|
||||
} else {
|
||||
return new Promise((resolve, reject) => {
|
||||
const req = new XMLHttpRequest();
|
||||
req.addEventListener("load", () => {
|
||||
resolve({
|
||||
status: req.status,
|
||||
ok: [200, 201, 204].includes(req.status),
|
||||
json() {
|
||||
return JSON.parse(req.responseText);
|
||||
}
|
||||
});
|
||||
});
|
||||
req.addEventListener("error", (e) => {
|
||||
reject(e);
|
||||
});
|
||||
export const RPCError = {
|
||||
BAD_REQUEST: { code: 6000, message: "Bad request" },
|
||||
RPC_VALIDATION_ERROR: { code: 6001, message: "We couldn't validate this request" },
|
||||
BAD_LOGIN_CREDENTIALS: { code: 6002, message: "Incorrect login credentials" },
|
||||
BAD_AUTH: { code: 6003, message: "You're not authenticated" },
|
||||
NOT_FOUND: { code: 6004, message: "Not found" },
|
||||
FORBIDDEN_DUE_TO_MISSING_PERMISSIONS: { code: 6005, message: "You don't have the required permissions to perform this action" },
|
||||
BAD_REQUEST_KEY: { code: 6006, message: "This request requires a special password, however, the password you provided was incorrect" },
|
||||
GOT_NO_DATABASE_DATA: { code: 7001, message: "Sorry, we couldn't process this request (server expected data from database, however got none)" },
|
||||
FEATURE_DISABLED: { code: 7002, message: "This feature is disabled" },
|
||||
INTERNAL_ERROR: { code: 7003, message: "Sorry, we couldn't process this request (internal server error)" },
|
||||
};
|
||||
|
||||
req.open(options.method || "GET", endpoint);
|
||||
if (options.headers) {
|
||||
for (const [header, value] of Object.entries(options.headers)) {
|
||||
req.setRequestHeader(header, value);
|
||||
export const RequestStatus = {
|
||||
OK: 0,
|
||||
NETWORK_EXCEPTION: 1,
|
||||
JSON_EXCEPTION: 2,
|
||||
FAILURE_STATUS: 3,
|
||||
RPC_ERROR: 4,
|
||||
INVARIANT_RPC_RESPONSE_COUNT: 5,
|
||||
};
|
||||
|
||||
export const RequestStatusToMessage = {
|
||||
[RequestStatus.OK]: "",
|
||||
[RequestStatus.NETWORK_EXCEPTION]: "We couldn't reach the server right now",
|
||||
[RequestStatus.JSON_EXCEPTION]: "We couldn't process this request right now (server gave an invalid response, failed to parse as JSON)",
|
||||
[RequestStatus.FAILURE_STATUS]: "We couldn't process this request right now (server gave a failure status code)",
|
||||
[RequestStatus.RPC_ERROR]: "We couldn't process this request right now (RPC error)",
|
||||
[RequestStatus.INVARIANT_RPC_RESPONSE_COUNT]: "We couldn't process this request right now (invalid RPC response)",
|
||||
};
|
||||
|
||||
|
||||
export function getErrorFromResponse(response) {
|
||||
if (!response) return;
|
||||
if (response.status === RequestStatus.OK) return;
|
||||
console.log(response);
|
||||
|
||||
let message = RequestStatusToMessage[response.status];
|
||||
if (!message) message = "Something went wrong (unknown request error)";
|
||||
|
||||
if (response.status === RequestStatus.RPC_ERROR) {
|
||||
let rpcErrorMessage = Object.values(RPCError).find(({ code }) => code === response.data.code);
|
||||
if (rpcErrorMessage) {
|
||||
rpcErrorMessage = rpcErrorMessage.message;
|
||||
} else {
|
||||
rpcErrorMessage = "Something went wrong (unknown RPC error)";
|
||||
}
|
||||
|
||||
if (response.data.code === RPCError.RPC_VALIDATION_ERROR.code) {
|
||||
return { message: rpcErrorMessage, validationErrors: response.data.errors };
|
||||
}
|
||||
req.send(options.body);
|
||||
});
|
||||
|
||||
return { message: rpcErrorMessage };
|
||||
}
|
||||
|
||||
return { message };
|
||||
}
|
||||
|
||||
export function getMessageFromResponse(response) {
|
||||
return getErrorFromResponse(response).message || "Something went wrong";
|
||||
}
|
||||
|
||||
export function responseOk(response) {
|
||||
if (response.status !== RequestStatus.OK) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
export default function doRequest(method, endpoint, auth=true, body=null) {
|
||||
|
@ -83,31 +120,45 @@ export default function doRequest(method, endpoint, auth=true, body=null) {
|
|||
}
|
||||
}
|
||||
|
||||
let res;
|
||||
try {
|
||||
const res = await compatibleFetch(endpoint, options);
|
||||
const json = res.status === 204 ? {} : await res.json();
|
||||
|
||||
res = await fetch(endpoint, options);
|
||||
} catch(o_O) {
|
||||
return resolve({
|
||||
json,
|
||||
ok: res.ok,
|
||||
});
|
||||
} catch (e) {
|
||||
return resolve({
|
||||
json: null,
|
||||
ok: false,
|
||||
status: RequestStatus.NETWORK_EXCEPTION
|
||||
});
|
||||
}
|
||||
|
||||
let json;
|
||||
try {
|
||||
json = res.status === 204 ? {} : await res.json();
|
||||
} catch(o_O) {
|
||||
return resolve({
|
||||
status: RequestStatus.JSON_EXCEPTION
|
||||
});
|
||||
}
|
||||
|
||||
resolve({
|
||||
data: json,
|
||||
status: res.ok ? RequestStatus.OK : RequestStatus.FAILURE_STATUS
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function remoteCall({methodId, requiresAuthentication, cacheable, _isSignal=false}, ...args) {
|
||||
const calls = [[methodId, ...args]];
|
||||
|
||||
if (requiresAuthentication && gateway.authenticated && !cacheable) {
|
||||
const replies = await gateway.sendRPCRequest(calls, _isSignal);
|
||||
const ok = Array.isArray(replies) && !(replies[0] && replies[0].code);
|
||||
if (!Array.isArray(replies) || replies.length !== 1) {
|
||||
return { status: RequestStatus.INVARIANT_RPC_RESPONSE_COUNT };
|
||||
}
|
||||
|
||||
const reply = replies[0];
|
||||
|
||||
return {
|
||||
json: ok ? replies[0] : null,
|
||||
ok
|
||||
data: reply,
|
||||
status: reply && reply.code ? RequestStatus.RPC_ERROR : RequestStatus.OK
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -117,9 +168,21 @@ export async function remoteCall({methodId, requiresAuthentication, cacheable, _
|
|||
} else {
|
||||
response = await doRequest("POST", apiRoute("rpc"), requiresAuthentication, calls);
|
||||
}
|
||||
response.ok = response.ok && Array.isArray(response.json) && !(response.json[0] && response.json[0].code);
|
||||
response.json = response.ok ? response.json[0] : null;
|
||||
return response;
|
||||
|
||||
if (response.status !== RequestStatus.OK) {
|
||||
return { status: response.status };
|
||||
}
|
||||
|
||||
if (!Array.isArray(response.data) || response.data.length !== 1) {
|
||||
return { status: RequestStatus.INVARIANT_RPC_RESPONSE_COUNT };
|
||||
}
|
||||
|
||||
const reply = response.data[0];
|
||||
|
||||
return {
|
||||
data: reply,
|
||||
status: reply && reply.code ? RequestStatus.RPC_ERROR : RequestStatus.OK
|
||||
};
|
||||
}
|
||||
|
||||
export async function remoteSignal(method, ...args) {
|
||||
|
@ -131,14 +194,22 @@ export async function remoteSignal(method, ...args) {
|
|||
|
||||
export async function remoteBlobUpload({methodId, requiresAuthentication, _isSignal=false}, blob) {
|
||||
const calls = [[methodId, [0, blob.size]]];
|
||||
|
||||
if (requiresAuthentication && gateway.authenticated) {
|
||||
const replies = await gateway.sendRPCRequest(calls, _isSignal, blob);
|
||||
const ok = Array.isArray(replies) && !(replies[0] && replies[0].code);
|
||||
if (!Array.isArray(replies) || replies.length !== 1) {
|
||||
return { status: RequestStatus.INVARIANT_RPC_RESPONSE_COUNT };
|
||||
}
|
||||
|
||||
const reply = replies[0];
|
||||
|
||||
return {
|
||||
json: ok ? replies[0] : null,
|
||||
ok
|
||||
data: reply,
|
||||
status: reply && reply.code ? RequestStatus.RPC_ERROR : RequestStatus.OK
|
||||
};
|
||||
} else {
|
||||
return { json: null, ok: false };
|
||||
return {
|
||||
status: RequestStatus.NETWORK_EXCEPTION
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import gateway, { GatewayEventType, GatewayPayloadType, GatewayPresenceStatus } from "./gateway";
|
||||
import logger from "./logging";
|
||||
import { methods, remoteCall, remoteSignal } from "./request";
|
||||
import { getMessageFromResponse, methods, remoteCall, remoteSignal, responseOk } from "./request";
|
||||
import { getItem, setItem } from "./storage";
|
||||
|
||||
const storeLog = logger("Store");
|
||||
|
@ -335,17 +335,17 @@ class MessageStore extends Store {
|
|||
|
||||
const oldestMessage = this.value[0];
|
||||
const res = await remoteCall(methods.getChannelMessages, this.channelId, null, oldestMessage ? oldestMessage.id : null);
|
||||
if (res.ok) {
|
||||
if (res.json.length < 1)
|
||||
if (responseOk(res)) {
|
||||
if (res.data.length < 1)
|
||||
return;
|
||||
if (beforeCommitToStore)
|
||||
beforeCommitToStore(res.json);
|
||||
res.json.reverse();
|
||||
this.value = res.json.concat(this.value);
|
||||
beforeCommitToStore(res.data);
|
||||
res.data.reverse();
|
||||
this.value = res.data.concat(this.value);
|
||||
this._recomputeMessages();
|
||||
this.updated();
|
||||
} else {
|
||||
overlayStore.toast("Messages failed to load");
|
||||
overlayStore.toast(`Messages failed to load: ${getMessageFromResponse(res)}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -877,11 +877,11 @@ export const sendMessageAction = createAction("sendMessageAction", async ({chann
|
|||
|
||||
const res = await remoteSignal(methods.createChannelMessage, channelId, content, optimisticMessageId, null);
|
||||
|
||||
if (!res.ok) {
|
||||
if (!responseOk(res)) {
|
||||
messagesStoreForChannel.deleteMessage({
|
||||
id: optimisticMessageId
|
||||
});
|
||||
overlayStore.toast("Couldn't send message");
|
||||
overlayStore.toast(`Couldn't send message: ${getMessageFromResponse(res)}`);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue