|
| 1 | +import { loadComps } from "bootstrap/view"; |
| 2 | +import { initApp } from "util/commonUtils"; |
| 3 | +import { connect, Provider } from "react-redux"; |
| 4 | +import { createRoot } from "react-dom/client"; |
| 5 | +import type {AppState} from "@lowcoder-ee/redux/reducers"; |
| 6 | +import {isFetchUserFinished} from "@lowcoder-ee/redux/selectors/usersSelectors"; |
| 7 | +import {getIsCommonSettingFetched} from "@lowcoder-ee/redux/selectors/commonSettingSelectors"; |
| 8 | +import {getBrandingConfig} from "@lowcoder-ee/redux/selectors/configSelectors"; |
| 9 | +import {buildMaterialPreviewURL} from "@lowcoder-ee/util/materialUtils"; |
| 10 | +import {favicon} from "@lowcoder-ee/assets/images"; |
| 11 | +import {trans} from "@lowcoder-ee/i18n"; |
| 12 | +import {fetchUserAction} from "@lowcoder-ee/redux/reduxActions/userActions"; |
| 13 | +import {fetchConfigAction} from "@lowcoder-ee/redux/reduxActions/configActions"; |
| 14 | +import {fetchHomeData} from "@lowcoder-ee/redux/reduxActions/applicationActions"; |
| 15 | +import {packageMetaReadyAction, setLowcoderCompsLoading} from "@lowcoder-ee/redux/reduxActions/npmPluginActions"; |
| 16 | +import {getNpmPackageMeta} from "@lowcoder-ee/comps/utils/remote"; |
| 17 | +import { reduxStore } from "redux/store/store"; |
| 18 | +import React from "react"; |
| 19 | +import {hasQueryParam} from "@lowcoder-ee/util/urlUtils"; |
| 20 | +import history from "@lowcoder-ee/util/history"; |
| 21 | +import { |
| 22 | + APP_EDITOR_URL, |
| 23 | + isAuthUnRequired, |
| 24 | +} from "@lowcoder-ee/constants/routesURL"; |
| 25 | +import {ProductLoading} from "@lowcoder-ee/components/ProductLoading"; |
| 26 | +import {Helmet} from "react-helmet"; |
| 27 | +import {SystemWarning} from "@lowcoder-ee/components/SystemWarning"; |
| 28 | +import {Router, Switch} from "react-router-dom"; |
| 29 | +import LazyRoute from "@lowcoder-ee/components/LazyRoute"; |
| 30 | +import {default as ConfigProvider} from "antd/es/config-provider"; |
| 31 | +import {getAntdLocale} from "@lowcoder-ee/i18n/antdLocale"; |
| 32 | +import {default as App} from "antd/es/app"; |
| 33 | +import GlobalInstances from "components/GlobalInstances"; |
| 34 | +const LazyAppEditor = React.lazy(() => import("pages/editor/AppEditor")); |
| 35 | + |
| 36 | + |
| 37 | + |
| 38 | +const mapStateToProps = (state: AppState) => ({ |
| 39 | + isFetchUserFinished: isFetchUserFinished(state), |
| 40 | + getIsCommonSettingFetched: getIsCommonSettingFetched(state), |
| 41 | + orgDev: state.ui.users.user.orgDev, |
| 42 | + currentUserId: state.ui.users.currentUser.id, |
| 43 | + currentUserAnonymous: state.ui.users.user.isAnonymous, |
| 44 | + currentOrgId: state.ui.users.user.currentOrgId, |
| 45 | + defaultHomePage: state.ui.application.homeOrg?.commonSettings.defaultHomePage, |
| 46 | + fetchHomeDataFinished: Boolean(state.ui.application.homeOrg?.commonSettings), |
| 47 | + favicon: getBrandingConfig(state)?.favicon |
| 48 | + ? buildMaterialPreviewURL(getBrandingConfig(state)?.favicon!) |
| 49 | + : favicon, |
| 50 | + brandName: getBrandingConfig(state)?.brandName ?? trans("productName"), |
| 51 | + uiLanguage: state.ui.users.user.uiLanguage, |
| 52 | +}); |
| 53 | + |
| 54 | + |
| 55 | +const mapDispatchToProps = (dispatch: any) => ({ |
| 56 | + getCurrentUser: () => { |
| 57 | + dispatch(fetchUserAction()); |
| 58 | + }, |
| 59 | + fetchConfig: (orgId?: string) => dispatch(fetchConfigAction(orgId)), |
| 60 | + fetchHomeData: (currentUserAnonymous: boolean | undefined) => { |
| 61 | + dispatch(fetchHomeData({})); |
| 62 | + }, |
| 63 | + fetchLowcoderCompVersions: async () => { |
| 64 | + try { |
| 65 | + dispatch(setLowcoderCompsLoading(true)); |
| 66 | + const packageMeta = await getNpmPackageMeta('lowcoder-comps'); |
| 67 | + if (packageMeta?.versions) { |
| 68 | + dispatch(packageMetaReadyAction('lowcoder-comps', packageMeta)); |
| 69 | + } |
| 70 | + dispatch(setLowcoderCompsLoading(false)); |
| 71 | + } catch (_) { |
| 72 | + dispatch(setLowcoderCompsLoading(false)); |
| 73 | + } |
| 74 | + }, |
| 75 | +}); |
| 76 | + |
| 77 | +const Wrapper = (props: { children: React.ReactNode, language: string }) => ( |
| 78 | + <ConfigProvider |
| 79 | + theme={{ hashed: false }} |
| 80 | + locale={getAntdLocale(props.language)} |
| 81 | + > |
| 82 | + <App> |
| 83 | + <GlobalInstances /> |
| 84 | + {props.children} |
| 85 | + </App> |
| 86 | + </ConfigProvider> |
| 87 | +); |
| 88 | + |
| 89 | +type AppIndexProps = { |
| 90 | + isFetchUserFinished: boolean; |
| 91 | + getIsCommonSettingFetched: boolean; |
| 92 | + currentOrgId?: string; |
| 93 | + currentUserId: string; |
| 94 | + currentUserAnonymous: boolean; |
| 95 | + orgDev: boolean; |
| 96 | + defaultHomePage: string | null | undefined; |
| 97 | + fetchHomeDataFinished: boolean; |
| 98 | + fetchConfig: (orgId?: string) => void; |
| 99 | + fetchHomeData: (currentUserAnonymous?: boolean | undefined) => void; |
| 100 | + fetchLowcoderCompVersions: () => void; |
| 101 | + getCurrentUser: () => void; |
| 102 | + favicon: string; |
| 103 | + brandName: string; |
| 104 | + uiLanguage: string; |
| 105 | +}; |
| 106 | + |
| 107 | +class AppIndex extends React.Component<AppIndexProps, any> { |
| 108 | + componentDidMount() { |
| 109 | + this.props.getCurrentUser(); |
| 110 | + // if (!this.props.currentUserAnonymous) { |
| 111 | + // this.props.fetchHomeData(this.props.currentUserAnonymous); |
| 112 | + // } |
| 113 | + } |
| 114 | + componentDidUpdate(prevProps: AppIndexProps) { |
| 115 | + if ( |
| 116 | + prevProps.currentOrgId !== this.props.currentOrgId && |
| 117 | + this.props.currentOrgId !== '' |
| 118 | + ) { |
| 119 | + this.props.fetchConfig(this.props.currentOrgId); |
| 120 | + if (!this.props.currentUserAnonymous) { |
| 121 | + this.props.fetchHomeData(this.props.currentUserAnonymous); |
| 122 | + this.props.fetchLowcoderCompVersions(); |
| 123 | + } |
| 124 | + } |
| 125 | + } |
| 126 | + render() { |
| 127 | + const isTemplate = hasQueryParam('template'); |
| 128 | + const pathname = history.location.pathname; |
| 129 | + |
| 130 | + // we check if we are on the public cloud |
| 131 | + const isLowCoderDomain = window.location.hostname === 'app.lowcoder.cloud'; |
| 132 | + const isLocalhost = window.location.hostname === 'localhost'; |
| 133 | + |
| 134 | + /* if (isLocalhost || isLowCoderDomain) { |
| 135 | + posthog.init('phc_lD36OXeppUehLgI33YFhioTpXqThZ5QqR8IWeKvXP7f', { api_host: 'https://eu.i.posthog.com', person_profiles: 'always' }); |
| 136 | + } */ |
| 137 | + |
| 138 | + // make sure all users in this app have checked login info |
| 139 | + if (!this.props.isFetchUserFinished || (this.props.currentUserId && !this.props.fetchHomeDataFinished)) { |
| 140 | + const hideLoadingHeader = isTemplate || isAuthUnRequired(pathname); |
| 141 | + return <ProductLoading hideHeader={hideLoadingHeader} />; |
| 142 | + } |
| 143 | + else { |
| 144 | + // if the user just logged in, we send the event to posthog |
| 145 | + if (isLocalhost || isLowCoderDomain) { |
| 146 | + if (sessionStorage.getItem('_just_logged_in_')) { |
| 147 | + // posthog.identify(this.props.currentUserId); |
| 148 | + sessionStorage.removeItem('_just_logged_in_'); |
| 149 | + } |
| 150 | + } |
| 151 | + } |
| 152 | + |
| 153 | + return ( |
| 154 | + <Wrapper language={this.props.uiLanguage}> |
| 155 | + <Helmet> |
| 156 | + {<title>{this.props.brandName}</title>} |
| 157 | + {<link rel="icon" href={this.props.favicon} />} |
| 158 | + <meta name="description" content={trans('productDesc')} /> |
| 159 | + <meta |
| 160 | + name="keywords" |
| 161 | + content="Lowcoder, Applications, App Builder, Internal Applications, Websites, Dashboards, Data Visualization, Customer Applications, CRM, ERP, eCommerce, VideoMeeting, Rapid Development" |
| 162 | + /> |
| 163 | + <meta name="author" content="Lowcoder Software LTD" /> |
| 164 | + <meta name="robots" content="index, follow" /> |
| 165 | + |
| 166 | + <meta |
| 167 | + key="og:title" |
| 168 | + property="og:title" |
| 169 | + content={this.props.brandName} |
| 170 | + /> |
| 171 | + <meta |
| 172 | + key="og:description" |
| 173 | + property="og:description" |
| 174 | + content={trans('productDesc')} |
| 175 | + /> |
| 176 | + <meta |
| 177 | + key="og:image" |
| 178 | + property="og:image" |
| 179 | + content="https://raw.githubusercontent.com/lowcoder-org/lowcoder-media-assets/main/images/App%20Editor%20%7C%20Main%20Screeen%20clean%20v2.4.0.png" |
| 180 | + /> |
| 181 | + <meta key="og:url" property="og:url" content={window.location.href} /> |
| 182 | + <meta key="og:type" property="og:type" content="website" /> |
| 183 | + |
| 184 | + <meta |
| 185 | + key="twitter:card" |
| 186 | + name="twitter:card" |
| 187 | + content="summary_large_image" |
| 188 | + /> |
| 189 | + <meta |
| 190 | + key="twitter:title" |
| 191 | + name="twitter:title" |
| 192 | + content={this.props.brandName} |
| 193 | + /> |
| 194 | + <meta |
| 195 | + key="twitter:description" |
| 196 | + name="twitter:description" |
| 197 | + content={trans('productDesc')} |
| 198 | + /> |
| 199 | + <meta |
| 200 | + key="twitter:image" |
| 201 | + name="twitter:image" |
| 202 | + content="https://raw.githubusercontent.com/lowcoder-org/lowcoder-media-assets/main/images/App%20Editor%20%7C%20Main%20Screeen%20clean%20v2.4.0.png" |
| 203 | + /> |
| 204 | + |
| 205 | + <meta |
| 206 | + key="viewport" |
| 207 | + name="viewport" |
| 208 | + content="width=device-width, initial-scale=1, shrink-to-fit=no" |
| 209 | + /> |
| 210 | + <meta |
| 211 | + key="mobile-web-app-capable" |
| 212 | + name="mobile-web-app-capable" |
| 213 | + content="yes" |
| 214 | + /> |
| 215 | + <meta key="theme-color" name="theme-color" content="#b480de" /> |
| 216 | + |
| 217 | + <meta |
| 218 | + key="apple-mobile-web-app-capable" |
| 219 | + name="apple-mobile-web-app-capable" |
| 220 | + content="yes" |
| 221 | + /> |
| 222 | + <meta |
| 223 | + key="apple-mobile-web-app-status-bar-style" |
| 224 | + name="apple-mobile-web-app-status-bar-style" |
| 225 | + content="black-translucent" |
| 226 | + /> |
| 227 | + <meta |
| 228 | + key="apple-mobile-web-app-title" |
| 229 | + name="apple-mobile-web-app-title" |
| 230 | + content={this.props.brandName} |
| 231 | + /> |
| 232 | + <link |
| 233 | + key="apple-touch-icon" |
| 234 | + rel="apple-touch-icon" |
| 235 | + href="https://raw.githubusercontent.com/lowcoder-org/lowcoder-media-assets/main/images/Lowcoder%20Logo%20512.png" |
| 236 | + /> |
| 237 | + <link |
| 238 | + key="apple-touch-startup-image" |
| 239 | + rel="apple-touch-startup-image" |
| 240 | + href="https://raw.githubusercontent.com/lowcoder-org/lowcoder-media-assets/main/images/Lowcoder%20Logo%20512.png" |
| 241 | + /> |
| 242 | + |
| 243 | + <meta |
| 244 | + key="application-name" |
| 245 | + name="application-name" |
| 246 | + content={this.props.brandName} |
| 247 | + /> |
| 248 | + <meta |
| 249 | + key="msapplication-TileColor" |
| 250 | + name="msapplication-TileColor" |
| 251 | + content="#b480de" |
| 252 | + /> |
| 253 | + <meta |
| 254 | + key="msapplication-TileImage" |
| 255 | + name="msapplication-TileImage" |
| 256 | + content="https://raw.githubusercontent.com/lowcoder-org/lowcoder-media-assets/main/images/Lowcoder%20Logo%20150.png" |
| 257 | + /> |
| 258 | + {/* }<meta key="msapplication-config" name="msapplication-config" content="https://www.yourdomain.com/path/to/browserconfig.xml" />, */} |
| 259 | + |
| 260 | + <link rel="canonical" href={window.location.href} /> |
| 261 | + {isLowCoderDomain || isLocalhost && [ |
| 262 | + // Adding Support for iframely to be able to embedd the component explorer in the docu |
| 263 | + <meta |
| 264 | + key="iframely:title" |
| 265 | + property="iframely:title" |
| 266 | + content={this.props.brandName} |
| 267 | + />, |
| 268 | + <meta |
| 269 | + key="iframely:description" |
| 270 | + property="iframely:description" |
| 271 | + content={trans('productDesc')} |
| 272 | + />, |
| 273 | + <link |
| 274 | + key="iframely" |
| 275 | + rel="iframely" |
| 276 | + type="text/html" |
| 277 | + href={window.location.href} |
| 278 | + media="(aspect-ratio: 1280/720)" |
| 279 | + />, |
| 280 | + |
| 281 | + <link |
| 282 | + key="preconnect-googleapis" |
| 283 | + rel="preconnect" |
| 284 | + href="https://fonts.googleapis.com" |
| 285 | + />, |
| 286 | + <link |
| 287 | + key="preconnect-gstatic" |
| 288 | + rel="preconnect" |
| 289 | + href="https://fonts.gstatic.com" |
| 290 | + crossOrigin="anonymous" |
| 291 | + />, |
| 292 | + <link |
| 293 | + key="font-ubuntu" |
| 294 | + href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,700;1,400&display=swap" |
| 295 | + rel="stylesheet" |
| 296 | + />, |
| 297 | + // adding Clearbit Support for Analytics |
| 298 | + <script |
| 299 | + key="clearbit-script" |
| 300 | + src="https://tag.clearbitscripts.com/v1/pk_dfbc0aeefb28dc63475b67134facf127/tags.js" |
| 301 | + referrerPolicy="strict-origin-when-cross-origin" |
| 302 | + type="text/javascript" |
| 303 | + ></script>, |
| 304 | + ]} |
| 305 | + </Helmet> |
| 306 | + <SystemWarning /> |
| 307 | + <Router history={history}> |
| 308 | + <Switch> |
| 309 | + <LazyRoute |
| 310 | + fallback="layout" |
| 311 | + path={APP_EDITOR_URL} |
| 312 | + component={LazyAppEditor} |
| 313 | + /> |
| 314 | + </Switch> |
| 315 | + </Router> |
| 316 | + </Wrapper> |
| 317 | + ); |
| 318 | + } |
| 319 | +} |
| 320 | + |
| 321 | +const AppIndexWithProps = connect(mapStateToProps, mapDispatchToProps)(AppIndex); |
| 322 | + |
| 323 | +export function bootstrap() { |
| 324 | + initApp(); |
| 325 | + loadComps(); |
| 326 | + |
| 327 | + const container = document.getElementById("root"); |
| 328 | + const root = createRoot(container!); |
| 329 | + root.render( |
| 330 | + <Provider store={reduxStore}> |
| 331 | + <AppIndexWithProps /> |
| 332 | + </Provider> |
| 333 | + ); |
| 334 | +} |
0 commit comments