Skip to content

Commit bc1cb95

Browse files
committed
fix: render both owned and t0 glyphs
1 parent e565e89 commit bc1cb95

File tree

9 files changed

+79
-50
lines changed

9 files changed

+79
-50
lines changed

cmd/api/src/database/migration/migrations/v8.4.0.sql

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,9 @@ JOIN permissions p
4444
ON CONFLICT DO NOTHING;
4545

4646

47-
-- Explicitly set glyph values for the default asset_group_tags
4847

48+
-- Explicitly set glyph values for the default asset_group_tags
4949
-- Find Tier Zero by position
50-
UPDATE asset_group_tags
51-
SET glyph = 'gem'
52-
WHERE position = 1;
50+
UPDATE asset_group_tags SET glyph = 'gem' WHERE position = 1;
5351
-- Find Owned by type
54-
UPDATE asset_group_tags
55-
SET glyph = 'skull'
56-
WHERE type = 3;
52+
UPDATE asset_group_tags SET glyph = 'skull' WHERE type = 3;

cmd/ui/src/views/Explore/GraphView.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ const GraphView: FC = () => {
7878
const isExploreTableSelected = useAppSelector((state) => state.global.view.isExploreTableSelected);
7979

8080
const customIconsQuery = useCustomNodeKinds({ select: transformIconDictionary });
81-
const tagGlyphMap = useTagGlyphs(glyphUtils, darkMode);
81+
const tagGlyphs = useTagGlyphs(glyphUtils, darkMode);
8282

8383
const autoDisplayTableEnabled = !exploreLayout && !isExploreTableSelected;
8484
const [autoDisplayTable, setAutoDisplayTable] = useExploreTableAutoDisplay(autoDisplayTableEnabled);
@@ -96,9 +96,9 @@ const GraphView: FC = () => {
9696
darkMode,
9797
customIcons: customIconsQuery?.data ?? {},
9898
hideNodes: displayTable,
99-
tagGlyphMap,
99+
tagGlyphs,
100100
};
101-
}, [theme, darkMode, customIconsQuery.data, displayTable, tagGlyphMap]);
101+
}, [theme, darkMode, customIconsQuery.data, displayTable, tagGlyphs]);
102102

103103
// Initialize graph data for rendering with sigmajs
104104
useEffect(() => {

cmd/ui/src/views/Explore/utils.test.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,15 +84,27 @@ describe('Explore utils', () => {
8484
it('uses sequentialLayout by default', () => {
8585
initGraph(
8686
{ nodes: {}, edges: [] },
87-
{ theme: mockTheme as Theme, hideNodes: false, customIcons: {}, darkMode: false, tagGlyphMap: {} }
87+
{
88+
theme: mockTheme as Theme,
89+
hideNodes: false,
90+
customIcons: {},
91+
darkMode: false,
92+
tagGlyphs: {},
93+
}
8894
);
8995

9096
expect(layoutDagreSpy).toBeCalled();
9197
});
9298
it('dedupes edges before adding them to the graph', () => {
9399
const graph = initGraph(
94100
{ nodes: testNodes, edges: testEdgesWithDuplicate },
95-
{ theme: mockTheme as Theme, hideNodes: false, customIcons: {}, darkMode: false, tagGlyphMap: {} }
101+
{
102+
theme: mockTheme as Theme,
103+
hideNodes: false,
104+
customIcons: {},
105+
darkMode: false,
106+
tagGlyphs: {},
107+
}
96108
);
97109

98110
expect(graph.edges().length).toEqual(3);

cmd/ui/src/views/Explore/utils.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
// SPDX-License-Identifier: Apache-2.0
1616

1717
import { Theme } from '@mui/material';
18-
import { GetIconInfo, IconDictionary, getGlyphFromKinds } from 'bh-shared-ui';
18+
import { GetIconInfo, IconDictionary, TagGlyphs, getGlyphFromKinds } from 'bh-shared-ui';
1919
import { MultiDirectedGraph } from 'graphology';
2020
import { random } from 'graphology-layout';
2121
import forceAtlas2 from 'graphology-layout-forceatlas2';
@@ -53,7 +53,7 @@ type GraphOptions = {
5353
darkMode: boolean;
5454
customIcons: IconDictionary;
5555
hideNodes: boolean;
56-
tagGlyphMap: Record<string, string>;
56+
tagGlyphs: TagGlyphs;
5757
themedOptions?: ThemedOptions;
5858
};
5959

@@ -95,7 +95,7 @@ const initGraphNodes = (
9595
nodes: GraphNodes,
9696
options: GraphOptions & { themedOptions: ThemedOptions }
9797
) => {
98-
const { themedOptions, customIcons, hideNodes, tagGlyphMap } = options;
98+
const { themedOptions, customIcons, hideNodes, tagGlyphs } = options;
9999

100100
Object.keys(nodes).forEach((key: string) => {
101101
const node = nodes[key];
@@ -113,11 +113,20 @@ const initGraphNodes = (
113113
nodeParams.image = iconInfo.url || '';
114114
nodeParams.glyphs = [];
115115

116-
const glyphImage = getGlyphFromKinds(node.kinds, tagGlyphMap);
116+
if (node.kinds.includes(tagGlyphs.owned)) {
117+
nodeParams.type = 'glyphs';
118+
nodeParams.glyphs.push({
119+
location: GlyphLocation.BOTTOM_RIGHT,
120+
image: tagGlyphs.ownedGlyph,
121+
...themedOptions.glyph.colors,
122+
});
123+
}
124+
125+
const glyphImage = getGlyphFromKinds(node.kinds, tagGlyphs);
117126
if (glyphImage) {
118127
nodeParams.type = 'glyphs';
119128
nodeParams.glyphs.push({
120-
location: node.isOwnedObject ? GlyphLocation.BOTTOM_RIGHT : GlyphLocation.TOP_RIGHT,
129+
location: GlyphLocation.TOP_RIGHT,
121130
image: glyphImage,
122131
...themedOptions.glyph.colors,
123132
});

packages/javascript/bh-shared-ui/src/components/AssetGroupEdit/AssetGroupEdit.test.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ describe('AssetGroupEdit', () => {
6666

6767
it('should display a total count of asset group members', async () => {
6868
const { screen } = await setup();
69-
const count = screen.getByText('Total Count').nextSibling.textContent;
69+
const count = screen.getByText('Total Count').nextSibling?.textContent;
7070
expect(count).toBe(memberCounts.total_count.toString());
7171
});
7272

@@ -75,7 +75,7 @@ describe('AssetGroupEdit', () => {
7575
const input = screen.getByRole('combobox');
7676

7777
await user.type(input, 'test');
78-
expect(input.value).toEqual('test');
78+
expect(input).toHaveAttribute('value', 'test');
7979

8080
const result = await waitFor(() => screen.getByText('00001.TESTLAB.LOCAL'));
8181
expect(result).toBeInTheDocument();
@@ -86,8 +86,9 @@ describe('AssetGroupEdit', () => {
8686
const selection = searchResults[0];
8787

8888
const input = screen.getByRole('combobox');
89+
8990
await user.type(input, 'test');
90-
expect(input.value).toEqual('test');
91+
expect(input).toHaveAttribute('value', 'test');
9192

9293
const result = await waitFor(() => screen.getByText(selection.name));
9394
await user.click(result);
@@ -105,7 +106,7 @@ describe('AssetGroupEdit', () => {
105106

106107
const input = screen.getByRole('combobox');
107108
await user.type(input, 'test');
108-
expect(input.value).toEqual('test');
109+
expect(input).toHaveAttribute('value', 'test');
109110

110111
const result = await waitFor(() => screen.getByText(selection.name));
111112
await user.click(result);

packages/javascript/bh-shared-ui/src/components/AssetGroupFilters/AssetGroupFilters.test.tsx

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,13 @@
1414
//
1515
// SPDX-License-Identifier: Apache-2.0
1616

17-
import { Screen, waitFor } from '@testing-library/react';
1817
import userEvent from '@testing-library/user-event';
1918
import { AssetGroupMemberCountsResponse, AssetGroupMemberParams } from 'js-client-library';
2019
import { rest } from 'msw';
2120
import { setupServer } from 'msw/node';
2221
import { ActiveDirectoryNodeKind } from '../../graphSchema';
2322
import { createMockAssetGroupMemberParams, createMockMemberCounts } from '../../mocks/factories';
24-
import { act, render } from '../../test-utils';
23+
import { act, render, screen, waitFor } from '../../test-utils';
2524
import AssetGroupFilters, { FILTERABLE_PARAMS } from './AssetGroupFilters';
2625

2726
const filterParams = createMockAssetGroupMemberParams();
@@ -48,7 +47,7 @@ describe('AssetGroupEdit', () => {
4847
}) => {
4948
const user = userEvent.setup();
5049
const handleFilterChange = vi.fn();
51-
const screen: Screen = await act(async () => {
50+
await act(async () => {
5251
return render(
5352
<AssetGroupFilters
5453
filterParams={options?.filterParams ?? {}}
@@ -57,11 +56,11 @@ describe('AssetGroupEdit', () => {
5756
/>
5857
);
5958
});
60-
return { user, screen, handleFilterChange };
59+
return { user, handleFilterChange };
6160
};
6261

6362
it('renders a button that expands the filter section', async () => {
64-
const { screen, user } = await setup({ filterParams, memberCounts });
63+
const { user } = await setup({ filterParams, memberCounts });
6564
const filtersButton = screen.getByTestId('display-filters-button');
6665
const collapsedSection = screen.getByTestId('asset-group-filter-collapsible-section');
6766

@@ -76,15 +75,15 @@ describe('AssetGroupEdit', () => {
7675
});
7776

7877
it('indicates that filters are active', async () => {
79-
const { screen } = await setup({ filterParams, memberCounts });
78+
await setup({ filterParams, memberCounts });
8079

8180
const activeFiltersDot = screen.getByTestId('active-filters-dot');
8281

8382
expect(activeFiltersDot).toHaveStyle({ visibility: 'visible' });
8483
});
8584

8685
it('indicates that filters are inactive', async () => {
87-
const { screen } = await setup();
86+
await setup();
8887

8988
const activeFiltersDot = screen.getByTestId('active-filters-dot');
9089

@@ -93,7 +92,7 @@ describe('AssetGroupEdit', () => {
9392

9493
describe('Node Type dropdown filter', () => {
9594
it('displays the value from filterParams.node_type', async () => {
96-
const { screen } = await setup({ filterParams, memberCounts });
95+
await setup({ filterParams, memberCounts });
9796
const nodeTypeFilter = screen.getByTestId('asset-groups-node-type-filter');
9897
const nodeTypeFilterValue = nodeTypeFilter.firstChild?.nextSibling;
9998

@@ -102,7 +101,7 @@ describe('AssetGroupEdit', () => {
102101
});
103102

104103
it('lists all available node kinds as options to filter by', async () => {
105-
const { screen, user } = await setup({ memberCounts });
104+
const { user } = await setup({ memberCounts });
106105

107106
await user.click(screen.getByTestId('display-filters-button'));
108107
await user.click(screen.getByLabelText('Node Type'));
@@ -117,7 +116,7 @@ describe('AssetGroupEdit', () => {
117116
});
118117

119118
it('calls handleFilterChange when a node type is selected', async () => {
120-
const { screen, user, handleFilterChange } = await setup({ memberCounts });
119+
const { user, handleFilterChange } = await setup({ memberCounts });
121120

122121
const expectedNodeKind = ActiveDirectoryNodeKind.Domain;
123122

@@ -132,14 +131,14 @@ describe('AssetGroupEdit', () => {
132131

133132
describe('Custom Member checkbox filter', () => {
134133
it("displays the checkbox as checked if the filter params value is 'true'", async () => {
135-
const { screen } = await setup({ filterParams: { custom_member: 'eq:true' }, memberCounts });
134+
await setup({ filterParams: { custom_member: 'eq:true' }, memberCounts });
136135
const checkbox = screen.getByTestId('asset-groups-custom-member-filter');
137136

138137
expect((checkbox.firstChild as HTMLInputElement)?.checked).toBe(true);
139138
});
140139

141140
it('invokes handleFilterChange with eq:false when clicked and custom_member filter is on', async () => {
142-
const { screen, user, handleFilterChange } = await setup({ filterParams, memberCounts });
141+
const { user, handleFilterChange } = await setup({ filterParams, memberCounts });
143142
const checkbox = screen.getByTestId('asset-groups-custom-member-filter');
144143

145144
await user.click(checkbox);
@@ -149,7 +148,7 @@ describe('AssetGroupEdit', () => {
149148
});
150149

151150
it('invokes handleFilterChange with eq:true when clicked and custom_member filter is off', async () => {
152-
const { screen, user, handleFilterChange } = await setup();
151+
const { user, handleFilterChange } = await setup();
153152
const checkbox = screen.getByTestId('asset-groups-custom-member-filter');
154153

155154
await user.click(checkbox);
@@ -161,14 +160,14 @@ describe('AssetGroupEdit', () => {
161160

162161
describe('Clear Filters button', () => {
163162
it('has a button with text Clear Filters', async () => {
164-
const { screen } = await setup({ filterParams, memberCounts });
163+
await setup({ filterParams, memberCounts });
165164
const clearFilersButton = screen.getByText('Clear Filters');
166165

167166
expect(clearFilersButton).toBeInTheDocument();
168167
});
169168

170169
it('calls handleFilterChange with all filter types and empty strings when clicked while filters are active', async () => {
171-
const { screen, user, handleFilterChange } = await setup({ filterParams, memberCounts });
170+
const { user, handleFilterChange } = await setup({ filterParams, memberCounts });
172171
const clearFilersButton = screen.getByText('Clear Filters');
173172

174173
await user.click(clearFilersButton);
@@ -180,7 +179,7 @@ describe('AssetGroupEdit', () => {
180179
});
181180

182181
it('is disabled if no filters are active', async () => {
183-
const { screen } = await setup();
182+
await setup();
184183
const clearFilersButton: HTMLButtonElement = screen.getByText('Clear Filters');
185184

186185
expect(clearFilersButton.disabled).toBe(true);

packages/javascript/bh-shared-ui/src/components/HelpTexts/CodeController/CodeController.test.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,27 +15,27 @@
1515
// SPDX-License-Identifier: Apache-2.0
1616

1717
import userEvent from '@testing-library/user-event';
18-
import { Screen, act, render } from '../../../test-utils';
18+
import { act, render, screen } from '../../../test-utils';
1919
import CodeController from './CodeController';
2020

2121
describe('CodeController', () => {
2222
const defaultExpected = 'testing some code to display';
2323
const setup = async (code = defaultExpected) => {
2424
const user = userEvent.setup();
25-
const screen: Screen = await act(async () => {
25+
await act(async () => {
2626
return render(<CodeController>{code}</CodeController>);
2727
});
28-
return { user, screen };
28+
return { user };
2929
};
3030

3131
it('displays the value thats passed via children', async () => {
32-
const { screen } = await setup();
32+
await setup();
3333

3434
expect(screen.getByText(defaultExpected)).toBeInTheDocument();
3535
});
3636

3737
it('defaults to wrapped and removes .wrapped class when unwrap btn is clicked', async () => {
38-
const { screen, user } = await setup();
38+
const { user } = await setup();
3939

4040
expect(screen.getByText(defaultExpected).className.includes('wrapped')).toBeTruthy();
4141

@@ -45,7 +45,7 @@ describe('CodeController', () => {
4545
});
4646

4747
it('copys children value to clipboard after clicking the copy btn', async () => {
48-
const { screen, user } = await setup();
48+
const { user } = await setup();
4949

5050
await user.click(screen.getByText('copy'));
5151

@@ -56,7 +56,7 @@ describe('CodeController', () => {
5656

5757
it('indicates the code container is scrollable when the code is unwrapped', async () => {
5858
const expected = Array(10).fill('testing large code block').join(' ');
59-
const { screen, user } = await setup(expected);
59+
const { user } = await setup(expected);
6060

6161
await user.click(screen.getByText('Unwrap'));
6262

packages/javascript/bh-shared-ui/src/hooks/useAssetGroupTags/useAssetGroupTags.tsx

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ export const glyphUtils: GlyphUtils = {
130130
transformer: glyphTransformer,
131131
};
132132

133+
export const TagLabelPrefix = 'Tag_' as const;
134+
133135
export const createGlyphMapFromTags = (
134136
tags: AssetGroupTag[] | undefined,
135137
utils: GlyphUtils,
@@ -141,11 +143,18 @@ export const createGlyphMapFromTags = (
141143
tags?.forEach((tag) => {
142144
const underscoredTagName = tag.name.split(' ').join('_');
143145

144-
if (tag.glyph !== null && qualifier(tag.glyph)) {
145-
const glyphValue = transformer(tag.glyph, darkMode);
146+
if (tag.glyph === null) return;
147+
if (!qualifier(tag.glyph)) return;
148+
149+
const glyphValue = transformer(tag.glyph, darkMode);
146150

147-
if (glyphValue !== '') glyphMap[`Tag_${underscoredTagName}`] = glyphValue;
151+
if (tag.type === AssetGroupTagTypeOwned) {
152+
glyphMap.owned = `${TagLabelPrefix}${underscoredTagName}`;
153+
glyphMap.ownedGlyph = glyphValue;
154+
return;
148155
}
156+
157+
if (glyphValue !== '') glyphMap[`${TagLabelPrefix}${underscoredTagName}`] = glyphValue;
149158
});
150159

151160
return glyphMap;
@@ -154,14 +163,17 @@ export const createGlyphMapFromTags = (
154163
export const getGlyphFromKinds = (kinds: string[] = [], tagGlyphMap: Record<string, string> = {}): string | null => {
155164
for (let index = kinds.length - 1; index > -1; index--) {
156165
const kind = kinds[index];
157-
if (!kind.includes('Tag_')) continue;
166+
167+
if (!kind.includes(TagLabelPrefix)) continue;
158168

159169
if (tagGlyphMap[kind]) return tagGlyphMap[kind];
160170
}
161171
return null;
162172
};
163173

164-
export const useTagGlyphs = (glyphUtils: GlyphUtils, darkMode?: boolean) => {
174+
export type TagGlyphs = Record<string, string>;
175+
176+
export const useTagGlyphs = (glyphUtils: GlyphUtils, darkMode?: boolean): TagGlyphs => {
165177
const [glyphMap, setGlyphMap] = useState<Record<string, string>>({});
166178
const tagsQuery = useAssetGroupTags();
167179

0 commit comments

Comments
 (0)