personal opening explorer: show indexing status

openingexplorer3
Thibault Duplessis 2021-10-19 10:42:15 +02:00
parent 8139647bdc
commit 2f2807d185
6 changed files with 59 additions and 25 deletions

View File

@ -44,6 +44,11 @@
text-overflow: ellipsis;
user-select: text;
}
.player-loading {
text-align: right;
background: $c-bg-zebra !important;
border-bottom: $border;
}
.empty {
display: flex;

View File

@ -155,7 +155,6 @@ const playerModal = (ctrl: ExplorerConfigCtrl) => {
input,
tag: 'span',
onSelect(v) {
// input.value = v.name;
ctrl.data.playerName.value(v.name);
ctrl.data.playerName.open(false);
ctrl.redraw();

View File

@ -1,6 +1,7 @@
import { prop } from 'common';
import { storedProp } from 'common/storage';
import debounce from 'common/debounce';
import { sync, Sync } from 'common/sync';
import { opposite } from 'chessground/util';
import { controller as configCtrl } from './explorerConfig';
import * as xhr from './explorerXhr';
@ -50,7 +51,7 @@ export default function (root: AnalyseCtrl, opts: ExplorerOpts, allow: boolean):
hovering = prop<Hovering | null>(null),
movesAway = prop(0),
gameMenu = prop<string | null>(null),
lastStream = prop<Promise<CancellableStream> | null>(null);
lastStream = prop<Sync<CancellableStream> | null>(null);
const checkHash = (e?: HashChangeEvent) => {
if ((location.hash === '#explorer' || location.hash === '#opening') && !root.embed) {
@ -88,29 +89,36 @@ export default function (root: AnalyseCtrl, opts: ExplorerOpts, allow: boolean):
root.redraw();
};
const prev = lastStream();
if (prev) prev.then(stream => stream.cancel());
if (prev) prev.promise.then(stream => stream.cancel());
if (withGames && tablebaseRelevant(effectiveVariant, fen))
xhr.tablebase(opts.tablebaseEndpoint, effectiveVariant, fen).then(processData, onError);
else
lastStream(
xhr.opening(
{
endpoint: opts.endpoint,
endpoint3: opts.endpoint3,
db: config.data.db.selected() as ExplorerDb,
personal: {
player: config.data.playerName.value(),
color: root.getOrientation(),
},
variant: effectiveVariant,
rootFen: root.nodeList[0].fen,
play: root.nodeList.slice(1).map(s => s.uci!),
fen,
speeds: config.data.speed.selected(),
ratings: config.data.rating.selected(),
withGames,
},
processData
sync(
xhr
.opening(
{
endpoint: opts.endpoint,
endpoint3: opts.endpoint3,
db: config.data.db.selected() as ExplorerDb,
personal: {
player: config.data.playerName.value(),
color: root.getOrientation(),
},
variant: effectiveVariant,
rootFen: root.nodeList[0].fen,
play: root.nodeList.slice(1).map(s => s.uci!),
fen,
speeds: config.data.speed.selected(),
ratings: config.data.rating.selected(),
withGames,
},
processData
)
.then(stream => {
stream.end.promise.then(root.redraw);
return stream;
})
)
);
},
@ -182,6 +190,10 @@ export default function (root: AnalyseCtrl, opts: ExplorerOpts, allow: boolean):
setNode();
}
},
isIndexing: () => {
const stream = lastStream();
return !!stream && (!stream.sync || !stream.sync.end.sync);
},
fetchMasterOpening: (() => {
const masterCache: Dictionary<OpeningData> = {};
return (fen: Fen): Promise<OpeningData> => {

View File

@ -14,6 +14,7 @@ import {
OpeningMoveStats,
OpeningGame,
Opening,
ExplorerCtrl,
} from './interfaces';
function resultBar(move: OpeningMoveStats): VNode {
@ -79,6 +80,7 @@ function showMoveTable(ctrl: AnalyseCtrl, data: OpeningData): VNode | null {
return h('table.moves', [
h('thead', [
h('tr', [h('th.title', trans('move')), h('th.title', trans('games')), h('th.title', trans('whiteDrawBlack'))]),
playerLoading(ctrl.explorer),
]),
h(
'tbody',
@ -388,6 +390,19 @@ function show(ctrl: AnalyseCtrl): MaybeVNode {
return lastShow;
}
const playerLoading = (explorer: ExplorerCtrl) =>
explorer.config.data.db.selected() == 'player' && explorer.isIndexing()
? h(
'tr',
h('th.title.player-loading', { attrs: { colspan: 3 } }, [
'Indexing ',
h('strong', explorer.config.data.playerName.value()),
' games',
h('i.ddloader'),
])
)
: undefined;
function showTitle(ctrl: AnalyseCtrl, variant: Variant) {
if (variant.key === 'standard' || variant.key === 'fromPosition') return ctrl.trans.noarg('openingExplorer');
return ctrl.trans('xOpeningExplorer', variant.name);

View File

@ -157,6 +157,7 @@ export interface ExplorerCtrl {
disable(): void;
setHovering(fen: Fen, uci: Uci | null): void;
onFlip(): void;
isIndexing: () => boolean;
fetchMasterOpening(fen: Fen): Promise<OpeningData>;
fetchTablebaseHit(fen: Fen): Promise<SimpleTablebaseHit>;
}

View File

@ -1,8 +1,10 @@
import { sync, Sync } from './sync';
export type ProcessLine = (line: any) => void;
export interface CancellableStream {
cancel(): void;
end: Promise<void>;
end: Sync<boolean>;
}
/*
@ -19,11 +21,11 @@ export const readNdJson =
const decoder = new TextDecoder();
let buf = '';
const loop = (): Promise<void> =>
const loop = (): Promise<boolean> =>
stream.read().then(({ done, value }) => {
if (done) {
if (buf.length > 0) processLine(JSON.parse(buf));
return Promise.resolve();
return Promise.resolve(true);
} else {
const chunk = decoder.decode(value, { stream: true });
buf += chunk;
@ -36,6 +38,6 @@ export const readNdJson =
return {
cancel: () => stream.cancel(),
end: loop(),
end: sync(loop()),
};
};