Skip to content
This repository has been archived by the owner on Apr 18, 2024. It is now read-only.

Commit

Permalink
fix: DIA-743: [FE] Blank space is displayed instead of the records on…
Browse files Browse the repository at this point in the history
… scroll up/down
  • Loading branch information
yyassi-heartex committed Dec 1, 2023
1 parent 93aaec6 commit ec6c703
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 50 deletions.
13 changes: 12 additions & 1 deletion src/components/CellViews/ImageCell.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { getRoot } from "mobx-state-tree";
import { FF_LSDV_4711, isFF } from "../../utils/feature-flags";
import { AnnotationPreview } from "../Common/AnnotationPreview/AnnotationPreview";
import { useRef } from "react";
import { useImageProvider } from "../../providers/ImageProvider";

const imgDefaultProps = {};

Expand All @@ -13,23 +15,32 @@ export const ImageCell = (column) => {
column: { alias },
} = column;
const root = getRoot(original);
const imgRef = useRef();
const { getImage } = useImageProvider();

const renderImagePreview = original.total_annotations === 0 || !root.showPreviews;
const imgSrc = Array.isArray(value) ? value[0] : value;

if (!imgSrc) return null;
getImage(imgSrc).then((loadedImage) => {
if (imgRef.current && loadedImage.loaded && loadedImage.url) {
imgRef.current.setAttribute("src", loadedImage.url);
imgRef.current.style.display = "";
}
});

return renderImagePreview ? (
<img
{...imgDefaultProps}
ref={imgRef}
key={imgSrc}
src={imgSrc}
alt="Data"
style={{
maxHeight: "100%",
maxWidth: "100px",
objectFit: "contain",
borderRadius: 3,
display: "none",
}}
/>
) : (
Expand Down
27 changes: 15 additions & 12 deletions src/components/DataManager/DataManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { FiltersSidebar } from "../Filters/FiltersSidebar/FilterSidebar";
import { DataView } from "../MainView";
import "./DataManager.styl";
import { Toolbar } from "./Toolbar/Toolbar";
import { ImageProvider } from "../../providers/ImageProvider";

const injector = inject(({ store }) => {
const { sidebarEnabled, sidebarVisible } = store.viewsStore ?? {};
Expand Down Expand Up @@ -127,19 +128,21 @@ const TabsSwitch = switchInjector(observer(({ sdk, views, tabs, selectedKey }) =

export const DataManager = injector(({ shrinkWidth }) => {
return (
<Block name="tabs-content">
<Elem name="tab" mod={{ shrink: shrinkWidth }}>
<Interface name="tabs">
<TabsSwitch />
</Interface>
<ImageProvider key="app-image-provider">
<Block name="tabs-content">
<Elem name="tab" mod={{ shrink: shrinkWidth }}>
<Interface name="tabs">
<TabsSwitch />
</Interface>

<Interface name="toolbar">
<Toolbar />
</Interface>
<Interface name="toolbar">
<Toolbar />
</Interface>

<DataView />
</Elem>
<FiltersSidebar />
</Block>
<DataView />
</Elem>
<FiltersSidebar />
</Block>
</ImageProvider>
);
});
77 changes: 40 additions & 37 deletions src/components/Label/Label.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Resizer } from "../Common/Resizer/Resizer";
import { Space } from "../Common/Space/Space";
import { DataView } from "../MainView";
import "./Label.styl";
import { ImageProvider } from "../../providers/ImageProvider";

const LabelingHeader = ({ SDK, onClick, isExplorerMode }) => {
return (
Expand Down Expand Up @@ -99,45 +100,47 @@ export const Labeling = injector(observer(({
const outlinerEnabled = isFF(FF_DEV_1170);

return (
<Block name="label-view" mod={{ loading }}>
{SDK.interfaceEnabled("labelingHeader") && (
<LabelingHeader
SDK={SDK}
onClick={closeLabeling}
isExplorerMode={isExplorerMode}
/>
)}

<Elem name="content">
{isExplorerMode && (
<Elem name="table">
<Elem
tag={Resizer}
name="dataview"
minWidth={200}
showResizerLine={false}
type={'quickview'}
maxWidth={window.innerWidth * 0.35}
initialWidth={view.labelingTableWidth} // hardcoded as in main-menu-trigger
onResizeFinished={onResize}
style={{ display: "flex", flex: 1, width: '100%' }}
>
<DataView />
</Elem>
</Elem>
<ImageProvider key="app-image-provider">
<Block name="label-view" mod={{ loading }}>
{SDK.interfaceEnabled("labelingHeader") && (
<LabelingHeader
SDK={SDK}
onClick={closeLabeling}
isExplorerMode={isExplorerMode}
/>
)}

<Elem name="lsf-wrapper" mod={{ mode: isExplorerMode ? "explorer" : "labeling" }}>
{loading && <Elem name="waiting" mod={{ animated: true }}/>}
<Elem
ref={lsfRef}
id="label-studio-dm"
name="lsf-container"
key="label-studio"
mod={{ outliner: outlinerEnabled }}
/>
<Elem name="content">
{isExplorerMode && (
<Elem name="table">
<Elem
tag={Resizer}
name="dataview"
minWidth={200}
showResizerLine={false}
type={'quickview'}
maxWidth={window.innerWidth * 0.35}
initialWidth={view.labelingTableWidth} // hardcoded as in main-menu-trigger
onResizeFinished={onResize}
style={{ display: "flex", flex: 1, width: '100%' }}
>
<DataView />
</Elem>
</Elem>
)}

<Elem name="lsf-wrapper" mod={{ mode: isExplorerMode ? "explorer" : "labeling" }}>
{loading && <Elem name="waiting" mod={{ animated: true }}/>}
<Elem
ref={lsfRef}
id="label-studio-dm"
name="lsf-container"
key="label-studio"
mod={{ outliner: outlinerEnabled }}
/>
</Elem>
</Elem>
</Elem>
</Block>
</Block>
</ImageProvider>
);
}));
81 changes: 81 additions & 0 deletions src/providers/ImageProvider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React, { useCallback, useContext, useMemo, useRef } from "react";

export const ImageContext = React.createContext({});
ImageContext.displayName = "ImageContext";

export const ImageProvider = ({ children }) => {
const loadedImagesRef = useRef(new Map());
const getImage = useCallback((imgSrc) => {
const loadedImages = loadedImagesRef.current;

if (loadedImages.has(imgSrc)) {
const loadedImage = loadedImages.get(imgSrc);

return loadedImage.promise;
}
const imageFetchPromise = fetch(imgSrc)
.then((response) => {
const reader = response.body.getReader();

return new ReadableStream({
start(controller) {
return pump();
function pump() {
return reader.read().then(({ done, value }) => {
// When no more data needs to be consumed, close the stream
if (done) {
controller.close();
return;
}
// Enqueue the next data chunk into our target stream
controller.enqueue(value);
return pump();
});
}
},
});
})
// Create a new response out of the stream
.then((stream) => new Response(stream))
// Create an object URL for the response
.then((response) => response.blob())
.then((blob) => URL.createObjectURL(blob))
// Update image
.then((url) => {
loadedImages.set(imgSrc, {
url,
promise: imageFetchPromise,
loaded: true,
});
return loadedImages.get(imgSrc);
})
.catch((err) => {
console.error(err);
return loadedImages.get(imgSrc);
});

loadedImages.set(imgSrc, {
url: imgSrc,
promise: imageFetchPromise,
loaded: false,
});

return imageFetchPromise;
}, []);
const contextValue = useMemo(() => {
return {
loadedImages: loadedImagesRef.current,
getImage,
};
}, [getImage]);

return (
<ImageContext.Provider value={contextValue}>
{children}
</ImageContext.Provider>
);
};

export const useImageProvider = () => {
return useContext(ImageContext) ?? {};
};

0 comments on commit ec6c703

Please sign in to comment.