/* Copyright (C) 2020 Cloudbase Solutions SRL This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ import { observer } from "mobx-react"; import * as React from "react"; import { Link } from "react-router-dom"; import styled, { css } from "styled-components"; import fieldHelper from "@src/@types/Field"; import { DeploymentItem, ReplicaItem, TransferItem } from "@src/@types/MainItem"; import { MinionPool } from "@src/@types/MinionPool"; import EndpointLogos from "@src/components/modules/EndpointModule/EndpointLogos"; import { ThemePalette, ThemeProps } from "@src/components/Theme"; import CopyMultilineValue from "@src/components/ui/CopyMultilineValue"; import CopyValue from "@src/components/ui/CopyValue"; import StatusIcon from "@src/components/ui/StatusComponents/StatusIcon"; import { OptionsSchemaPlugin } from "@src/plugins"; import DateUtils from "@src/utils/DateUtils"; import LabelDictionary from "@src/utils/LabelDictionary"; import type { Endpoint } from "@src/@types/Endpoint"; import type { Field as FieldType } from "@src/@types/Field"; const Wrapper = styled.div` display: flex; flex-direction: column; padding-bottom: 48px; `; const ColumnsLayout = styled.div` display: flex; `; const Column = styled.div` ${props => ThemeProps.exactWidth(props.width)} `; const Row = styled.div` margin-bottom: 32px; &:last-child { margin-bottom: 16px; } `; const Field = styled.div` display: flex; flex-direction: column; `; const Label = styled.div` font-size: 10px; color: ${ThemePalette.grayscale[3]}; font-weight: ${ThemeProps.fontWeights.medium}; text-transform: uppercase; display: flex; align-items: center; `; const StatusIconStub = styled.div` ${ThemeProps.exactSize("16px")} `; const Value = styled.div` display: ${props => props.flex ? "flex" : props.block ? "block" : "inline-table"}; margin-top: 3px; ${props => (props.capitalize ? "text-transform: capitalize;" : "")} `; const ValueLink = styled(Link)` display: flex; margin-top: 3px; color: ${ThemePalette.primary}; text-decoration: none; cursor: pointer; `; const PropertiesTable = styled.div``; const PropertyRow = styled.div` display: flex; justify-content: space-between; margin-bottom: 4px; `; const PropertyText = css``; const PropertyName = styled.div` ${PropertyText} overflow: hidden; text-overflow: ellipsis; max-width: 50%; `; const PropertyValue = styled.div` ${PropertyText} color: ${ThemePalette.grayscale[4]}; text-align: right; overflow: hidden; text-overflow: ellipsis; max-width: calc(50% + 16px); margin-right: -16px; `; type Props = { item?: MinionPool | null; replicas: ReplicaItem[]; deployments: DeploymentItem[]; schema: FieldType[]; schemaLoading: boolean; endpoints: Endpoint[]; bottomControls: React.ReactNode; }; @observer class MinionPoolMainDetails extends React.Component { getEndpoint(): Endpoint | undefined { const endpoint = this.props.endpoints.find( e => e.id === this.props.item?.endpoint_id ); return endpoint; } renderLastExecutionTime() { return this.props.item?.updated_at ? this.renderValue( DateUtils.getLocalDate(this.props.item.updated_at).toFormat( "yyyy-LL-dd HH:mm:ss" ) ) : "-"; } renderValue(value: string, capitalize?: boolean) { return ; } renderEndpointLink(): React.ReactNode { const endpointIsMissing = ( Endpoint is missing ); const endpoint = this.getEndpoint(); if (endpoint) { return ( {endpoint.name} ); } return endpointIsMissing; } renderPropertiesTable(propertyNames: string[]) { const endpoint = this.getEndpoint(); const getValue = (name: string, value: any) => { if ( value.join && value.length && value[0].destination && value[0].source ) { return value .map( (v: { source: any; destination: any }) => `${v.source}=${v.destination}` ) .join(", "); } const schema = this.props.schema; return fieldHelper.getValueAlias({ name, value, fields: schema, targetProvider: endpoint && endpoint.type, }); }; let properties: any[] = []; const plugin = endpoint && OptionsSchemaPlugin.for(endpoint.type); const deploymentImageMapFieldName = plugin && plugin.deploymentImageMapFieldName; let dictionaryKey = ""; if (endpoint) { dictionaryKey = `${endpoint.type}-minion-pool`; } const environment = this.props.item?.environment_options; propertyNames.forEach(pn => { const value = environment ? environment[pn] : ""; const label = LabelDictionary.get(pn, dictionaryKey); if (value && value.join) { value.forEach((v: any, i: number) => { const useLabel = i === 0 ? label : ""; properties.push({ label: useLabel, value: v }); }); } else if (value && typeof value === "object") { properties = properties.concat( Object.keys(value).map(p => { if (p === "disk_mappings") { return null; } let fieldName = pn; if ( deploymentImageMapFieldName && fieldName === deploymentImageMapFieldName ) { fieldName = p; } return { label: `${label} - ${LabelDictionary.get(p)}`, value: getValue(fieldName, value[p]), }; }) ); } else { properties.push({ label, value: getValue(pn, value) }); } }); return ( {properties .filter(Boolean) .filter(p => p.value != null && p.value !== "") .map(prop => ( {prop.label} ))} ); } renderUsage(items: TransferItem[]) { return items.map(item => { const actionHref = item.type === "replica" ? "transfers" : "deployments" return (
{item.instances[0]}
); }); } renderTable() { const endpoint = this.getEndpoint(); const lastUpdated = this.renderLastExecutionTime(); const getPropertyNames = () => { const env = this.props.item?.environment_options; return env ? Object.keys(env).filter( k => k !== "network_map" && (k !== "storage_mappings" || (env[k] != null && typeof env[k] === "object" && Object.keys(env[k]).length > 0)) ) : []; }; const usage: TransferItem[] = this.props.replicas.concat( this.props.deployments as any[] ); return ( {this.renderEndpointLink()} {this.renderValue(this.props.item?.id || "-")} {this.renderValue(this.props.item?.platform || "-", true)} {this.renderValue(this.props.item?.os_type || "-", true)} {this.props.item?.created_at ? ( this.renderValue( DateUtils.getLocalDate(this.props.item.created_at).toFormat( "yyyy-LL-dd HH:mm:ss" ) ) ) : ( - )} {this.props.item?.notes ? ( ) : null} {lastUpdated ? ( {lastUpdated} ) : null} {usage.length > 0 ? this.renderUsage(usage) : -} {getPropertyNames().length > 0 ? ( {this.renderPropertiesTable(getPropertyNames())} ) : null} {this.props.item?.minimum_minions || "1"} {this.props.item?.maximum_minions || "1"} {this.props.item?.minion_max_idle_time || "-"} {this.props.item?.minion_retention_strategy || "delete"} ); } renderBottomControls() { return this.props.bottomControls; } render() { return ( {this.renderTable()} {this.renderBottomControls()} ); } } export default MinionPoolMainDetails;