Merge remote-tracking branch 'origin/main' into 19836-new-tooltip-impl
[arvados.git] / src / store / tooltips / tooltips-middleware.ts
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import { CollectionDirectory, CollectionFile } from "models/collection-file";
6 import { Middleware, Store } from "redux";
7 import { ServiceRepository } from "services/services";
8 import { RootState } from "store/store";
9 import tippy, { createSingleton } from 'tippy.js';
10 import 'tippy.js/dist/tippy.css';
11
12 let running = false;
13 let tooltipsContents = null;
14 let tooltipsFetchFailed = false;
15 const TOOLTIP_LOCAL_STORAGE_KEY = "TOOLTIP_LOCAL_STORAGE_KEY";
16
17 export const tooltipsMiddleware = (services: ServiceRepository): Middleware => (store: Store) => next => action => {
18     const state: RootState = store.getState();
19     const result = localStorage.getItem(TOOLTIP_LOCAL_STORAGE_KEY);
20     const { BannerURL } = (state.auth.config.clusterConfig.Workbench as any);
21
22     let bannerUUID = !!BannerURL ? BannerURL : 'tordo-4zz18-1buneu6sb8zxiti';
23
24     if (bannerUUID && !tooltipsContents && !result && !tooltipsFetchFailed && !running) {
25         running = true;
26         fetchTooltips(services, bannerUUID);
27     } else if (tooltipsContents && !result && !tooltipsFetchFailed) {
28         applyTooltips();
29     }
30
31     return next(action);
32 };
33
34 const fetchTooltips = (services, bannerUUID) => {
35     services.collectionService.files(bannerUUID)
36         .then(results => {
37             const tooltipsFile: CollectionDirectory | CollectionFile | undefined = results.find(({ name }) => name === 'tooltips.json');
38
39             if (tooltipsFile) {
40                 running = true;
41                 services.collectionService.getFileContents(tooltipsFile as CollectionFile)
42                     .then(data => {
43                         tooltipsContents = JSON.parse(data);
44                         applyTooltips();
45                     })
46                     .catch(() => {})
47                     .finally(() => {
48                         running = false;
49                     });
50             }  else {
51                 tooltipsFetchFailed = true;
52             }
53         })
54         .catch(() => {})
55         .finally(() => {
56             running = false;
57         });
58 };
59
60 const applyTooltips = () => {
61     const tippyInstances: any[] = Object.keys(tooltipsContents as any)
62         .map((key) => {
63             const content = (tooltipsContents as any)[key]
64             const element = document.querySelector(key);
65
66             if (element) {
67                 const hasTippyAttatched = !!(element as any)._tippy;
68
69                 if (!hasTippyAttatched && tooltipsContents) {
70                     return tippy(element as any, { content });
71                 }
72             }
73
74             return null;
75         })
76         .filter(data => !!data);
77
78         createSingleton(tippyInstances, {delay: 10});
79 };