Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enh/wonders #2367

Merged
merged 5 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added client/public/textures/my_realm_wonder_label.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added client/public/textures/realm_wonder_label.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion client/src/hooks/helpers/use-get-all-players.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export const useGetAllPlayers = () => {
]).size,
hyperstructures: runQuery([Has(Hyperstructure), HasValue(Owner, { address: player.address })]).size,
isAlive: player.isAlive,
guildName: player.guildName,
guildName: player.guildName || "",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Remove redundant fallback for guildName

The fallback || "" is unnecessary since guildName is already initialized with an empty string on line 30 when guildMember is null. This creates redundant defensive programming.

-        guildName: player.guildName || "", 
+        guildName: player.guildName,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
guildName: player.guildName || "",
guildName: player.guildName,

};
});
};
Expand Down
41 changes: 22 additions & 19 deletions client/src/hooks/helpers/useEntities.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type ClientComponents } from "@/dojo/createClientComponents";
import { getRealmNameById } from "@/ui/utils/realms";
import { getRealmName, getRealmNameById } from "@/ui/utils/realms";
import { divideByPrecision, getEntityIdFromKeys } from "@/ui/utils/utils";
import {
CAPACITY_CONFIG_CATEGORY_STRING_MAP,
Expand All @@ -9,7 +9,7 @@ import {
type ID,
} from "@bibliothecadao/eternum";
import { useEntityQuery } from "@dojoengine/react";
import { Has, getComponentValue, type Component, type ComponentValue, type Entity } from "@dojoengine/recs";
import { Has, getComponentValue, type ComponentValue } from "@dojoengine/recs";
import { useMemo } from "react";
import { shortString } from "starknet";
import { useDojo } from "../context/DojoContext";
Expand Down Expand Up @@ -111,11 +111,8 @@ export const useEntities = () => {

const structureName = getEntityName(structure.entity_id);

const name = realm
? getRealmNameById(realm.realm_id)
: structureName
? `${structureName}`
: structure.category || "";
const name = realm ? getRealmName(realm) : structureName || structure.category || "";

return { ...structure, position: position!, name, owner: getComponentValue(Owner, id) };
})
.filter((structure): structure is PlayerStructure => structure !== undefined)
Expand Down Expand Up @@ -256,20 +253,26 @@ export const useEntitiesUtils = () => {
const realm = getComponentValue(Realm, getEntityIdFromKeys([BigInt(entityId)]));
const structure = getComponentValue(Structure, getEntityIdFromKeys([BigInt(entityId)]));

if (structure?.category === StructureType[StructureType.Realm]) {
return getRealmNameById(realm?.realm_id || 0);
} else if (entityName) {
if (structure?.category === StructureType[StructureType.Realm] && realm) {
return getRealmName(realm);
}

if (entityName) {
return shortString.decodeShortString(entityName.name.toString());
} else {
if (abbreviate) {
if (structure?.category === StructureType[StructureType.FragmentMine]) {
return `FM ${structure.entity_id}`;
} else if (structure?.category === StructureType[StructureType.Hyperstructure]) {
return `HS ${structure.entity_id}`;
} else if (structure?.category === StructureType[StructureType.Bank]) {
return `BK ${structure.entity_id}`;
}
}

if (abbreviate && structure) {
const abbreviations: Record<string, string> = {
[StructureType[StructureType.FragmentMine]]: "FM",
[StructureType[StructureType.Hyperstructure]]: "HS",
[StructureType[StructureType.Bank]]: "BK",
};

const abbr = abbreviations[structure.category];
if (abbr) {
return `${abbr} ${structure.entity_id}`;
}

return `${structure?.category} ${structure?.entity_id}`;
}
};
Expand Down
10 changes: 5 additions & 5 deletions client/src/hooks/helpers/useGuilds.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ export const useGuilds = () => {
guilds,
nextBlockTimestamp,
account.address,
getEntityName,
(entityId: number) => getEntityName(entityId) || 'Unknown',
Guild,
Owner,
GuildMember,
Expand All @@ -202,7 +202,7 @@ export const useGuilds = () => {
[getEntityIdFromKeys([BigInt(entityId)])],
nextBlockTimestamp,
account.address,
getEntityName,
(entityId: number) => getEntityName(entityId) || 'Unknown',
Guild,
Owner,
GuildMember,
Expand All @@ -222,7 +222,7 @@ export const useGuilds = () => {
const guild = getComponentValue(Guild, getEntityIdFromKeys([BigInt(guildMember.guild_entity_id)]));
const owner = getComponentValue(Owner, getEntityIdFromKeys([BigInt(guildMember.guild_entity_id)]));

const name = guildMember.guild_entity_id ? getEntityName(guildMember.guild_entity_id) : "Unknown";
const name = guildMember.guild_entity_id ? getEntityName(guildMember.guild_entity_id) || 'Unknown' : "Unknown";

return {
entityId: guildMember?.guild_entity_id,
Expand Down Expand Up @@ -254,13 +254,13 @@ export const useGuilds = () => {
HasValue(GuildWhitelist, { guild_entity_id: guildEntityId, is_whitelisted: true }),
]);

return formatGuildWhitelist(whitelist, players, GuildWhitelist, getAddressName, getEntityName);
return formatGuildWhitelist(whitelist, players, GuildWhitelist, getAddressName, (entityId: number) => getEntityName(entityId) || 'Unknown');
};

const usePlayerWhitelist = (address: ContractAddress) => {
const whitelist = useEntityQuery([HasValue(GuildWhitelist, { address, is_whitelisted: true })]);

return formatPlayerWhitelist(whitelist, GuildWhitelist, getEntityName);
return formatPlayerWhitelist(whitelist, GuildWhitelist, (entityId: number) => getEntityName(entityId) || 'Unknown');
};

const getPlayersInPlayersGuild = useCallback((accountAddress: ContractAddress) => {
Expand Down
6 changes: 5 additions & 1 deletion client/src/hooks/helpers/useRealm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import {
} from "@bibliothecadao/eternum";
import { useEntityQuery } from "@dojoengine/react";
import { type ComponentValue, type Entity, Has, HasValue, getComponentValue, runQuery } from "@dojoengine/recs";
import { useMemo } from "react";
import { shortString } from "starknet";
import realmIdsByOrder from "../../data/realmids_by_order.json";
import { unpackResources } from "../../ui/utils/packedData";
import { getRealmNameById } from "../../ui/utils/realms";
import { getEntityIdFromKeys } from "../../ui/utils/utils";
import { useDojo } from "../context/DojoContext";
import useUIStore from "../store/useUIStore";
import { useMemo } from "react";

export interface RealmInfo {
realmId: ID;
Expand All @@ -29,6 +29,7 @@ export interface RealmInfo {
hasCapacity: boolean;
owner: ContractAddress;
ownerName: string;
hasWonder: boolean;
}

export function useRealm() {
Expand Down Expand Up @@ -237,6 +238,7 @@ export function useGetRealm(realmEntityId: ID | undefined) {
hasCapacity:
!population || population.capacity + configManager.getBasePopulationCapacity() > population.population,
owner: address,
hasWonder: realm.has_wonder,
};
}
}
Expand Down Expand Up @@ -286,6 +288,7 @@ export function getRealms(): RealmInfo[] {
!population || population.capacity + configManager.getBasePopulationCapacity() > population.population,
owner: address,
ownerName,
hasWonder: realm.has_wonder,
};
})
.filter((realm) => realm !== undefined);
Expand Down Expand Up @@ -332,6 +335,7 @@ export function usePlayerRealms(): RealmInfo[] {
!population || population.capacity + configManager.getBasePopulationCapacity() > population.population,
owner: address,
ownerName,
hasWonder: realm.has_wonder,
};
})
.filter((realm) => realm !== undefined);
Expand Down
2 changes: 1 addition & 1 deletion client/src/hooks/helpers/useStructures.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export const useStructureAtPosition = ({ x, y }: Position): Structure | undefine
const protectorArmy = getComponentValue(Protector, structureEntityId);
const protector = protectorArmy ? getAliveArmy(protectorArmy.army_id) : undefined;

const name = getEntityName(structure.entity_id);
const name = getEntityName(structure.entity_id) || "";

const addressName = getComponentValue(AddressName, getEntityIdFromKeys([owner?.address]));
const ownerName = addressName ? shortString.decodeShortString(addressName!.name.toString()) : "Bandits";
Expand Down
14 changes: 11 additions & 3 deletions client/src/three/components/Minimap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ const LABELS = {
MY_ARMY: "/textures/my_army_label.png",
MY_REALM: "/textures/my_realm_label.png",
BATTLE: "/textures/battle_label.png",
MY_REALM_WONDER: "/textures/my_realm_wonder_label.png",
REALM_WONDER: "/textures/realm_wonder_label.png",
STRUCTURES: {
[StructureType.Realm]: "/textures/realm_label.png",
[StructureType.Hyperstructure]: "/textures/hyper_label.png",
Expand Down Expand Up @@ -249,9 +251,13 @@ class Minimap {

structures.forEach((structure) => {
if (structureType === StructureType.Realm) {
labelImg = structure.isMine
? this.labelImages.get("MY_REALM")
: this.labelImages.get(`STRUCTURE_${structureType}`);
if (structure.isMine) {
labelImg = structure.hasWonder ? this.labelImages.get("MY_REALM_WONDER") : this.labelImages.get("MY_REALM");
} else {
labelImg = structure.hasWonder
? this.labelImages.get("REALM_WONDER")
: this.labelImages.get(`STRUCTURE_${structureType}`);
}
}
if (!labelImg) return;
const { col, row } = structure.hexCoords;
Expand Down Expand Up @@ -455,6 +461,8 @@ class Minimap {
this.loadImage("MY_ARMY", LABELS.MY_ARMY);
this.loadImage("BATTLE", LABELS.BATTLE);
this.loadImage("MY_REALM", LABELS.MY_REALM);
this.loadImage("MY_REALM_WONDER", LABELS.MY_REALM_WONDER);
this.loadImage("REALM_WONDER", LABELS.REALM_WONDER);

// Load structure labels
Object.entries(LABELS.STRUCTURES).forEach(([type, path]) => {
Expand Down
6 changes: 4 additions & 2 deletions client/src/three/components/StructureManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export class StructureManager {

async onUpdate(update: StructureSystemUpdate) {
await Promise.all(this.modelLoadPromises);
const { entityId, hexCoords, structureType, stage, level, owner } = update;
const { entityId, hexCoords, structureType, stage, level, owner, hasWonder } = update;
const normalizedCoord = { col: hexCoords.col - FELT_CENTER, row: hexCoords.row - FELT_CENTER };
const position = getWorldPositionForHex(normalizedCoord);

Expand All @@ -106,7 +106,7 @@ export class StructureManager {

const key = structureType;
// Add the structure to the structures map
this.structures.addStructure(entityId, key, normalizedCoord, stage, level, owner);
this.structures.addStructure(entityId, key, normalizedCoord, stage, level, owner, hasWonder);

// Update the visible structures if this structure is in the current chunk
if (this.isInCurrentChunk(normalizedCoord)) {
Expand Down Expand Up @@ -227,6 +227,7 @@ class Structures {
stage: number = 0,
level: number = 0,
owner: { address: bigint },
hasWonder: boolean,
) {
if (!this.structures.has(structureType)) {
this.structures.set(structureType, new Map());
Expand All @@ -239,6 +240,7 @@ class Structures {
isMine: isAddressEqualToAccount(owner.address),
owner,
structureType,
hasWonder,
});
}

Expand Down
3 changes: 3 additions & 0 deletions client/src/three/systems/SystemManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,11 @@ export class SystemManager {
const stage = this.getStructureStage(StructureType[categoryKey], structure.entity_id);

let level = 0;
let hasWonder = false;
if (StructureType[categoryKey] === StructureType.Realm) {
const realm = getComponentValue(this.setup.components.Realm, update.entity);
level = realm?.level || RealmLevels.Settlement;
hasWonder = realm?.has_wonder || false;
}

return {
Expand All @@ -176,6 +178,7 @@ export class SystemManager {
stage,
level,
owner: { address: owner?.address || 0n },
hasWonder,
};
});
},
Expand Down
1 change: 1 addition & 0 deletions client/src/three/systems/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export type StructureSystemUpdate = {
stage: StructureProgress;
level: number;
owner: { address: bigint };
hasWonder: boolean;
};

export type TileSystemUpdate = {
Expand Down
1 change: 1 addition & 0 deletions client/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export interface StructureInfo {
isMine: boolean;
owner: { address: bigint };
structureType: StructureType;
hasWonder: boolean;
}

export interface ArmyData {
Expand Down
4 changes: 2 additions & 2 deletions client/src/ui/components/worldmap/armies/ArmyInfoLabel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { currencyFormat } from "../../../utils/utils";

import { ArmyInfo, getArmyByEntityId } from "@/hooks/helpers/useArmies";
import { useQuery } from "@/hooks/helpers/useQuery";
import { useIsStructureImmune, useStructureImmunityTimer, useStructures } from "@/hooks/helpers/useStructures";
import { Structure, useIsStructureImmune, useStructureImmunityTimer, useStructures } from "@/hooks/helpers/useStructures";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Potential runtime error: Unsafe type assertion

The type assertion as Structure on line 58 could lead to runtime errors since structure might be undefined. The structure variable is conditionally assigned in the useMemo hook above, but the timer hook is called unconditionally.

Consider adding a null check or using optional chaining:

- const timer = useStructureImmunityTimer(structure as Structure, nextBlockTimestamp || 0);
+ const timer = structure ? useStructureImmunityTimer(structure, nextBlockTimestamp || 0) : undefined;

Also applies to: 58-58

import { ArmyCapacity } from "@/ui/elements/ArmyCapacity";
import { BaseThreeTooltip, Position } from "@/ui/elements/BaseThreeTooltip";
import { Headline } from "@/ui/elements/Headline";
Expand Down Expand Up @@ -55,7 +55,7 @@ const RaiderInfo = ({ army }: ArmyInfoLabelProps) => {
const nextBlockTimestamp = useUIStore((state) => state.nextBlockTimestamp);

const isImmune = useIsStructureImmune(structure, nextBlockTimestamp || 0);
const timer = useStructureImmunityTimer(structure, nextBlockTimestamp || 0);
const timer = useStructureImmunityTimer(structure as Structure, nextBlockTimestamp || 0);

return (
<BaseThreeTooltip
Expand Down
2 changes: 1 addition & 1 deletion client/src/ui/components/worldmap/battles/BattleLabel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const BattleInfoLabel = () => {
battleEntityId={battle.entity_id}
dojo={dojo}
currentTimestamp={currentTimestamp}
structure={structure}
structure={structure as Structure}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Remove unnecessary type assertion

The BattleInfo component already accepts Structure | undefined in its props type definition. The type assertion is redundant and can be removed.

- structure={structure as Structure}
+ structure={structure}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
structure={structure as Structure}
structure={structure}

/>
))}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useGuilds } from "@/hooks/helpers/useGuilds";
import { useQuery } from "@/hooks/helpers/useQuery";
import { useIsStructureImmune, useStructureImmunityTimer, useStructures } from "@/hooks/helpers/useStructures";
import { Structure, useIsStructureImmune, useStructureImmunityTimer, useStructures } from "@/hooks/helpers/useStructures";
import { BaseThreeTooltip, Position } from "@/ui/elements/BaseThreeTooltip";
import { Headline } from "@/ui/elements/Headline";
import { formatTime } from "@/ui/utils/utils";
Expand Down Expand Up @@ -47,7 +47,7 @@ export const StructureInfoLabel = () => {
const nextBlockTimestamp = useUIStore((state) => state.nextBlockTimestamp);

const isImmune = useIsStructureImmune(structure, nextBlockTimestamp || 0);
const timer = useStructureImmunityTimer(structure, nextBlockTimestamp || 0);
const timer = useStructureImmunityTimer(structure as Structure, nextBlockTimestamp || 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add null check before type assertion

The type assertion as Structure could lead to runtime errors if structure is undefined. Consider using optional chaining or a null check.

- const timer = useStructureImmunityTimer(structure as Structure, nextBlockTimestamp || 0);
+ const timer = structure ? useStructureImmunityTimer(structure, nextBlockTimestamp || 0) : 0;

Committable suggestion skipped: line range outside the PR's diff.


return (
<>
Expand All @@ -65,7 +65,7 @@ export const StructureInfoLabel = () => {
)}
</Headline>
<StructureListItem
structure={structure}
structure={structure as Structure}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Use conditional rendering instead of type assertion

Similar to the timer issue, casting potentially undefined structure to Structure is unsafe.

- structure={structure as Structure}
+ structure={structure!}

Additionally, consider adding a type guard:

if (!structure) return null;

before the JSX return statement.

ownArmySelected={undefined}
setShowMergeTroopsPopup={() => {}}
maxInventory={3}
Expand Down
2 changes: 1 addition & 1 deletion client/src/ui/elements/ResourceCost.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export const ResourceCost = ({
{" "}
{Intl.NumberFormat("en-US", {
notation: "compact",
maximumFractionDigits: 1,
maximumFractionDigits: 6,
}).format(props.amount || 0)}{" "}
<span className={clsx(balanceColor, "font-normal")}>
{!isNaN(balance) && `(${currencyFormat(balance, 0)})`}{" "}
Expand Down
4 changes: 2 additions & 2 deletions client/src/ui/modules/entity-details/realm/RealmDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useIsStructureImmune, useStructureByEntityId, useStructureImmunityTimer } from "@/hooks/helpers/useStructures";
import { Structure, useIsStructureImmune, useStructureByEntityId, useStructureImmunityTimer } from "@/hooks/helpers/useStructures";
import useUIStore from "@/hooks/store/useUIStore";
import { HintSection } from "@/ui/components/hints/HintModal";
import { HintModalButton } from "@/ui/elements/HintModalButton";
Expand Down Expand Up @@ -42,7 +42,7 @@ export const RealmDetails = () => {
);

const isImmune = useIsStructureImmune(structure, nextBlockTimestamp || 0);
const timer = useStructureImmunityTimer(structure, nextBlockTimestamp || 0);
const timer = useStructureImmunityTimer(structure as Structure, nextBlockTimestamp || 0);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Leverage existing checks for type safety

The component already has proper null checking with structure &&. Consider restructuring the immunity timer logic to avoid type assertion.

- const timer = useStructureImmunityTimer(structure as Structure, nextBlockTimestamp || 0);
+ const timer = structure && isImmune 
+   ? useStructureImmunityTimer(structure, nextBlockTimestamp || 0)
+   : 0;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const timer = useStructureImmunityTimer(structure as Structure, nextBlockTimestamp || 0);
const timer = structure && isImmune
? useStructureImmunityTimer(structure, nextBlockTimestamp || 0)
: 0;

return (
structure && (
Expand Down
4 changes: 2 additions & 2 deletions client/src/ui/modules/military/battle-view/BattleView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { BattleManager } from "@/dojo/modelManager/BattleManager";
import { useDojo } from "@/hooks/context/DojoContext";
import { useBattleManager } from "@/hooks/helpers/battles/useBattles";
import { getArmiesByBattleId, getArmyByEntityId, useArmyByArmyEntityId } from "@/hooks/helpers/useArmies";
import { useStructureByEntityId, useStructureByPosition } from "@/hooks/helpers/useStructures";
import { Structure, useStructureByEntityId, useStructureByPosition } from "@/hooks/helpers/useStructures";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Improve type safety for Battle component structure prop

The type assertion as Structure on line 147 could be problematic since structure might be undefined (when both structureFromPosition and structureId are undefined). If the Battle component expects a non-null Structure, this could lead to runtime errors.

Consider these improvements:

  1. Add proper type guards:
- structure={structure as Structure}
+ structure={structure || undefined}
  1. Update the Battle component's props to handle optional structure:
interface BattleProps {
  structure?: Structure;
  // ... other props
}
  1. Add runtime validation:
if (structure && !isStructure(structure)) {
  console.warn('Invalid structure provided to Battle component');
}

Also applies to: 147-147

import useUIStore from "@/hooks/store/useUIStore";
import { BattleSide } from "@bibliothecadao/eternum";
import { useMemo } from "react";
Expand Down Expand Up @@ -144,7 +144,7 @@ export const BattleView = () => {
defenderHealth={defenderHealth}
defenderTroops={defenderTroops}
userArmiesInBattle={armies.userArmiesInBattle}
structure={structure}
structure={structure as Structure}
/>
);
};
2 changes: 1 addition & 1 deletion client/src/ui/modules/social/PlayerId.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ export const PlayerId = ({

return (
<div key={structure.entity_id} className="flex flex-col gap-2 border-2 border-gold/10 p-2 rounded-md">
<div className="flex flex-col justify-between text-xs font-bold truncate">
<div className="flex flex-col justify-between text-xs font-bold break-words">
{structure.structureName}
<div className="flex flex-row items-center">
<NavigateToPositionIcon className="!w-5 !h-5" position={structure.position.getNormalized()} />
Expand Down
Loading
Loading