21720: fixed sidepanel width
[arvados.git] / services / workbench2 / src / views-components / baner / banner.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import React, { useState, useCallback, useEffect } from "react";
6 import { CustomStyleRulesCallback } from 'common/custom-theme';
7 import { Dialog, DialogContent, DialogActions, Button } from "@mui/material";
8 import { WithStyles } from '@mui/styles';
9 import withStyles from '@mui/styles/withStyles';
10 import { connect } from "react-redux";
11 import { RootState } from "store/store";
12 import bannerActions from "store/banner/banner-action";
13 import { ArvadosTheme } from "common/custom-theme";
14 import servicesProvider from "common/service-provider";
15 import { Dispatch } from "redux";
16 import { sanitizeHTML } from "common/html-sanitize";
17
18 type CssRules = "dialogContent" | "dialogContentIframe";
19
20 const styles: CustomStyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
21     dialogContent: {
22         minWidth: "550px",
23         minHeight: "500px",
24         display: "block",
25     },
26     dialogContentIframe: {
27         minWidth: "550px",
28         minHeight: "500px",
29     },
30 });
31
32 interface BannerProps {
33     isOpen: boolean;
34     bannerUUID?: string;
35     keepWebInlineServiceUrl: string;
36 }
37
38 type BannerComponentProps = BannerProps &
39     WithStyles<CssRules> & {
40         openBanner: Function;
41         closeBanner: Function;
42     };
43
44 const mapStateToProps = (state: RootState): BannerProps => ({
45     isOpen: state.banner.isOpen,
46     bannerUUID: state.auth.config.clusterConfig.Workbench.BannerUUID,
47     keepWebInlineServiceUrl: state.auth.config.keepWebInlineServiceUrl,
48 });
49
50 const mapDispatchToProps = (dispatch: Dispatch) => ({
51     openBanner: () => dispatch<any>(bannerActions.openBanner()),
52     closeBanner: () => dispatch<any>(bannerActions.closeBanner()),
53 });
54
55 export const BANNER_LOCAL_STORAGE_KEY = "bannerFileData";
56
57 export const BannerComponent = (props: BannerComponentProps) => {
58     const { isOpen, openBanner, closeBanner, bannerUUID, keepWebInlineServiceUrl } = props;
59     const [bannerContents, setBannerContents] = useState(`<h1>Loading ...</h1>`);
60
61     const onConfirm = useCallback(() => {
62         closeBanner();
63     }, [closeBanner]);
64
65     useEffect(() => {
66         if (!!bannerUUID && bannerUUID !== "") {
67             try {
68             servicesProvider
69                 .getServices()
70                 .collectionService.files(bannerUUID)
71                 .then(results => {
72                     const bannerFileData = results.find(({ name }) => name === "banner.html");
73                     const result = localStorage.getItem(BANNER_LOCAL_STORAGE_KEY);
74
75                     if (result && result === JSON.stringify(bannerFileData) && !isOpen) {
76                         return;
77                     }
78
79                     if (bannerFileData) {
80                         servicesProvider
81                             .getServices()
82                             .collectionService.getFileContents(bannerFileData)
83                             .then(data => {
84                                 setBannerContents(data);
85                                 openBanner();
86                                 localStorage.setItem(BANNER_LOCAL_STORAGE_KEY, JSON.stringify(bannerFileData));
87                             });
88                     }
89                 })
90             } catch (e) {
91                 console.error("Failed to load banner", e);
92             }
93         }
94     }, [bannerUUID, keepWebInlineServiceUrl, openBanner, isOpen]);
95
96     return (
97         <Dialog
98             open={isOpen}
99             maxWidth="md"
100         >
101             <div data-cy="confirmation-dialog">
102                 <DialogContent className={props.classes.dialogContent}>
103                     <div dangerouslySetInnerHTML={{ __html: sanitizeHTML(bannerContents) }}></div>
104                 </DialogContent>
105                 <DialogActions style={{ margin: "0px 24px 24px" }}>
106                     <Button
107                         data-cy="confirmation-dialog-ok-btn"
108                         variant="contained"
109                         color="primary"
110                         type="submit"
111                         onClick={onConfirm}
112                     >
113                         Close
114                     </Button>
115                 </DialogActions>
116             </div>
117         </Dialog>
118     );
119 };
120
121 export const Banner = withStyles(styles)(connect(mapStateToProps, mapDispatchToProps)(BannerComponent));