mirror of
https://github.com/discourse/discourse.git
synced 2025-05-25 19:29:34 +08:00

This PR is a first step towards private groups. It redesigns settings/members area of a channel and also drops the "about" page which is now mixed into settings. This commit is also: - introducing chat-form, a small DSL to create forms, ideally I would want something in core for this - introducing a DToggleSwitch page object component to simplify testing toggles - migrating various components to gjs
101 lines
2.2 KiB
JavaScript
101 lines
2.2 KiB
JavaScript
import { ajax } from "discourse/lib/ajax";
|
|
import { tracked } from "@glimmer/tracking";
|
|
import { bind } from "discourse-common/utils/decorators";
|
|
import { Promise } from "rsvp";
|
|
|
|
/**
|
|
* Handles a paginated API response.
|
|
*/
|
|
export default class Collection {
|
|
@tracked items = [];
|
|
@tracked meta = {};
|
|
@tracked loading = false;
|
|
@tracked fetchedOnce = false;
|
|
|
|
constructor(resourceURL, handler, params = {}) {
|
|
this._resourceURL = resourceURL;
|
|
this._handler = handler;
|
|
this._params = params;
|
|
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.length) {
|
|
return { value: this.items[index++], done: false };
|
|
} else {
|
|
return { done: true };
|
|
}
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Loads first batch of results
|
|
* @returns {Promise}
|
|
*/
|
|
@bind
|
|
load(params = {}) {
|
|
if (
|
|
this.loading ||
|
|
this._fetchedAll ||
|
|
(this.totalRows && this.items.length >= this.totalRows)
|
|
) {
|
|
return Promise.resolve();
|
|
}
|
|
|
|
this.loading = true;
|
|
|
|
let endpoint;
|
|
if (this.loadMoreURL) {
|
|
endpoint = this.loadMoreURL;
|
|
} else {
|
|
const filteredQueryParams = Object.entries(params).filter(
|
|
([, v]) => v !== undefined
|
|
);
|
|
|
|
const queryString = new URLSearchParams(filteredQueryParams).toString();
|
|
endpoint = this._resourceURL + (queryString ? `?${queryString}` : "");
|
|
}
|
|
|
|
return this.#fetch(endpoint)
|
|
.then((result) => {
|
|
const items = this._handler(result);
|
|
|
|
if (items.length) {
|
|
this.items = (this.items ?? []).concat(items);
|
|
}
|
|
|
|
if (!items.length || items.length < params.limit) {
|
|
this._fetchedAll = true;
|
|
}
|
|
|
|
this.meta = result.meta;
|
|
this.fetchedOnce = true;
|
|
})
|
|
.finally(() => {
|
|
this.loading = false;
|
|
});
|
|
}
|
|
|
|
#fetch(url) {
|
|
return ajax(url, { type: "GET", data: this._params });
|
|
}
|
|
}
|