This repository has been archived on 2023-03-18. You can view files and clone it, but cannot push or open issues or pull requests.
osr-discourse-src/plugins/chat/assets/javascripts/discourse/services/chat-api.js
Joffrey JAFFEUX cb2f684a43
FIX: correctly always return a promise from loadMore (#19676)
This commit also fixes an issue where `loading = false` was never called when the server had nothing new to return.
2023-01-02 15:55:45 +01:00

241 lines
5.6 KiB
JavaScript

import Service, { inject as service } from "@ember/service";
import { ajax } from "discourse/lib/ajax";
import UserChatChannelMembership from "discourse/plugins/chat/discourse/models/user-chat-channel-membership";
import { tracked } from "@glimmer/tracking";
import { bind } from "discourse-common/utils/decorators";
import { Promise } from "rsvp";
class Collection {
@tracked items = [];
@tracked meta = {};
@tracked loading = false;
constructor(resourceURL, handler) {
this._resourceURL = resourceURL;
this._handler = handler;
this._fetchedAll = false;
}
get loadMoreURL() {
return this.meta.load_more_url;
}
get totalRows() {
return this.meta.total_rows;
}
get length() {
return this.items.length;
}
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols
[Symbol.iterator]() {
let index = 0;
return {
next: () => {
if (index < this.items.length) {
return { value: this.items[index++], done: false };
} else {
return { done: true };
}
},
};
}
@bind
load(params = {}) {
this._fetchedAll = false;
if (this.loading) {
return;
}
this.loading = true;
const filteredQueryParams = Object.entries(params).filter(
([, v]) => v !== undefined
);
const queryString = new URLSearchParams(filteredQueryParams).toString();
const endpoint = this._resourceURL + (queryString ? `?${queryString}` : "");
return this.#fetch(endpoint)
.then((result) => {
this.items = this._handler(result);
this.meta = result.meta;
})
.finally(() => {
this.loading = false;
});
}
@bind
loadMore() {
let promise = Promise.resolve();
if (this.loading) {
return promise;
}
if (
this._fetchedAll ||
(this.totalRows && this.items.length >= this.totalRows)
) {
return promise;
}
this.loading = true;
if (this.loadMoreURL) {
promise = this.#fetch(this.loadMoreURL).then((result) => {
const newItems = this._handler(result);
if (newItems.length) {
this.items = this.items.concat(newItems);
} else {
this._fetchedAll = true;
}
this.meta = result.meta;
});
}
return promise.finally(() => {
this.loading = false;
});
}
#fetch(url) {
return ajax(url, { type: "GET" });
}
}
export default class ChatApi extends Service {
@service chatChannelsManager;
getChannel(channelId) {
return this.#getRequest(`/channels/${channelId}`).then((result) =>
this.chatChannelsManager.store(result.channel)
);
}
channels() {
return new Collection(`${this.#basePath}/channels`, (response) => {
return response.channels.map((channel) =>
this.chatChannelsManager.store(channel)
);
});
}
moveChannelMessages(channelId, data = {}) {
return this.#postRequest(`/channels/${channelId}/messages/moves`, {
move: data,
});
}
destroyChannel(channelId, data = {}) {
return this.#deleteRequest(`/channels/${channelId}`, { channel: data });
}
createChannel(data = {}) {
return this.#postRequest("/channels", { channel: data }).then((response) =>
this.chatChannelsManager.store(response.channel)
);
}
categoryPermissions(categoryId) {
return ajax(`/chat/api/category-chatables/${categoryId}/permissions`);
}
sendMessage(channelId, data = {}) {
return ajax(`/chat/${channelId}`, {
ignoreUnsent: false,
type: "POST",
data,
});
}
createChannelArchive(channelId, data = {}) {
return this.#postRequest(`/channels/${channelId}/archives`, {
archive: data,
});
}
updateChannel(channelId, data = {}) {
return this.#putRequest(`/channels/${channelId}`, { channel: data });
}
updateChannelStatus(channelId, status) {
return this.#putRequest(`/channels/${channelId}/status`, { status });
}
listChannelMemberships(channelId) {
return new Collection(
`${this.#basePath}/channels/${channelId}/memberships`,
(response) => {
return response.memberships.map((membership) =>
UserChatChannelMembership.create(membership)
);
}
);
}
listCurrentUserChannels() {
return this.#getRequest(`/channels/me`).then((result) => {
return (result?.channels || []).map((channel) =>
this.chatChannelsManager.store(channel)
);
});
}
followChannel(channelId) {
return this.#postRequest(`/channels/${channelId}/memberships/me`).then(
(result) => UserChatChannelMembership.create(result.membership)
);
}
unfollowChannel(channelId) {
return this.#deleteRequest(`/channels/${channelId}/memberships/me`).then(
(result) => UserChatChannelMembership.create(result.membership)
);
}
updateCurrentUserChatChannelNotificationsSettings(channelId, data = {}) {
return this.#putRequest(
`/channels/${channelId}/notifications-settings/me`,
{ notifications_settings: data }
);
}
get #basePath() {
return "/chat/api";
}
#getRequest(endpoint, data = {}) {
return ajax(`${this.#basePath}${endpoint}`, {
type: "GET",
data,
});
}
#putRequest(endpoint, data = {}) {
return ajax(`${this.#basePath}${endpoint}`, {
type: "PUT",
data,
});
}
#postRequest(endpoint, data = {}) {
return ajax(`${this.#basePath}${endpoint}`, {
type: "POST",
data,
});
}
#deleteRequest(endpoint, data = {}) {
return ajax(`${this.#basePath}${endpoint}`, {
type: "DELETE",
data,
});
}
}