import { Minimize2 } from 'lucide-react';
import { NodeSelectorRequirement, Pod } from 'kubernetes-types/core/v1';
import { useMemo } from 'react';
import { Icon } from '@@/Icon';
import { TextTip } from '@@/Tip/TextTip';
import { Application } from '../../types';
import { applicationIsKind } from '../../utils';
type Props = {
app?: Application;
};
export function PlacementsTable({ app }: Props) {
const formPlacements = useAppPlacements(app);
return (
<>
Placement preferences and constraints
{!formPlacements.length && (
This application has no pod preference or constraint rules from the
application form. See the application YAML for other placement rules.
)}
{formPlacements.length > 0 && (
Key |
Value(s) |
{formPlacements.map((placement, i) => (
{placement.key} |
{placement.values?.join(', ')} |
))}
)}
>
);
}
// useAppPlacements is a custom hook that returns the placements that relate to the Portainer application form.
function useAppPlacements(app?: Application): NodeSelectorRequirement[] {
const formPlacements = useMemo(() => {
if (!app) {
return [];
}
// firstly get the pod spec
const podSpec = applicationIsKind('Pod', app)
? app.spec
: app.spec?.template?.spec;
// secondly filter all placements to get the placements that are related to the Portainer form. They are:
// - preference (s) in spec.affinity.nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution
const placements =
podSpec?.affinity?.nodeAffinity
?.preferredDuringSchedulingIgnoredDuringExecution;
// - matchExpressions in preference
const placementsWithMatchExpressions = placements?.filter(
(placement) => placement?.preference?.matchExpressions
);
// - only matchExpressions items with the operator: In
const portainerPlacements =
placementsWithMatchExpressions?.flatMap(
(placement) =>
placement?.preference?.matchExpressions?.filter(
(expression) => expression?.operator === 'In'
) || []
) || [];
return portainerPlacements;
}, [app]);
return formPlacements;
}