show collections
This commit is contained in:
@ -10,6 +10,9 @@
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<div>
|
||||
<collections-list aw-endpoint="https://aw.sa.vin/v1" aw-project="62f5ccd6af025a76edb0"></collections-list>
|
||||
</div>
|
||||
|
||||
<script src="/src/index.tsx" type="module"></script>
|
||||
</body>
|
||||
|
@ -4,7 +4,10 @@
|
||||
"description": "UI that generates itself based on the shape of a given Appwrite project.",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"start": "vite",
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"serve": "vite preview"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -24,7 +27,8 @@
|
||||
"vite-plugin-solid": "^2.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"node-appwrite": "^7.0.2",
|
||||
"appwrite": "^9.0.1",
|
||||
"rxjs": "^7.5.6",
|
||||
"solid-element": "^1.4.8",
|
||||
"solid-js": "^1.4.7"
|
||||
}
|
||||
|
94
pnpm-lock.yaml
generated
94
pnpm-lock.yaml
generated
@ -1,7 +1,8 @@
|
||||
lockfileVersion: 5.4
|
||||
|
||||
specifiers:
|
||||
node-appwrite: ^7.0.2
|
||||
appwrite: ^9.0.1
|
||||
rxjs: ^7.5.6
|
||||
solid-element: ^1.4.8
|
||||
solid-js: ^1.4.7
|
||||
typescript: ^4.7.4
|
||||
@ -9,7 +10,8 @@ specifiers:
|
||||
vite-plugin-solid: ^2.3.0
|
||||
|
||||
dependencies:
|
||||
node-appwrite: 7.0.2
|
||||
appwrite: 9.0.1
|
||||
rxjs: 7.5.6
|
||||
solid-element: 1.4.8_solid-js@1.4.8
|
||||
solid-js: 1.4.8
|
||||
|
||||
@ -387,17 +389,17 @@ packages:
|
||||
color-convert: 1.9.3
|
||||
dev: true
|
||||
|
||||
/asynckit/0.4.0:
|
||||
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
||||
/appwrite/9.0.1:
|
||||
resolution: {integrity: sha512-yLxb5H2fqlK0l4q6eEzrb5HGs3xA2894wcLIseOJ2v/iqUmjuIjXfLUpWG+DC94CQmEdZCxwvIFUVO/AG/t+cw==}
|
||||
dependencies:
|
||||
cross-fetch: 3.1.5
|
||||
isomorphic-form-data: 2.0.0
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
dev: false
|
||||
|
||||
/axios/0.27.2:
|
||||
resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==}
|
||||
dependencies:
|
||||
follow-redirects: 1.15.1
|
||||
form-data: 4.0.0
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
/asynckit/0.4.0:
|
||||
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
||||
dev: false
|
||||
|
||||
/babel-plugin-jsx-dom-expressions/0.33.14_@babel+core@7.18.10:
|
||||
@ -472,6 +474,14 @@ packages:
|
||||
safe-buffer: 5.1.2
|
||||
dev: true
|
||||
|
||||
/cross-fetch/3.1.5:
|
||||
resolution: {integrity: sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==}
|
||||
dependencies:
|
||||
node-fetch: 2.6.7
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
dev: false
|
||||
|
||||
/debug/4.3.4:
|
||||
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
|
||||
engines: {node: '>=6.0'}
|
||||
@ -712,19 +722,9 @@ packages:
|
||||
engines: {node: '>=0.8.0'}
|
||||
dev: true
|
||||
|
||||
/follow-redirects/1.15.1:
|
||||
resolution: {integrity: sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==}
|
||||
engines: {node: '>=4.0'}
|
||||
peerDependencies:
|
||||
debug: '*'
|
||||
peerDependenciesMeta:
|
||||
debug:
|
||||
optional: true
|
||||
dev: false
|
||||
|
||||
/form-data/4.0.0:
|
||||
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
|
||||
engines: {node: '>= 6'}
|
||||
/form-data/2.5.1:
|
||||
resolution: {integrity: sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==}
|
||||
engines: {node: '>= 0.12'}
|
||||
dependencies:
|
||||
asynckit: 0.4.0
|
||||
combined-stream: 1.0.8
|
||||
@ -780,6 +780,12 @@ packages:
|
||||
engines: {node: '>=12.13'}
|
||||
dev: true
|
||||
|
||||
/isomorphic-form-data/2.0.0:
|
||||
resolution: {integrity: sha512-TYgVnXWeESVmQSg4GLVbalmQ+B4NPi/H4eWxqALKj63KsUrcu301YDjBqaOw3h+cbak7Na4Xyps3BiptHtxTfg==}
|
||||
dependencies:
|
||||
form-data: 2.5.1
|
||||
dev: false
|
||||
|
||||
/js-tokens/4.0.0:
|
||||
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
||||
dev: true
|
||||
@ -826,13 +832,16 @@ packages:
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/node-appwrite/7.0.2:
|
||||
resolution: {integrity: sha512-qFahgNKk0qfzoL8/a2v1p/9+EsEuKNutxZqZSlweYi5q4jK3jJDcQZyoPI+B76zmLbYpk7q0zO5LrbfVVkI/kg==}
|
||||
/node-fetch/2.6.7:
|
||||
resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==}
|
||||
engines: {node: 4.x || >=6.0.0}
|
||||
peerDependencies:
|
||||
encoding: ^0.1.0
|
||||
peerDependenciesMeta:
|
||||
encoding:
|
||||
optional: true
|
||||
dependencies:
|
||||
axios: 0.27.2
|
||||
form-data: 4.0.0
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
whatwg-url: 5.0.0
|
||||
dev: false
|
||||
|
||||
/node-releases/2.0.6:
|
||||
@ -873,6 +882,12 @@ packages:
|
||||
fsevents: 2.3.2
|
||||
dev: true
|
||||
|
||||
/rxjs/7.5.6:
|
||||
resolution: {integrity: sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw==}
|
||||
dependencies:
|
||||
tslib: 2.4.0
|
||||
dev: false
|
||||
|
||||
/safe-buffer/5.1.2:
|
||||
resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
|
||||
dev: true
|
||||
@ -927,10 +942,18 @@ packages:
|
||||
engines: {node: '>=4'}
|
||||
dev: true
|
||||
|
||||
/tr46/0.0.3:
|
||||
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
||||
dev: false
|
||||
|
||||
/ts-toolbelt/9.6.0:
|
||||
resolution: {integrity: sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==}
|
||||
dev: true
|
||||
|
||||
/tslib/2.4.0:
|
||||
resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==}
|
||||
dev: false
|
||||
|
||||
/typescript/4.7.4:
|
||||
resolution: {integrity: sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==}
|
||||
engines: {node: '>=4.2.0'}
|
||||
@ -991,3 +1014,14 @@ packages:
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.2
|
||||
dev: true
|
||||
|
||||
/webidl-conversions/3.0.1:
|
||||
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
||||
dev: false
|
||||
|
||||
/whatwg-url/5.0.0:
|
||||
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
|
||||
dependencies:
|
||||
tr46: 0.0.3
|
||||
webidl-conversions: 3.0.1
|
||||
dev: false
|
||||
|
1
src/components.tsx
Normal file
1
src/components.tsx
Normal file
@ -0,0 +1 @@
|
||||
import './components/collections';
|
51
src/components/collections.tsx
Normal file
51
src/components/collections.tsx
Normal file
@ -0,0 +1,51 @@
|
||||
import {createSignal, onMount} from "solid-js";
|
||||
import { customElement } from "solid-element";
|
||||
import {awService} from "../services/aw-service";
|
||||
import {Attribute, Collection, CollectionsList} from "./types";
|
||||
|
||||
const style = ``;
|
||||
|
||||
const defaultProps = {
|
||||
awEndpoint: "localhost:80/v1",
|
||||
awProject: "",
|
||||
styles: "",
|
||||
};
|
||||
|
||||
customElement("collections-list", defaultProps, (props) => {
|
||||
const [collections, setCollections] = createSignal<CollectionsList>();
|
||||
awService.init(props.awEndpoint, props.awProject);
|
||||
|
||||
let customStyles;
|
||||
try {
|
||||
customStyles = props.styles;
|
||||
} catch(e) {
|
||||
customStyles = '';
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
awService.getCollections().subscribe((collection: CollectionsList) => {
|
||||
setCollections(collection);
|
||||
});
|
||||
});
|
||||
|
||||
return (
|
||||
<div class={'collections-frame'}>
|
||||
<style>{style}</style>
|
||||
<style>{customStyles}</style>
|
||||
{/*<span>{JSON.stringify(collections(), null, " ")}</span>*/}
|
||||
{collections()?.collections.map((col: Collection) => {
|
||||
return <div>
|
||||
<h3>{col.name}</h3>
|
||||
<span>{col.$id}</span><br></br>
|
||||
{
|
||||
col.attributes.map((attr: Attribute) => {
|
||||
return <div>
|
||||
<span>{attr.key + ", " + attr.type}</span>
|
||||
</div>;
|
||||
})
|
||||
}
|
||||
</div>;
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
});
|
28
src/components/types.ts
Normal file
28
src/components/types.ts
Normal file
@ -0,0 +1,28 @@
|
||||
export interface CollectionsList {
|
||||
collections: Collection[]
|
||||
total: number
|
||||
}
|
||||
|
||||
export interface Collection {
|
||||
$id: string
|
||||
$createdAt: number
|
||||
$updatedAt: number
|
||||
$read: string[]
|
||||
$write: string[]
|
||||
databaseId: string
|
||||
name: string
|
||||
enabled: boolean
|
||||
permission: string
|
||||
attributes: Attribute[]
|
||||
}
|
||||
|
||||
export interface Attribute {
|
||||
key: string
|
||||
type: string
|
||||
status: string
|
||||
required: boolean
|
||||
array: boolean
|
||||
size: number
|
||||
default: any
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
/* @refresh reload */
|
||||
import { render } from 'solid-js/web';
|
||||
// import { render } from 'solid-js/web';
|
||||
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
// import App from './App';
|
||||
|
||||
render(() => <App />, document.getElementById('root') as HTMLElement);
|
||||
import './components';
|
||||
|
||||
// render(() => <App />, document.getElementById('root') as HTMLElement);
|
||||
|
82
src/services/aw-service.ts
Normal file
82
src/services/aw-service.ts
Normal file
@ -0,0 +1,82 @@
|
||||
import { Observable } from 'rxjs';
|
||||
import {ObserveCache} from "./observeCache";
|
||||
import {Account, Client, Functions, Models} from 'appwrite';
|
||||
import {CollectionsList} from "../components/types";
|
||||
|
||||
class AWService {
|
||||
private awEndpoint: string = "";
|
||||
private awProject: string = "";
|
||||
private readonly awClient: Client;
|
||||
private collectionsObserveCache: ObserveCache<CollectionsList> = new ObserveCache<CollectionsList>();
|
||||
|
||||
constructor() {
|
||||
this.awClient = new Client();
|
||||
}
|
||||
|
||||
public getCollections(): Observable<CollectionsList> {
|
||||
let collectionRequest: () => Promise<CollectionsList> = () => {
|
||||
let account = new Account(this.awClient);
|
||||
let functions = new Functions(this.awClient);
|
||||
|
||||
return account.get().then(() => {
|
||||
return functions.createExecution("getCollections")
|
||||
}).then((executionInfo: Models.Execution) => {
|
||||
return waitForCompletion();
|
||||
|
||||
async function waitForCompletion(): Promise<Models.Execution> {
|
||||
let complete = false;
|
||||
let exec: Models.Execution = await getExec();
|
||||
if (exec.status !== "processing") {
|
||||
complete = true;
|
||||
}
|
||||
while (!complete) {
|
||||
exec = await delay();
|
||||
if (exec.status !== "processing") {
|
||||
complete = true;
|
||||
}
|
||||
}
|
||||
return exec;
|
||||
}
|
||||
|
||||
async function delay(): Promise<Models.Execution> {
|
||||
return new Promise<Models.Execution>((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
getExec().then((exec: Models.Execution) => {
|
||||
resolve(exec);
|
||||
});
|
||||
}, 2000);
|
||||
})
|
||||
}
|
||||
|
||||
function getExec(): Promise<Models.Execution> {
|
||||
return functions.getExecution("getCollections", executionInfo.$id);
|
||||
}
|
||||
}).then((ex: Models.Execution) => {
|
||||
return JSON.parse(ex.response) as CollectionsList;
|
||||
}).catch((err) => {
|
||||
console.error(err);
|
||||
return {collections: [], total: 0};
|
||||
});
|
||||
}
|
||||
return this.collectionsObserveCache.get('collections', collectionRequest);
|
||||
}
|
||||
|
||||
public init(endpoint: string, project: string) {
|
||||
if (this.awEndpoint === "") {
|
||||
this.awEndpoint = endpoint;
|
||||
this.awClient.setEndpoint(endpoint);
|
||||
}
|
||||
if (this.awProject === "") {
|
||||
this.awProject = project;
|
||||
this.awClient.setProject(project);
|
||||
}
|
||||
// otherwise we have already been initialized, and we don't need to do anything
|
||||
}
|
||||
}
|
||||
|
||||
const awService = new AWService();
|
||||
|
||||
export {
|
||||
awService
|
||||
// AWService
|
||||
}
|
100
src/services/fetch.ts
Normal file
100
src/services/fetch.ts
Normal file
@ -0,0 +1,100 @@
|
||||
declare var window: any;
|
||||
const defaultBasePath = '';
|
||||
|
||||
export function fetchAsync(method: 'GET' | 'POST' | 'DELETE' | 'PUT', url: string, body?: any) {
|
||||
const headers = { 'Content-Type': 'application/json; charset=utf-8' };
|
||||
// if (access_token) headers['Authorization'] = `Token ${access_token}`;
|
||||
return window.fetch(`${defaultBasePath}${url}`, {
|
||||
method,
|
||||
headers,
|
||||
body: body && JSON.stringify(body)
|
||||
}).then((response: any) => {
|
||||
// if (response.status === 401) {
|
||||
// window.location.href = '/auth/login';
|
||||
// // throw new Error('401');
|
||||
// }
|
||||
// if (response.status === 403 && url === '/api/v1/organization/') {
|
||||
// // this indicates a user that is not supposed to be in bx-console
|
||||
// window.location.href = '/auth/logout';
|
||||
// }
|
||||
const result = response.json();
|
||||
if (!response.ok) throw result;
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
export function get<T>(url: string): Promise<T> {
|
||||
return fetchAsync('GET', url);
|
||||
}
|
||||
|
||||
export function post<T>(url: string, body?: any): Promise<T> {
|
||||
return fetchAsync('POST', url, body);
|
||||
}
|
||||
|
||||
export function postWithFile<T>(url: string, body?: any): Promise<T> {
|
||||
return fetchWithFile('POST', url, body);
|
||||
}
|
||||
|
||||
export function putWithFile<T>(url: string, body?: any): Promise<T> {
|
||||
return fetchWithFile('PUT', url, body);
|
||||
}
|
||||
|
||||
export function fetchWithFile<T>(method: string, url: string, body?: any): Promise<T> {
|
||||
return window.fetch(`${defaultBasePath}${url}`, {
|
||||
method: method,
|
||||
body: body
|
||||
}).then((response: any) => {
|
||||
if (response.status === 401) {
|
||||
window.location.href = '/auth/login';
|
||||
// throw new Error('401');
|
||||
}
|
||||
const result = response.json();
|
||||
if (!response.ok) throw result;
|
||||
return result;
|
||||
})
|
||||
}
|
||||
|
||||
export function del(url: string) {
|
||||
return fetchAsync('DELETE', url);
|
||||
}
|
||||
|
||||
export function put(url: string, body?: any) {
|
||||
return fetchAsync('PUT', url, body);
|
||||
}
|
||||
export function toQueryString(obj: any) {
|
||||
const parts = [];
|
||||
for (var i in obj) {
|
||||
if (obj.hasOwnProperty(i)) {
|
||||
parts.push(encodeURIComponent(i) + "=" + encodeURIComponent(obj[i]));
|
||||
}
|
||||
}
|
||||
return parts.join("&");
|
||||
}
|
||||
|
||||
export function serializeObject<T>(form: any) {
|
||||
let obj: {[key: string]: any} = {};
|
||||
if (typeof form == 'object' && form.nodeName == "FORM") {
|
||||
for (let i = 0; i < form.elements.length; i++) {
|
||||
const field = form.elements[i];
|
||||
if (field.name
|
||||
&& field.type != 'file'
|
||||
&& field.type != 'reset'
|
||||
&& field.type != 'submit'
|
||||
&& field.type != 'button') {
|
||||
if (field.type == 'select-multiple') {
|
||||
obj[field.name] = '';
|
||||
let tempvalue = '';
|
||||
for (let j = 0; j < form.elements[i].options.length; j++) {
|
||||
if (field.options[j].selected)
|
||||
tempvalue += field.options[j].value + ';';
|
||||
}
|
||||
if (tempvalue.charAt(tempvalue.length - 1) === ';') obj[field.name] = tempvalue.substring(0, tempvalue.length - 1);
|
||||
|
||||
} else if ((field.type != 'checkbox' && field.type != 'radio') || field.checked) {
|
||||
obj[field.name] = field.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return obj as T;
|
||||
}
|
43
src/services/observeCache.ts
Normal file
43
src/services/observeCache.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import { Observable, from } from 'rxjs';
|
||||
import { get } from './fetch';
|
||||
import { ObserveService } from './observeService';
|
||||
|
||||
interface storedItem<T> {
|
||||
observeService: ObserveService<T>
|
||||
bust: boolean
|
||||
updated: number
|
||||
}
|
||||
|
||||
class ObserveCache<T> {
|
||||
private cacheStore: { [key: string]: storedItem<T> } = {};
|
||||
private expiration: number = 5 * 60 * 1000; // 5 minutes
|
||||
|
||||
public get(key: string, endpoint: string|(()=>Promise<T>)) {
|
||||
let now = new Date().getTime();
|
||||
if (!this.cacheStore[key]) {
|
||||
function getRequest() {
|
||||
if (typeof endpoint === 'string') {
|
||||
return from<Promise<T>>(get<T>(endpoint));
|
||||
}
|
||||
return from<Promise<T>>(endpoint());
|
||||
}
|
||||
this.cacheStore[key] = {
|
||||
observeService: new ObserveService<T>(getRequest),
|
||||
bust: false,
|
||||
updated: now,
|
||||
};
|
||||
} else if (this.cacheStore[key].bust || now - this.cacheStore[key].updated > this.expiration) {
|
||||
this.cacheStore[key].observeService.next();
|
||||
this.cacheStore[key].updated = now;
|
||||
}
|
||||
return this.cacheStore[key].observeService.value$;
|
||||
}
|
||||
|
||||
public bust(key: string) {
|
||||
this.cacheStore[key].bust = true;
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
ObserveCache
|
||||
}
|
19
src/services/observeService.ts
Normal file
19
src/services/observeService.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import {merge, Observable, Subject} from 'rxjs';
|
||||
import {debounceTime, shareReplay, switchMap} from 'rxjs/operators';
|
||||
|
||||
export class ObserveService<T> {
|
||||
private updateStream: Subject<void>;
|
||||
public value$: Observable<T>;
|
||||
// TODO: add timestamp for last updated so the cache can be smart about when to check for new values
|
||||
|
||||
constructor(request: ()=>Observable<T>) {
|
||||
this.updateStream = new Subject<void>();
|
||||
const initialCurrentResponse$ = request();
|
||||
const reload$ = this.updateStream.pipe(debounceTime(1000), switchMap(() => request()));
|
||||
this.value$ = merge(initialCurrentResponse$, reload$).pipe(shareReplay(1));
|
||||
}
|
||||
|
||||
public next() {
|
||||
this.updateStream.next();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user