Skip to content

Commit 2adc45b

Browse files
ChloepegCopilot
andauthored
Dyn 10225 add default placeholder images in dynamo app home (#71)
* Add template files support to New dropdown - Enhance CustomDropdown component to support divider and header option types - Add template options to Sidebar "New" dropdown with visual grouping - Add template data structure in home.ts assets - Update dropdown styling for divider and header elements - Add TypeScript types for dropdown option kinds (item/divider/header) - Update package dependencies * Add Templates section to home page - Add Templates section above Recent section on home page - Implement templates data loading from home.ts (dev) and backend (prod) - Add independent grid/list view toggle for Templates section - Add templatesPageViewMode setting for view preference persistence - Map template data structure (date -> DateModified) for component compatibility - Add receiveTemplatesDataFromDotNet window function for backend integration - Add "Templates" translation key to locale files - Reuse existing GraphGridItem and GraphTable components for templates display * Open templates in a new editable workspace from template sidebar dropdown - Add newWorkspaceWithTemplate utility function - Implement listener pattern for template data sharing between Sidebar and PageRecent - Map hardcoded dropdown options to real template files from backend - Update TypeScript types for listener pattern * template data to use React Context - Add TemplatesContext to manage template state centrally - Update Sidebar and PageRecent to use useTemplates() hook - Remove duplicate global handlers to prevent race conditions - Aligns with existing React patterns * Update sidebar to match renamed template files Update template matching logic to use new filenames: - Template 1: matches 'Create a Graph.dyn' (was Template_00_) - Template 2: matches 'Import & Export Workflow.dyn' (was Template_01_) * Drop down menu on side panel removed Drop down menu on side panel removed, will be added back later - Remove Template 1 and Template 2 options from Sidebar dropdown - Remove newWorkspaceWithTemplate function from utility.ts - Remove divider/header support from CustomDropdown component - Remove template data from home.ts assets - Update type definitions to remove template-related types * fix development build TemplatesContext requires templates export in development mode * Fix build errors Fix module path in TemplatesContext.tsx and restore package-lock.json metadata. * Swap Recent and Templates order on home page Display Recent files section above Templates section on the home page. Visual reordering only, there is no functional changes to either section * Add tooltip to Templates heading Add info icon with tooltip to the Templates section title that appears when hovering over the Template heading Changes: - Add tooltip component to Templates title in PageRecent.tsx - Add tooltip text to locale file (en.json) - Extend Tooltip component to support right-side positioning with arrow - Update tooltip styling for wider layout to fit space inbetween - Position tooltip to the right of the title with left-pointing arrow * Move Templates tooltip to question mark icon - Add QuestionMarkIcon import to PageRecent component - Tooltip now appears when hover over the icon instead of the header - Text updated * Adds default placeholder images for template files when thumbnails are missing, showing file-type-specific icons (.dyn, .dyt, .dyf) Add placeholder icon assets for .dyn, .dyt, and .dyf file types - Create placeholder utility function to select icon based on file extension - Update GraphGridItem to use placeholder images when thumbnails are missing - Update CustomNameCellRenderer to use placeholder images in table view * Fix placeholder icon display in GraphGridItem Fix placeholder icons in GraphGridItem to match CustomNameCellRenderer pattern * Update src/components/Common/Tooltip.tsx Remove unused arrowDirection from Tooltip Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Address PR feedback Remove duplicate declare module "*.module.css" entry. Narrow Tooltip position type to 'right' only; default placement is unchanged (below the anchor). 'below' was redundant in the type. Add HomeTemplate in types/index.d.ts and type TemplatesContext / useTemplates() accordingly. Centralize template date display in templateDateDisplay (date vs DateModified); behaviour unchanged. Deduplicate list row click: Recent and Templates share handleRowClick. * Settings persistence pr comments Changes : Stale snapshots when saving : updateAndSaveSettings builds the next object inside setSettings(prev => …) and calls saveHomePageSettings on that merged object, so save: are not based on an outdated settings closure. Sidebar width Resize uses updateAndSaveSettings; the old “save in a useEffect off sideBarWidth” path that could race with context is gone. Recent / templates / samples view modes : Persistence goes through updateAndSaveSettings, templates use the same “local vs prop” idea as recent so the first toggle isn’t blocked, and templates get a defaulted prop from MainContent. No stray saveHomePageSettings in components : It only runs from SettingsContext inside updateAndSaveSettings. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent f8a00b0 commit 2adc45b

23 files changed

Lines changed: 367 additions & 87 deletions

package-lock.json

Lines changed: 16 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/App.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { IntlProvider } from 'react-intl';
44
import { getMessagesForLocale } from './localization/localization';
55
import { LayoutContainer } from './components/LayoutContainer';
66
import { SettingsProvider } from './components/SettingsContext';
7+
import { TemplatesProvider } from './components/TemplatesContext';
78

89
const App = () => {
910
const [locale, setLocale] = useState<Locale>("en");
@@ -25,7 +26,9 @@ const App = () => {
2526
return (
2627
<IntlProvider locale={locale} messages={messages}>
2728
<SettingsProvider>
28-
<LayoutContainer id='homeContainer' />
29+
<TemplatesProvider>
30+
<LayoutContainer id='homeContainer' />
31+
</TemplatesProvider>
2932
</SettingsProvider>
3033
</IntlProvider>
3134
);

src/assets/dyfIcon.png

40.7 KB
Loading

src/assets/dynIcon.png

41.8 KB
Loading

src/assets/dytIcon.png

40.1 KB
Loading

src/assets/home.ts

Lines changed: 13 additions & 7 deletions
Large diffs are not rendered by default.

src/components/Common/Tooltip.tsx

Lines changed: 55 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,78 @@
11
import { useState, useRef, useEffect, CSSProperties } from 'react';
22
import Portal from './Portal'; // Import your Portal component
33

4-
export const Tooltip = ({ children, content, verticalOffset = 12 }: Tooltip) => {
4+
export const Tooltip = ({ children, content, verticalOffset = 12, position: positionProp }: Tooltip) => {
55
const [show, setShow] = useState<boolean>(false);
66
const [position, setPosition] = useState<CSSProperties>({});
77
const tooltipRef = useRef(null);
88
const contentRef = useRef(null); // Ref for the tooltip content
99

1010
useEffect(() => {
1111
if (tooltipRef.current && contentRef.current && show) {
12-
const targetRect = tooltipRef.current.getBoundingClientRect();
13-
const tooltipRect = contentRef.current.getBoundingClientRect();
14-
15-
let left = targetRect.left + window.scrollX + (targetRect.width / 2); // Center align
16-
const top = targetRect.bottom + window.scrollY + verticalOffset;
17-
18-
// Check if the tooltip is going off the right side of the screen
19-
if (left + tooltipRect.width > window.innerWidth) {
20-
left = window.innerWidth - tooltipRect.width / 2 - 10; // Adjust to keep it on screen
21-
}
22-
// Check if the tooltip is going off the left side of the screen
23-
if (left - tooltipRect.width / 2 < 0) {
24-
left += 10; // Adjust to keep it on screen
25-
}
26-
27-
setPosition({
28-
top: top,
29-
left: left,
30-
position: 'absolute'
12+
// Use requestAnimationFrame to ensure tooltip is rendered and measured correctly
13+
requestAnimationFrame(() => {
14+
if (tooltipRef.current && contentRef.current) {
15+
const targetRect = tooltipRef.current.getBoundingClientRect();
16+
const tooltipRect = contentRef.current.getBoundingClientRect();
17+
18+
let left: number;
19+
let top: number;
20+
21+
// If position prop is 'right', position to the right of the element
22+
if (positionProp === 'right') {
23+
left = targetRect.right + window.scrollX + verticalOffset;
24+
top = targetRect.top + window.scrollY + (targetRect.height / 2) - (tooltipRect.height / 2);
25+
26+
// Check if the tooltip is going off the right side of the screen
27+
if (left + tooltipRect.width > window.innerWidth + window.scrollX) {
28+
// If it goes off right, position it to the left of the element instead
29+
left = targetRect.left + window.scrollX - tooltipRect.width - verticalOffset;
30+
}
31+
} else {
32+
// Default: position tooltip below the element (centered)
33+
left = targetRect.left + window.scrollX + (targetRect.width / 2);
34+
top = targetRect.bottom + window.scrollY + verticalOffset;
35+
36+
// Check if the tooltip is going off the right side of the screen
37+
if (left + tooltipRect.width / 2 > window.innerWidth + window.scrollX) {
38+
left = window.innerWidth + window.scrollX - tooltipRect.width / 2 - 10;
39+
}
40+
// Check if the tooltip is going off the left side of the screen
41+
if (left - tooltipRect.width / 2 < window.scrollX) {
42+
left = window.scrollX + tooltipRect.width / 2 + 10;
43+
}
44+
}
45+
46+
// Check if the tooltip is going off the top of the screen
47+
if (top < window.scrollY) {
48+
top = window.scrollY + 10;
49+
}
50+
// Check if the tooltip is going off the bottom of the screen
51+
if (top + tooltipRect.height > window.innerHeight + window.scrollY) {
52+
top = window.innerHeight + window.scrollY - tooltipRect.height - 10;
53+
}
54+
55+
setPosition({
56+
top: top,
57+
left: left,
58+
position: 'absolute',
59+
// For default positioning (below), center using transform
60+
transform: positionProp === 'right' ? 'none' : 'translateX(-50%)'
61+
});
62+
}
3163
});
3264
}
33-
}, [show, content, verticalOffset]); // Added 'content' to dependencies array
65+
}, [show, content, verticalOffset, positionProp]);
3466

3567
return (
36-
<span className="tooltip-wrapper"
68+
<span className="tooltip-wrapper"
3769
onMouseEnter={() => setShow(true)}
3870
onMouseLeave={() => setShow(false)}
3971
ref={tooltipRef}>
4072
{children}
4173
{show && (
4274
<Portal>
43-
<div className={`tooltip-box ${show ? 'show' : ''}`} ref={contentRef} style={position}>
75+
<div className={`tooltip-box ${show ? 'show' : ''} ${positionProp === 'right' ? 'arrow-left' : ''}`} ref={contentRef} style={position}>
4476
<div className="tooltip-arrow" />
4577
<div style={{ whiteSpace: 'pre-line' }}>{content}</div>
4678
</div>

src/components/LayoutContainer.tsx

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,13 @@ import { MainContent } from './MainContent';
33
import { Sidebar } from './Sidebar/Sidebar';
44
import SplitPane from 'react-split-pane';
55
import { useSettings } from './SettingsContext';
6-
import { saveHomePageSettings } from '../functions/utility';
76

87
export const LayoutContainer = ({ id }: { id?: string }) => {
98
const defaultMinSize = 250;
109
const defaultMaxSize = 500;
1110
const defaultBarWidth = 300;
1211

13-
const { settings, updateSettings } = useSettings();
12+
const { settings, updateSettings, updateAndSaveSettings } = useSettings();
1413
const [isDisabled, setIsDisabled] = useState<boolean>(false);
1514
const [selectedSidebarItem, setSelectedSidebarItem] = useState<SidebarItem>('Recent');
1615
const [sideBarWidth, setSideBarWidth] = useState<number | null>(null);
@@ -28,8 +27,8 @@ export const LayoutContainer = ({ id }: { id?: string }) => {
2827
const handleSplitPaneResize = (size: number) => {
2928
setSideBarWidth(size);
3029

31-
// Persist the new sidebar width in settings
32-
updateSettings({ sideBarWidth: size.toString() });
30+
// persist the new sidebar width using latest merged settings.
31+
updateAndSaveSettings({ sideBarWidth: size.toString() });
3332
};
3433

3534
useEffect(() => {
@@ -40,12 +39,6 @@ export const LayoutContainer = ({ id }: { id?: string }) => {
4039
}
4140
}, [settings?.sideBarWidth]);
4241

43-
useEffect(() => {
44-
if (sideBarWidth !== null && settings) {
45-
saveHomePageSettings({ ...settings, sideBarWidth: sideBarWidth.toString() });
46-
}
47-
}, [sideBarWidth]);
48-
4942
const setHomePageSettings = (settingsJson: string) => {
5043
try {
5144
if (settingsJson) {

src/components/MainContent.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ export const MainContent = ({ selectedSidebarItem, settings, isDisabled, setIsDi
1717
)}
1818

1919
<div className={`page-container ${selectedSidebarItem === 'Recent' ? '' : 'hidden'}`}>
20-
<RecentPage setIsDisabled={setIsDisabled} recentPageViewMode={settings?.recentPageViewMode || "grid"} />
20+
<RecentPage
21+
setIsDisabled={setIsDisabled}
22+
recentPageViewMode={settings?.recentPageViewMode || 'grid'}
23+
templatesPageViewMode={settings?.templatesPageViewMode || 'grid'}
24+
/>
2125
</div>
2226
<div className={`page-container ${selectedSidebarItem === 'Samples' ? '' : 'hidden'}`}>
2327
<SamplesPage samplesViewMode={settings?.samplesViewMode || "grid"} />

src/components/Recent/CustomNameCellRenderer.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { img } from '../../assets/home';
1+
import { getPlaceholderImage } from '../../functions/placeholder';
22
import { Tooltip } from '../Common/Tooltip';
33
import styles from './CustomCellRenderer.module.css';
44
import cardStyles from '../Common/CardItems.module.css';
5+
import { img } from '../../assets/home';
56

67

78
/**
@@ -10,7 +11,10 @@ import cardStyles from '../Common/CardItems.module.css';
1011
* @param row - the data associate with this row containing all the information for the graph
1112
*/
1213
export const CustomNameCellRenderer = ({ value, row }: CellParams) => {
13-
const imgSrc = row.original.Thumbnail || img;
14+
// Use placeholder if Thumbnail is empty, null, undefined, or the default img
15+
const thumbnail = row.original.Thumbnail;
16+
const hasCustomThumbnail = thumbnail && thumbnail !== img && thumbnail.trim() !== '';
17+
const imgSrc = hasCustomThumbnail ? thumbnail : getPlaceholderImage(row.original.ContextData);
1418
const description = row.original.Description;
1519
return (
1620
<div className={styles["title-cell"]}>

0 commit comments

Comments
 (0)