/*
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;