Loading cloud_dashboard/src/bootstrap3-components/Button.tsx +4 −3 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ type ButtonProps = Omit< type GroupProps = { className?: string; children: React.ReactNode; }; Loading @@ -19,9 +20,9 @@ type GroupProps = { * @param children Children Node. * @param className Added text of className. */ const Group = ({ children }: GroupProps) => { const Group = ({ children, className }: GroupProps) => { return <div className={'btn-group'} role="group">{children}</div>; return <div className={`btn-group${className ? ' ' + className : ''}`} role="group">{children}</div>; } Loading @@ -32,7 +33,7 @@ const Group = ({ children }: GroupProps) => { * @param className Added text of className. */ const Button: (({ children, className, ...props }: ButtonProps) => JSX.Element) & { Group: ({ children }: GroupProps) => JSX.Element Group: ({ children, className }: GroupProps) => JSX.Element } = ({ children, className, ...props }) => { return <button type="button" Loading cloud_dashboard/src/model/DataRecord.ts +1 −0 Original line number Diff line number Diff line interface DataRecord { id: string, entityTypeId: string, value: { [key: string]: string } }; Loading cloud_dashboard/src/molecules/DataTableRowWithOperationLinks.tsx 0 → 100644 +175 −0 Original line number Diff line number Diff line import Button from 'bootstrap3-components/Button'; import GlyphIcon from 'bootstrap3-components/GlyphIcon'; import DataColumn from 'model/DataColumn'; import DataRecord from 'model/DataRecord'; import React from 'react'; import { Link } from 'react-router-dom'; /** * TD tag of DataTable. * * @param text Message. */ const DataTableData = ({ text, link }: { text: string | number, link?: string }) => { // For the text to be displayed, split the text at the line break position beforehand // so that any text is always processed to be enclosed in a "one line at a time" tag. const records = typeof text === 'string' && text.includes('\n') ? text.split('\n') : [`${text}`]; // If you need to set a link, enclose the entire group of <span> tags in an <a> tag. // If not, do not use the <a> tag. const textSpanTagList = records.map((r, index) => { return index === 0 ? <span key={index}>{r}</span> : <span key={index}><br />{r}</span>; }); return typeof link === 'string' ? <Link to={link}> {textSpanTagList} </Link> : <> {textSpanTagList} </>; } /** * Find and return the list of items to be added to Operation links. * * @param dataRecord Record of data. * @returns The list of items. */ const getOperations = (dataRecord: DataRecord): [string, string][] => { switch (dataRecord.entityTypeId) { case 'aws_cloud_instance': { // TODO: support 'Associate Elastic IP' menu. const list: [string, string][] = [['Create Image', '']]; if (dataRecord.value['instance_state'] === 'running') { list.push(['Stop', 'stop']); list.push(['Reboot', 'repeat']); } else if (dataRecord.value['instance_state'] === 'stopped') { list.push(['Start', 'play']); } return list; } case 'aws_cloud_volume': { const list: [string, string][] = [['Create Snapshot', '']]; if (dataRecord.value['state'] === 'available') { list.push(['Attach', 'tag']); } else if (dataRecord.value['state'] === 'in-use') { list.push(['Detach', 'tags']); } return list; } case 'aws_cloud_elastic_ip': return dataRecord.value['allocation_id'] === '' || dataRecord.value['allocation_id'] === null ? [['Associate', 'ok']] : [['Disassociate', 'remove']]; case 'aws_cloud_snapshot': return [['Create Volume', '']]; case 'aws_cloud_security_group': return [['Copy', 'duplicate']]; case 'aws_cloud_vpc_peering_connection': return dataRecord.value['status_code'] === 'pending-acceptance' ? [['Accept', '']] : []; case 'aws_cloud_internet_gateway': return dataRecord.value['vpc_id'] === '' || dataRecord.value['vpc_id'] === null ? [['Attach', '']] : [['Detach', '']]; case 'k8s_deployment': return [['Scale', '']]; case 'cloud_launch_template': { const list: [string, string][] = []; if (dataRecord.value['field_workflow_status'] === 'Approved') { list.push(['Launch', 'play']); } list.push(['Copy', 'duplicate']); if (dataRecord.value['field_workflow_status'] === 'Review') { list.push(['Approve', '']); } if (dataRecord.value['field_workflow_status'] === 'Draft') { list.push(['Review', 'comment']); } return list; } case 'cloud_project': return [['Launch', 'play'], ['Copy', 'duplicate']]; case 'k8s_cost_store': return [['Copy', 'duplicate']]; case 'k8s_namespace_resource_store': return [['Copy', 'duplicate']]; case 'k8s_node_resource_store': return [['Copy', 'duplicate']]; case 'k8s_pod_resource_store': return [['Copy', 'duplicate']]; } return []; } /** * Row data of DataTable. * Note: The OperationLinks column is added. * * @param dataRecord Record of data. * @param dataColumn List of DataColumn. * @param className Parameter of className. * @param detailInfo Information required to create a link to more information. */ const DataTableRowWithOperationLinks = ({ dataRecord, dataColumnList, className, detailInfo }: { dataRecord: DataRecord, dataColumnList: DataColumn[], className?: string, detailInfo?: { column: string, path: string, }, }) => { return <tr key={dataRecord.id} className={className}> {dataColumnList.map((dataColumn) => { return <td key={dataColumn.key} className="word-break-all"> <DataTableData text={ dataColumn.key in dataRecord.value ? dataRecord.value[dataColumn.key] : '' } link={dataColumn.key === detailInfo?.column ? `${detailInfo.path}/${dataRecord.id}` : undefined} /> </td>; })} <td> <Button.Group> <Button><GlyphIcon iconName='wrench' /> Edit</Button> <Button className='dropdown-toggle' data-toggle="dropdown"> <span className="caret" /> </Button> <ul className="dropdown-menu" role="menu"> { getOperations(dataRecord).map((menuInfo) => { return <li role="presentation" key={menuInfo[0]}> {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */} <a role="menuitem" href="#"> {menuInfo[1] !== '' ? <GlyphIcon iconName={menuInfo[1]} /> : <></>} {' '} {menuInfo[0]} </a> </li>; }) } <li role="presentation"> {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */} <a role="menuitem" href="#"><GlyphIcon iconName='trash' /> Delete</a> </li> </ul> </Button.Group> </td> </tr>; } export default DataTableRowWithOperationLinks; cloud_dashboard/src/organisms/CloudServiceProviderTable.tsx +2 −0 Original line number Diff line number Diff line Loading @@ -35,12 +35,14 @@ const CloudServiceProviderTable = () => { .map((r) => { return { id: `${r.cloudServiceProvider}_${r.name}`, entityTypeId: '', value: { 'labelName': r.labelName } }; }) } sortInfo={sortInfo} setSortInfo={setSortInfo} hasOperationLinks={false} /> </Form>; Loading cloud_dashboard/src/organisms/DataTable.tsx +23 −7 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ import DataRecord from 'model/DataRecord'; import SortInfo from 'model/SortInfo'; import DataTableHeader from 'molecules/DataTableHeader'; import DataTableRow from 'molecules/DataTableRow'; import DataTableRowWithOperationLinks from 'molecules/DataTableRowWithOperationLinks'; import React from 'react'; /** Loading @@ -15,11 +16,12 @@ import React from 'react'; * @param setSortInfo Setter of sortInfo. * @param detailInfo Information required to create a link to more information. */ const DataTable = ({ dataColumnList, dataRecordList, sortInfo, setSortInfo, detailInfo }: { const DataTable = ({ dataColumnList, dataRecordList, sortInfo, setSortInfo, hasOperationLinks, detailInfo }: { dataColumnList: DataColumn[], dataRecordList: DataRecord[], sortInfo: SortInfo, setSortInfo: (s: SortInfo) => void, hasOperationLinks: boolean, detailInfo?: { column: string, path: string, Loading @@ -32,12 +34,26 @@ const DataTable = ({ dataColumnList, dataRecordList, sortInfo, setSortInfo, deta {dataColumnList.map((dataColumn) => { return <DataTableHeader dataColumn={dataColumn} sortInfo={sortInfo} setSortInfo={setSortInfo} /> })} { hasOperationLinks ? <th> Operation links </th> : <></> } </tr> </thead> <tbody> { dataRecordList.map((dataRecord, index) => { return <DataTableRow return hasOperationLinks ? <DataTableRowWithOperationLinks dataRecord={dataRecord} dataColumnList={dataColumnList} className={index % 2 === 0 ? 'odd' : 'even'} detailInfo={detailInfo} /> : <DataTableRow dataRecord={dataRecord} dataColumnList={dataColumnList} className={index % 2 === 0 ? 'odd' : 'even'} Loading Loading
cloud_dashboard/src/bootstrap3-components/Button.tsx +4 −3 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ type ButtonProps = Omit< type GroupProps = { className?: string; children: React.ReactNode; }; Loading @@ -19,9 +20,9 @@ type GroupProps = { * @param children Children Node. * @param className Added text of className. */ const Group = ({ children }: GroupProps) => { const Group = ({ children, className }: GroupProps) => { return <div className={'btn-group'} role="group">{children}</div>; return <div className={`btn-group${className ? ' ' + className : ''}`} role="group">{children}</div>; } Loading @@ -32,7 +33,7 @@ const Group = ({ children }: GroupProps) => { * @param className Added text of className. */ const Button: (({ children, className, ...props }: ButtonProps) => JSX.Element) & { Group: ({ children }: GroupProps) => JSX.Element Group: ({ children, className }: GroupProps) => JSX.Element } = ({ children, className, ...props }) => { return <button type="button" Loading
cloud_dashboard/src/model/DataRecord.ts +1 −0 Original line number Diff line number Diff line interface DataRecord { id: string, entityTypeId: string, value: { [key: string]: string } }; Loading
cloud_dashboard/src/molecules/DataTableRowWithOperationLinks.tsx 0 → 100644 +175 −0 Original line number Diff line number Diff line import Button from 'bootstrap3-components/Button'; import GlyphIcon from 'bootstrap3-components/GlyphIcon'; import DataColumn from 'model/DataColumn'; import DataRecord from 'model/DataRecord'; import React from 'react'; import { Link } from 'react-router-dom'; /** * TD tag of DataTable. * * @param text Message. */ const DataTableData = ({ text, link }: { text: string | number, link?: string }) => { // For the text to be displayed, split the text at the line break position beforehand // so that any text is always processed to be enclosed in a "one line at a time" tag. const records = typeof text === 'string' && text.includes('\n') ? text.split('\n') : [`${text}`]; // If you need to set a link, enclose the entire group of <span> tags in an <a> tag. // If not, do not use the <a> tag. const textSpanTagList = records.map((r, index) => { return index === 0 ? <span key={index}>{r}</span> : <span key={index}><br />{r}</span>; }); return typeof link === 'string' ? <Link to={link}> {textSpanTagList} </Link> : <> {textSpanTagList} </>; } /** * Find and return the list of items to be added to Operation links. * * @param dataRecord Record of data. * @returns The list of items. */ const getOperations = (dataRecord: DataRecord): [string, string][] => { switch (dataRecord.entityTypeId) { case 'aws_cloud_instance': { // TODO: support 'Associate Elastic IP' menu. const list: [string, string][] = [['Create Image', '']]; if (dataRecord.value['instance_state'] === 'running') { list.push(['Stop', 'stop']); list.push(['Reboot', 'repeat']); } else if (dataRecord.value['instance_state'] === 'stopped') { list.push(['Start', 'play']); } return list; } case 'aws_cloud_volume': { const list: [string, string][] = [['Create Snapshot', '']]; if (dataRecord.value['state'] === 'available') { list.push(['Attach', 'tag']); } else if (dataRecord.value['state'] === 'in-use') { list.push(['Detach', 'tags']); } return list; } case 'aws_cloud_elastic_ip': return dataRecord.value['allocation_id'] === '' || dataRecord.value['allocation_id'] === null ? [['Associate', 'ok']] : [['Disassociate', 'remove']]; case 'aws_cloud_snapshot': return [['Create Volume', '']]; case 'aws_cloud_security_group': return [['Copy', 'duplicate']]; case 'aws_cloud_vpc_peering_connection': return dataRecord.value['status_code'] === 'pending-acceptance' ? [['Accept', '']] : []; case 'aws_cloud_internet_gateway': return dataRecord.value['vpc_id'] === '' || dataRecord.value['vpc_id'] === null ? [['Attach', '']] : [['Detach', '']]; case 'k8s_deployment': return [['Scale', '']]; case 'cloud_launch_template': { const list: [string, string][] = []; if (dataRecord.value['field_workflow_status'] === 'Approved') { list.push(['Launch', 'play']); } list.push(['Copy', 'duplicate']); if (dataRecord.value['field_workflow_status'] === 'Review') { list.push(['Approve', '']); } if (dataRecord.value['field_workflow_status'] === 'Draft') { list.push(['Review', 'comment']); } return list; } case 'cloud_project': return [['Launch', 'play'], ['Copy', 'duplicate']]; case 'k8s_cost_store': return [['Copy', 'duplicate']]; case 'k8s_namespace_resource_store': return [['Copy', 'duplicate']]; case 'k8s_node_resource_store': return [['Copy', 'duplicate']]; case 'k8s_pod_resource_store': return [['Copy', 'duplicate']]; } return []; } /** * Row data of DataTable. * Note: The OperationLinks column is added. * * @param dataRecord Record of data. * @param dataColumn List of DataColumn. * @param className Parameter of className. * @param detailInfo Information required to create a link to more information. */ const DataTableRowWithOperationLinks = ({ dataRecord, dataColumnList, className, detailInfo }: { dataRecord: DataRecord, dataColumnList: DataColumn[], className?: string, detailInfo?: { column: string, path: string, }, }) => { return <tr key={dataRecord.id} className={className}> {dataColumnList.map((dataColumn) => { return <td key={dataColumn.key} className="word-break-all"> <DataTableData text={ dataColumn.key in dataRecord.value ? dataRecord.value[dataColumn.key] : '' } link={dataColumn.key === detailInfo?.column ? `${detailInfo.path}/${dataRecord.id}` : undefined} /> </td>; })} <td> <Button.Group> <Button><GlyphIcon iconName='wrench' /> Edit</Button> <Button className='dropdown-toggle' data-toggle="dropdown"> <span className="caret" /> </Button> <ul className="dropdown-menu" role="menu"> { getOperations(dataRecord).map((menuInfo) => { return <li role="presentation" key={menuInfo[0]}> {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */} <a role="menuitem" href="#"> {menuInfo[1] !== '' ? <GlyphIcon iconName={menuInfo[1]} /> : <></>} {' '} {menuInfo[0]} </a> </li>; }) } <li role="presentation"> {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */} <a role="menuitem" href="#"><GlyphIcon iconName='trash' /> Delete</a> </li> </ul> </Button.Group> </td> </tr>; } export default DataTableRowWithOperationLinks;
cloud_dashboard/src/organisms/CloudServiceProviderTable.tsx +2 −0 Original line number Diff line number Diff line Loading @@ -35,12 +35,14 @@ const CloudServiceProviderTable = () => { .map((r) => { return { id: `${r.cloudServiceProvider}_${r.name}`, entityTypeId: '', value: { 'labelName': r.labelName } }; }) } sortInfo={sortInfo} setSortInfo={setSortInfo} hasOperationLinks={false} /> </Form>; Loading
cloud_dashboard/src/organisms/DataTable.tsx +23 −7 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ import DataRecord from 'model/DataRecord'; import SortInfo from 'model/SortInfo'; import DataTableHeader from 'molecules/DataTableHeader'; import DataTableRow from 'molecules/DataTableRow'; import DataTableRowWithOperationLinks from 'molecules/DataTableRowWithOperationLinks'; import React from 'react'; /** Loading @@ -15,11 +16,12 @@ import React from 'react'; * @param setSortInfo Setter of sortInfo. * @param detailInfo Information required to create a link to more information. */ const DataTable = ({ dataColumnList, dataRecordList, sortInfo, setSortInfo, detailInfo }: { const DataTable = ({ dataColumnList, dataRecordList, sortInfo, setSortInfo, hasOperationLinks, detailInfo }: { dataColumnList: DataColumn[], dataRecordList: DataRecord[], sortInfo: SortInfo, setSortInfo: (s: SortInfo) => void, hasOperationLinks: boolean, detailInfo?: { column: string, path: string, Loading @@ -32,12 +34,26 @@ const DataTable = ({ dataColumnList, dataRecordList, sortInfo, setSortInfo, deta {dataColumnList.map((dataColumn) => { return <DataTableHeader dataColumn={dataColumn} sortInfo={sortInfo} setSortInfo={setSortInfo} /> })} { hasOperationLinks ? <th> Operation links </th> : <></> } </tr> </thead> <tbody> { dataRecordList.map((dataRecord, index) => { return <DataTableRow return hasOperationLinks ? <DataTableRowWithOperationLinks dataRecord={dataRecord} dataColumnList={dataColumnList} className={index % 2 === 0 ? 'odd' : 'even'} detailInfo={detailInfo} /> : <DataTableRow dataRecord={dataRecord} dataColumnList={dataColumnList} className={index % 2 === 0 ? 'odd' : 'even'} Loading