ReactViews/Preview/Description.js

import React from "react";

import createReactClass from "create-react-class";

import PropTypes from "prop-types";

import defined from "terriajs-cesium/Source/Core/defined";

import Collapsible from "../Custom/Collapsible/Collapsible";
import DataPreviewSections from "./DataPreviewSections";
import DataUri from "../../Core/DataUri";
import MetadataTable from "./MetadataTable";
import ObserveModelMixin from "../ObserveModelMixin";
import parseCustomMarkdownToReact from "../Custom/parseCustomMarkdownToReact";
import Styles from "./mappable-preview.scss";
import { withTranslation, Trans } from "react-i18next";
import i18next from "i18next";
/**
 * CatalogItem description.
 */
const Description = createReactClass({
  displayName: i18next.t("description.name"),
  mixins: [ObserveModelMixin],

  propTypes: {
    item: PropTypes.object.isRequired,
    printView: PropTypes.bool,
    t: PropTypes.func.isRequired
  },

  render() {
    const { t } = this.props;
    const catalogItem = this.props.item;
    const dataUrlType = catalogItem.dataUrlType;
    let hasDataUriCapability;
    let dataUri;
    let dataUriFormat;
    if (dataUrlType === "data-uri" || dataUrlType === "local") {
      hasDataUriCapability = DataUri.checkCompatibility();
      if (hasDataUriCapability) {
        dataUri = catalogItem.dataUrl;
        if (dataUri) {
          dataUriFormat = getDataUriFormat(dataUri);
        }
      }
    }
    return (
      <div className={Styles.description}>
        <If
          condition={
            catalogItem.description && catalogItem.description.length > 0
          }
        >
          <div>
            <h4 className={Styles.h4}>{t("description.name")}</h4>
            {parseCustomMarkdownToReact(catalogItem.description, {
              catalogItem: catalogItem
            })}
          </div>
        </If>

        <If condition={catalogItem.dataUrlType === "local"}>
          <p>{t("description.dataLocal")}</p>
        </If>

        <If
          condition={
            catalogItem.dataUrlType !== "local" && !catalogItem.hasDescription
          }
        >
          <p>{t("description.dataNotLocal")}</p>
        </If>

        <DataPreviewSections metadataItem={catalogItem} />

        <If
          condition={
            catalogItem.dataCustodian && catalogItem.dataCustodian.length > 0
          }
        >
          <div>
            <h4 className={Styles.h4}>{t("description.dataCustodian")}</h4>
            {parseCustomMarkdownToReact(catalogItem.dataCustodian, {
              catalogItem: catalogItem
            })}
          </div>
        </If>

        <If condition={!catalogItem.hideSource}>
          <If condition={catalogItem.url}>
            <h4 className={Styles.h4}>{catalogItem.typeName} URL</h4>
            <Choose>
              <When condition={catalogItem.type === "wms"}>
                <p key="wms-description">
                  <Trans i18nKey="description.wms">
                    This is a
                    <a
                      href="https://en.wikipedia.org/wiki/Web_Map_Service"
                      target="_blank"
                      rel="noopener noreferrer"
                    >
                      WMS service
                    </a>
                    , which generates map images on request. It can be used in
                    GIS software with this URL:
                  </Trans>
                </p>
              </When>
              <When condition={catalogItem.type === "wfs"}>
                <p key="wfs-description">
                  <Trans i18nKey="description.wfs">
                    This is a{" "}
                    <a
                      href="https://en.wikipedia.org/wiki/Web_Feature_Service"
                      target="_blank"
                      rel="noopener noreferrer"
                    >
                      WFS service
                    </a>
                    , which transfers raw spatial data on request. It can be
                    used in GIS software with this URL:
                  </Trans>
                </p>
              </When>
            </Choose>

            <Choose>
              <When condition={this.props.printView}>
                <code>{catalogItem.url}</code>
              </When>
              <Otherwise>
                <input
                  readOnly
                  className={Styles.field}
                  type="text"
                  value={catalogItem.url}
                  onClick={e => e.target.select()}
                />
              </Otherwise>
            </Choose>

            <Choose>
              <When
                condition={
                  catalogItem.type === "wms" ||
                  (catalogItem.type === "esri-mapServer" &&
                    defined(catalogItem.layers))
                }
              >
                <p key="wms-layers">
                  {t("description.layerName")}
                  {catalogItem.layers.split(",").length > 1 ? "s" : ""}:{" "}
                  {catalogItem.layers}
                </p>
              </When>
              <When condition={catalogItem.type === "wfs"}>
                <p key="wfs-typeNames">
                  {t("description.typeName")}
                  {catalogItem.typeNames.split(",").length > 1 ? "s" : ""}:{" "}
                  {catalogItem.typeNames}
                </p>
              </When>
            </Choose>
          </If>

          <If condition={catalogItem.metadataUrl}>
            <h4 className={Styles.h4}>{t("description.metadataUrl")}</h4>
            <p>
              <a
                href={catalogItem.metadataUrl}
                target="_blank"
                rel="noopener noreferrer"
                className={Styles.link}
              >
                {catalogItem.metadataUrl}
              </a>
            </p>
          </If>

          <If
            condition={
              catalogItem.dataUrlType &&
              catalogItem.dataUrlType !== "none" &&
              catalogItem.dataUrl
            }
          >
            <h4 className={Styles.h4}>{t("description.dataUrl")}</h4>
            <p>
              <Choose>
                <When
                  condition={
                    catalogItem.dataUrlType.indexOf("wfs") === 0 ||
                    catalogItem.dataUrlType.indexOf("wcs") === 0
                  }
                >
                  {catalogItem.dataUrlType.indexOf("wfs") === 0 &&
                    t("description.useLinkBelow", {
                      link: (
                        <a
                          href="http://docs.geoserver.org/latest/en/user/services/wfs/reference.html"
                          target="_blank"
                          rel="noopener noreferrer"
                          key="wfs"
                        >
                          Web Feature Service (WFS) documentation
                        </a>
                      )
                    })}
                  {catalogItem.dataUrlType.indexOf("wcs") === 0 &&
                    t("description.useLinkBelow", {
                      link: (
                        <a
                          href="http://docs.geoserver.org/latest/en/user/services/wcs/reference.html"
                          target="_blank"
                          rel="noopener noreferrer"
                          key="wms"
                        >
                          Web Coverage Service (WCS) documentation
                        </a>
                      )
                    })}
                  <br />
                  <Link url={catalogItem.dataUrl} text={catalogItem.dataUrl} />
                </When>
                <When
                  condition={
                    dataUrlType === "data-uri" || dataUrlType === "local"
                  }
                >
                  <If condition={hasDataUriCapability}>
                    <Link
                      url={dataUri}
                      text={t("description.downloadInFormat", {
                        format: dataUriFormat.toUpperCase()
                      })}
                      download={getBetterFileName(
                        dataUrlType,
                        catalogItem.name,
                        dataUriFormat
                      )}
                    />
                  </If>
                  <If condition={!hasDataUriCapability}>
                    {t("description.downloadNotSupported")}
                  </If>
                </When>
                <Otherwise>
                  {t("description.useTheLinkToDownload")}
                  <br />
                  {catalogItem.dataUrl.startsWith("data:") && (
                    <Link
                      url={catalogItem.dataUrl}
                      text={t("description.downloadData")}
                    />
                  )}
                  {!catalogItem.dataUrl.startsWith("data:") && (
                    <Link
                      url={catalogItem.dataUrl}
                      text={catalogItem.dataUrl}
                    />
                  )}
                </Otherwise>
              </Choose>
            </p>
          </If>

          <If
            condition={!this.props.printView && defined(catalogItem.metadata)}
          >
            {/*
                            // By default every catalog item has an error message here, so better to ignore it.
                        <If condition={defined(catalogItem.metadata.dataSourceErrorMessage)}>
                            <div className={Styles.error}>
                                Error loading data source details: {catalogItem.metadata.dataSourceErrorMessage}
                            </div>
                        </If>
                        */}
            <If
              condition={
                defined(catalogItem.metadata.dataSourceMetadata) &&
                catalogItem.metadata.dataSourceMetadata.items.length > 0
              }
            >
              <div className={Styles.metadata}>
                <Collapsible
                  title={t("description.dataSourceDetails")}
                  isInverse={true}
                >
                  <MetadataTable
                    metadataItem={catalogItem.metadata.dataSourceMetadata}
                  />
                </Collapsible>
              </div>
            </If>

            {/*
                        <If condition={defined(catalogItem.metadata.serviceErrorMessage)}>
                            <div className={Styles.error}>
                                Error loading data service details: {catalogItem.metadata.serviceErrorMessage}
                            </div>
                        </If>
                        */}
            <If
              condition={
                defined(catalogItem.metadata.dataSourceMetadata) &&
                catalogItem.metadata.dataSourceMetadata.items.length > 0
              }
            >
              <div className={Styles.metadata}>
                <Collapsible
                  title={t("description.dataServiceDetails")}
                  isInverse={true}
                >
                  <MetadataTable
                    metadataItem={catalogItem.metadata.serviceMetadata}
                  />
                </Collapsible>
              </div>
            </If>
          </If>
        </If>
      </div>
    );
  }
});

/**
 * Read the format from the start of a data uri, eg. data:attachment/csv,...
 * @param  {String} dataUri The data URI.
 * @return {String} The format string, eg. 'csv', or undefined if none found.
 */
function getDataUriFormat(dataUri) {
  if (defined(dataUri)) {
    const slashIndex = dataUri.indexOf("/");
    const commaIndex = dataUri.indexOf(",");
    // Don't look into the data itself. Assume the format is somewhere in the first 40 chars.
    if (slashIndex < commaIndex && commaIndex < 40) {
      return dataUri.slice(slashIndex + 1, commaIndex);
    }
  }
}

/**
 * Return a nicer filename for this file.
 * @private
 */
function getBetterFileName(dataUrlType, itemName, format) {
  let name = itemName;
  const extension = "." + format;
  // Only add the extension if it's not already there.
  if (name.indexOf(extension) !== name.length - extension.length) {
    name = name + extension;
  }
  // For local files, the file already exists on the user's computer with the original name, so give it a modified name.
  if (dataUrlType === "local") {
    name = "processed " + name;
  }
  return name;
}

const Link = createReactClass({
  displayName: "Link",
  mixins: [ObserveModelMixin],

  propTypes: {
    url: PropTypes.string.isRequired,
    text: PropTypes.string.isRequired,
    download: PropTypes.string
  },

  render() {
    return (
      <a
        href={this.props.url}
        className={Styles.link}
        download={this.props.download}
        target="_blank"
        rel="noopener noreferrer"
      >
        {this.props.text}
      </a>
    );
  }
});

export default withTranslation()(Description);