|
- import { Component, h, Fragment, createRef } from 'preact';
- import { RpcClient } from 'webextension-rpc';
- import type { backgroundRpcServer } from '../background';
- import { AnnotationSource } from '../storage/AnnotationSource';
- import classes from './AnnotationSourcesList.module.scss';
- import cls from 'classnames';
- import niceTime from '../util/niceTime';
- import { Annotation } from '../storage/Annotation';
- import { AnnotationsList } from './AnnotationsList';
- import infoIcon from '../assets/icons/info.svg';
- import rssIcon from '../assets/icons/rss.svg';
-
- const backgroundRpc = new RpcClient<typeof backgroundRpcServer>();
-
- // Run refresh in the background: should continue if the page/popup is closed.
- const refreshAnnotationSource = backgroundRpc.func('refreshAnnotationSource');
- const refreshAnnotationSources = backgroundRpc.func('refreshAnnotationSources');
-
- interface AnnotationSourcesListProps {
- withAnnotations?: boolean;
- }
-
- interface AnnotationSourcesListState {
- sources?: AnnotationSource[];
- totalAnnotationCount?: number;
- }
-
- export class AnnotationSourcesList extends Component<
- AnnotationSourcesListProps,
- AnnotationSourcesListState
- > {
- state: AnnotationSourcesListState = {};
-
- refreshButton = createRef<HTMLButtonElement>();
-
- async componentDidMount() {
- await this.loadData();
- }
-
- async loadData() {
- this.setState({
- sources: await AnnotationSource.getAll(),
- // sources: await AnnotationSource.getActiveSources(),
- totalAnnotationCount: await Annotation.count(),
- });
- }
-
- refreshAll = async () => {
- const button = this.refreshButton.current!;
- try {
- button.classList.add(classes.loading);
- button.disabled = true;
- await refreshAnnotationSources({ forceAll: true });
- await this.loadData();
- } catch (error) {
- alert(`Refreshing failed: ${error}`);
- throw error;
- } finally {
- button.disabled = false;
- button.classList.remove(classes.loading);
- }
- };
-
- refreshSource = async (source: AnnotationSource) => {
- try {
- await refreshAnnotationSource(source.data, true);
- } catch (error) {
- alert(`Refreshing failed: ${error}`);
- }
- await this.loadData();
- };
-
- removeSource = async (source: AnnotationSource) => {
- await source.delete();
- await this.loadData();
- };
-
- render(
- { withAnnotations }: AnnotationSourcesListProps,
- { sources }: AnnotationSourcesListState,
- ) {
- const sourceList = sources?.map((source) => (
- <li
- key={source.data._id}
- class={cls(classes.source, { [classes.active]: source.data.active })}
- >
- <div class={classes.infoAndButtons}>
- <div class={classes.info}>
- <div class={classes.title}>
- {source.data.active && (
- <>
- <img src={rssIcon} />{' '}
- </>
- )}
- “{source.data.title}”
- </div>
- <div class={classes.url}>
- {source.data.active ? 'Feed: ' : 'Source: '}
- <a href={source.data.url} target="_blank">
- {source.data.url}
- </a>
- </div>{' '}
- <div class={classes.lastUpdate}>
- {source.data.active ? 'Last update: ' : 'Imported: '}
- {source.data.lastUpdate ? niceTime(source.data.lastUpdate) : '?'}
- {source.data.active || (
- <small> (this source is not refreshed automatically)</small>
- )}
- </div>
- </div>
- <div class={classes.buttons}>
- <button
- class={classes.button}
- onClick={(e) => this.removeSource(source)}
- >
- ❌ Remove
- </button>
- <button
- class={classes.button}
- onClick={(e) => this.refreshSource(source)}
- title={
- source.data.type === 'embeddedJsonld'
- ? `To refresh annotations embedded in a page, first open that page again.`
- : undefined
- }
- >
- 🗘 Refresh
- {source.data.type === 'embeddedJsonld' && (
- <>
- {' '}
- <img src={infoIcon} />
- </>
- )}
- </button>
- </div>
- </div>
- {withAnnotations && (
- <details class={classes.showAnnotations} open>
- <summary>Stored annotations from this source</summary>
- <div style="margin-left: 2em;">
- <AnnotationsList source={source.data} />
- </div>
- </details>
- )}
- </li>
- ));
-
- return (
- <div>
- {sourceList ? (
- <ul class={classes.sourceList}>{sourceList}</ul>
- ) : (
- <p>
- <i>Loading list of sources…</i>
- </p>
- )}
- <div style="display: flex; align-items: center;">
- <div style="flex-grow: 1;">
- Total number of annotations:{' '}
- {this.state.totalAnnotationCount ?? <i>'counting…'</i>}
- </div>
- <button
- class={classes.button}
- ref={this.refreshButton}
- onClick={this.refreshAll}
- >
- 🗘 Refresh all sources
- </button>
- </div>
- </div>
- );
- }
- }
|