Skip to content

Commit

Permalink
[master] fix: Add Ingresses and Volumes components to ResourceStatus …
Browse files Browse the repository at this point in the history
…view (#4398)

fix: Add Ingresses and Volumes components to ResourceStatus view

Signed-off-by: leioy <[email protected]>
Co-authored-by: leioy <[email protected]>
  • Loading branch information
ks-ci-bot and Leioy authored Dec 26, 2024
1 parent bc7d578 commit 6e5157d
Show file tree
Hide file tree
Showing 13 changed files with 483 additions and 129 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ module.exports = {
UNABLE_TO_ACCESS_TIP:
'Make sure that domain name resolution policies have been configured in your DNS server or the hosts file of your client machine.',
CERTIFICATE_VALUE: 'Certificate: {value}',
// Metadata
// Events
ROUTE_PATH: 'Path',
ROUTE_PORT: 'Port',
};
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@ module.exports = {
UNABLE_TO_ACCESS_TIP:
'Make sure that domain name resolution policies have been configured in your DNS server or the hosts file of your client machine.',
CERTIFICATE_VALUE: 'Certificate: {value}',
ROUTE_PATH: 'Path',
ROUTE_PORT: 'Port',
};
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@ module.exports = {
UNABLE_TO_ACCESS_TIP:
'Make sure that domain name resolution policies have been configured in your DNS server or the hosts file of your client machine.',
CERTIFICATE_VALUE: 'Certificate: {value}',
ROUTE_PATH: '路徑',
ROUTE_PORT: '端口',
};
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ module.exports = {
UNABLE_TO_ACCESS: '无法访问服务',
UNABLE_TO_ACCESS_TIP: '请确保已在您的 DNS 服务器或客户机 hosts 文件中配置域名解析规则。',
CERTIFICATE_VALUE: '证书:{value}',
ROUTE_PATH: '路径',
ROUTE_PORT: '端口',
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,70 +5,119 @@

import React, { useMemo } from 'react';
import { Link } from 'react-router-dom';
import { Field } from '@kubed/components';
import { getDisplayName } from '../../../../../../utils';
import Icon from '../../../../../Icon';
import { ItemWrapper } from '../styles';
import { AccessButton, RulesWrapper } from './styles';
import { AccessButton, Content, Path, Tip, Title } from './styles';
import { find, get, isEmpty } from 'lodash';
import { gatewayStore } from '../../../../../../stores';
import { Col, Row, Tooltip } from '@kubed/components';

const { useQueryNewGatewayByProject } = gatewayStore;
type Props = {
detail: any;
gateway: any;
ingress: any;
prefix?: string;
params: Record<string, string>;
};

function IngressesItem({ prefix, detail, gateway }: Props): JSX.Element {
const tls = detail.tls || [];
const ports = useMemo(() => {
const finalPorts: Record<string, any> = {};
if (gateway && gateway.ports && gateway.type === 'NodePort') {
gateway.ports.forEach((_port: any) => {
if (_port.name === 'http' && _port.nodePort !== 80) {
finalPorts.http = _port.nodePort;
}
if (_port.name === 'https' && _port.nodePort !== 443) {
finalPorts.https = _port.nodePort;
}
});
}
type Tls = {
hosts: string[];
secretName: string;
}[];

function IngressesItem({ prefix, ingress, params }: Props): JSX.Element {
const { data } = useQueryNewGatewayByProject(params, {
enabled: !!params.cluster && !!params.workspace,
});
const rules = get(ingress, 'spec.rules', []);
const ingressClassName = get(ingress, 'spec.ingressClassName', '');

return finalPorts;
}, []);
const gateway = useMemo(() => {
return find(data, item => item.ingressClass === ingressClassName);
}, [data, ingressClassName]);
const tls: Tls = get(ingress, 'spec.tls', []);

return (
<ItemWrapper>
<Field
className="mb12"
avatar={<Icon name="loadbalancer" size={40} />}
label={t('DOMAIN_NAME_VALUE', {
value: detail.rules.map((rule: any) => rule.host).join(', '),
})}
value={<Link to={`${prefix}/ingresses/${detail.name}`}>{getDisplayName(detail)}</Link>}
/>
<RulesWrapper>
{detail.rules.map((rule: any) => {
const protocol = tls.hosts && tls.hosts.includes(rule.host) ? 'https' : 'http';
let host = `${protocol}://${rule.host}`;
if (ports[protocol]) {
host = `${host}:${ports[protocol]}`;
{rules.map((rule: any) => {
const tlsItem = tls.find(item => item.hosts && item.hosts.includes(rule.host));
const protocol = tlsItem ? 'https' : 'http';
let host = rule.host;
const service = get(gateway, 'service', []);
if (!isEmpty(service)) {
const tempPort = find(service, item => item.name === protocol);
if (
tempPort &&
((protocol === 'http' && tempPort.nodePort !== 80) ||
(protocol === 'https' && tempPort.nodePort !== 443))
) {
host = `${host}:${tempPort.nodePort}`;
}

return rule.http.paths.map((path: any) => (
<li key={`${rule.host}${path.path}`}>
<span>URL:&nbsp;&nbsp;</span>
<span>
<strong>
{host}
{path.path}
</strong>
</span>
<a href={`${host}${path.path}`} target="_blank" rel="noreferrer noopener">
<AccessButton>{t('ACCESS_SERVICE')}</AccessButton>
</a>
</li>
));
})}
</RulesWrapper>
}
return (
<>
<Content>
<Icon name="earth" size={40} />
<Title>
{host}
<div>
<span>
{t('PROTOCOL_VALUE')}
{protocol.toUpperCase()}
</span>
{protocol === 'https' && (
<span>
{t('CERTIFICATE_VALUE')}
{tlsItem?.secretName}
</span>
)}
<Tip>
{t('UNABLE_TO_ACCESS')}
&nbsp;&nbsp;
<Tooltip content={t('UNABLE_TO_ACCESS_TIP')}>
<Icon name="question" />
</Tooltip>
</Tip>
</div>
</Title>
</Content>
{rule.http.paths.map((path: any, i: number) => (
<Path key={`${path.path}-${i}`}>
<Row>
<Col span={3}>
<span>
{t('ROUTE_PATH')}<strong>{path.path}</strong>
</span>
</Col>
<Col span={3}>
<span>
{t('SERVICE_COLON')}
<strong>
<Link replace to={`${prefix}/services/${path.backend.service.name}`}>
{path.backend.service.name}
</Link>
</strong>
</span>
</Col>
<Col span={3}>
<span>
{t('ROUTE_PORT')}<strong>{path.backend.service.port.number}</strong>
</span>
</Col>
<Col span={3}>
<a
href={`${protocol}://${host}${path.path}`}
target="_blank"
rel="noreferrer noopener"
>
<AccessButton>{t('ACCESS_SERVICE')}</AccessButton>
</a>
</Col>
</Row>
</Path>
))}
</>
);
})}
</ItemWrapper>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,68 +3,48 @@
* https://github.com/kubesphere/console/blob/master/LICENSE
*/

import React, { useMemo } from 'react';
import { isEmpty } from 'lodash';
import { useQueries } from 'react-query';
import React, { useEffect, useMemo, useState } from 'react';

import { joinSelector } from '../../../../../../utils';
import { gatewayStore } from '../../../../../../stores';
import IngressesItem from './Item';
import ResourceCard from '../ResourceCard';
import { openpitrixStore } from '../../../../../../stores';
const { useBaseK8sList } = openpitrixStore;

const { fetchDetail } = gatewayStore;
import { EmptyTips } from './styles';

type Props = {
cluster?: string;
namespace?: string;
prefix?: string;
title?: string;
selector?: any;
};

function Ingresses({ title, cluster, namespace, selector, prefix }: Props): JSX.Element {
const k8sParams = useMemo(() => {
if (!isEmpty(selector)) {
return {
cluster,
namespace,
labelSelector: joinSelector(selector),
};
}
detail: any;

return {};
}, [selector]);
const gateWays = useQueries([
{
queryKey: ['gateWay', 'cluster', cluster],
queryFn: () => fetchDetail({ cluster }),
enabled: !!cluster,
},
{
queryKey: ['gateWay', 'namespace', cluster, namespace],
queryFn: () => fetchDetail({ cluster, namespace }),
enabled: !!cluster && !!namespace,
},
]);
const { data } = useBaseK8sList({
module: 'ingresses',
params: k8sParams,
autoFetch: gateWays[0].isSuccess && gateWays[1].isSuccess,
});
params: Record<string, string>;
};

function Ingresses({ detail, params }: Props): JSX.Element {
const { workspace, cluster, namespace } = params;
const prefix = workspace
? `/${workspace}/clusters/${cluster}/projects/${namespace}`
: `/clusters/${cluster}/projects/${namespace}`;
const [ingressList, setIngressList] = useState<any[]>([]);

const list = useMemo(
() =>
detail.map((item: any) => ({
...item,
module: item.kind,
...item.metadata,
})),
[detail],
);
useEffect(() => {
if (!list) return;
const ingressItems = list.filter((item: any) => item.kind === 'Ingress');
setIngressList(ingressItems);
}, [list]);
return (
<ResourceCard
title={title || t('ROUTE_PL')}
data={data}
title={t('ROUTE_PL')}
data={ingressList}
emptyPlaceholder={
<EmptyTips>{t('NO_AVAILABLE_RESOURCE_VALUE', { resource: t('ROUTE_PL') })}</EmptyTips>
}
itemRender={item => (
<IngressesItem
key={item.name}
prefix={prefix}
detail={item}
gateway={gateWays[0].data || gateWays[1].data}
/>
<IngressesItem params={params} key={item.name} prefix={prefix} ingress={item} />
)}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ export const AccessButton = styled(Button)`
top: 50%;
right: 6px;
transform: translateY(-50%);
& span {
color: #242e42 !important;
}
`;

export const RulesWrapper = styled.ul`
Expand All @@ -28,3 +31,83 @@ export const RulesWrapper = styled.ul`
}
}
`;

export const EmptyTips = styled.div`
padding: 20px;
color: ${({ theme }) => theme.palette.accents_4};
font-size: 16px;
font-weight: 600;
line-height: 1.5;
background-color: ${({ theme }) => theme.palette.accents_0};
border-radius: 4px;
`;

export const CardWrapper = styled.div`
padding: 20px;
border-radius: 4px;
background-color: #f9fbfd;
transition: all 0.3s ease-in-out;
& + & {
margin-top: 8px;
}
`;

export const Content = styled.div`
position: relative;
margin-bottom: 12px;
& > svg {
vertical-align: middle;
}
`;

export const Title = styled.div`
display: inline-block;
margin-left: 20px;
margin-right: 20px;
font-weight: 600;
line-height: 1.43;
color: #242e42;
vertical-align: middle;
& > div {
font-size: 12px;
color: #79879c;
font-weight: 400;
span + span {
margin-left: 100px;
}
}
`;
export const Tip = styled.div`
position: absolute;
top: 24px;
right: 12px;
display: inline-flex;
align-items: center;
justify-content: center;
`;

export const Path = styled.div`
position: relative;
padding: 12px 20px;
border-radius: 22px;
background-color: #eff4f9;
border: solid 1px #ccd3db;
& + & {
margin-top: 8px;
}
span {
text-align: left;
color: #79879c;
strong {
line-height: 1.43;
color: #242e42;
}
}
`;
Loading

0 comments on commit 6e5157d

Please sign in to comment.