diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 09627d83..013fff62 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
node-version: "${{ env.NODE }}"
diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml
index 2fb9f934..74518112 100644
--- a/.github/workflows/eslint.yml
+++ b/.github/workflows/eslint.yml
@@ -26,7 +26,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
fetch-depth: 0
diff --git a/.github/workflows/git-command.yml b/.github/workflows/git-command.yml
index 9c17ff7c..b9185c83 100644
--- a/.github/workflows/git-command.yml
+++ b/.github/workflows/git-command.yml
@@ -19,7 +19,7 @@ jobs:
run: echo "$PAYLOAD_CONTEXT"
- name: Checkout on chat command
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
token: ${{ secrets.GIT_PAT }}
repository: ${{ github.event.client_payload.pull_request.head.repo.full_name }}
diff --git a/src/components/CandidateTaskView/CandidateTaskView.js b/src/components/CandidateTaskView/CandidateTaskView.js
deleted file mode 100644
index 0338a76a..00000000
--- a/src/components/CandidateTaskView/CandidateTaskView.js
+++ /dev/null
@@ -1,183 +0,0 @@
-import { observer } from "mobx-react";
-import React, { forwardRef, useCallback, useRef } from "react";
-import { Block, Elem } from "../../utils/bem";
-import { Spinner } from "../Common/Spinner";
-import "./CandidateTaskView.styl";
-import { getRoot } from "mobx-state-tree";
-import { useEffect, useState } from "react";
-import { format } from "date-fns";
-import { FF_LSDV_4711, isFF } from "../../utils/feature-flags";
-
-const imgDefaultProps = {};
-
-if (isFF(FF_LSDV_4711)) imgDefaultProps.crossOrigin = 'anonymous';
-
-const DataItemVisual = forwardRef(({ columns, dataKey, data }, imageRef) => {
- const [isInProgress, setIsInProgress] = useState();
- const [fileContent, setFileContent] = useState();
- const [isFileError, setIsFileError] = useState(false);
- const isUrlData = /https?:\/\/.*/.test(data);
- const columnDefinition = columns.find(colData => colData.alias === dataKey);
-
- useEffect(async () => {
- if ( isUrlData && columnDefinition?.currentType === "Text" ) {
- setIsInProgress(true);
- setIsFileError(false);
- let response;
-
- try {
- response = await fetch(data);
- } catch (ex) {
- response = ex;
- }
-
- if (response?.status === 200) {
- setFileContent(await response.text());
- } else {
- console.error("Error:", response);
- setIsFileError(true);
- }
- setIsInProgress(false);
- }
- }, [isUrlData, data, columnDefinition]);
-
- if (columnDefinition?.currentType === "Image") {
- return (
-
-
-
- );
- } else if (columnDefinition?.currentType === "Text" && isUrlData && !isFileError) {
- return (
-
- {isInProgress ? : (
-
- {fileContent}
-
- )}
-
- );
- } else if (isUrlData) {
- return (
-
- {data}
-
- );
- }
- return (
-
- {data}
-
- );
-});
-
-const AttributeRow = (({ fieldName, value }) => {
- return (
-
- {fieldName}
- {value}
-
- );
-});
-const dateDisplayFormat = "MMM dd, yyyy HH:mm a";
-
-export const CandidateTaskView = observer(({ item, columns }) => {
- const { candidate_task_id, id, data, exported } = item;
- const dataset = getRoot(item)?.SDK?.dataset;
- const [fName, setFName] = useState();
- const [fType, setFType] = useState();
- const [mType, setMType] = useState();
- const [created, setCreated] = useState();
- const [modified, setModified] = useState();
- const [size, setSize] = useState();
- const [dimensions, setDimensions] = useState([]);
- const [bucket, setBucket] = useState();
- const imgRef = useRef({});
- const associatedList = getRoot(item).taskStore.associatedList;
-
- useEffect(() => {
- const setDefaultMetadata = async () => {
- const { metadata } = await getRoot(item).apiCall("candidateTaskMeta", {
- candidate_task_id,
- });
-
- if (metadata) {
- setFName(metadata.name.split('/').pop());
- setFType(metadata.contentType.split('/').shift());
- setMType(metadata.contentType);
- setCreated(metadata.timeCreated ? format(new Date(metadata.timeCreated), dateDisplayFormat) : "");
- setModified(metadata.updated ? format(new Date(metadata.updated), dateDisplayFormat) : "");
- setSize(`${new Intl.NumberFormat().format(parseInt(metadata.size))} bytes`);
- setBucket(metadata.bucket);
- setDimensions(Object.values(imgRef.current).map(ref => `${ref?.naturalWidth ?? 0} x ${ref?.naturalHeight ?? 0} px`));
- }
- };
-
- setDefaultMetadata();
- }, [candidate_task_id]);
-
-
- return (
-
-
- {Object.entries(data).map( ([dataKey, dataValue]) => (
- imgRef.current[dataKey] = ele} />
- ))}
-
-
-
- File Attributes
- {fName}
-
-
-
- General
-
-
-
-
-
-
-
- {dim})}/>
-
-
-
-
- Origin Storage
-
-
-
-
-
-
-
- Projects
- {
- (associatedList.length && exported.length) ? (
- exported.map((exportedEntry, index) => {
- const { project_id, created_at } = exportedEntry;
- const associtedRecord = associatedList?.find(associatedItem => associatedItem?.id === project_id);
- const { title, workspace } = associtedRecord;
- const clickHandler = useCallback(e => {
- e.preventDefault();
- window.open(`/projects/${project_id}/data`, '_self');
- }, [project_id]);
-
- return (
-
- {workspace?.length && `${workspace.join(" - ")} / `}{title}
- {created_at && Added {format(new Date(created_at), dateDisplayFormat)}}
-
- );
- })
- ) : (
- <>This file hasn’t been imported to any projects.>
- )
- }
-
-
-
-
- );
-});
\ No newline at end of file
diff --git a/src/components/CandidateTaskView/CandidateTaskView.styl b/src/components/CandidateTaskView/CandidateTaskView.styl
deleted file mode 100644
index 0474a206..00000000
--- a/src/components/CandidateTaskView/CandidateTaskView.styl
+++ /dev/null
@@ -1,116 +0,0 @@
-.candidate-task-view
- --border-color rgba(137, 128, 152, 0.12)
- --border-color-hard rgba(137, 128, 152, 0.16)
- display flex
- gap 16px
- align-items stretch
- &__data-display-container
- display flex
- flex 1 auto
- flex-direction column
- gap 16px
- &__data-display
- border 1px solid var(--border-color-hard)
- flex 1 auto
- &_image
- background linear-gradient(0deg, rgba(9, 109, 217, 0.05), rgba(9, 109, 217, 0.05)), #FAFAFA
- display flex
- align-items center
- justify-content center
- img
- display block
- max-width 100%
- height auto
- width auto
- max-height: calc(80vh - var(--header-height) - var(--ribbon-height));
- &_text,
- &_link
- padding 12px 16px
- &__details
- background-color #FAFAFA
- border-radius 8px
- display flex
- width 256px
- border 1px solid var(--border-color-hard)
- flex-direction column
- flex-shrink 0
- &__title
- font-style normal
- font-weight 500
- font-size 16px
- line-height 24px
- letter-spacing 0.1px
- color #1F1F1F
- &__detailContainer
- padding 16px
- border-top 1px solid var(--border-color)
- &:first-child
- border-top 0
- &__detailSubContainer
- border-top 1px solid var(--border-color)
- padding 18px 0 8px
- &:first-child
- border-top 0
- padding-top 0
- &__subtitle
- font-family 'Roboto'
- font-weight 500
- font-size 12px
- line-height 16px
- letter-spacing 0.5px
- color #898098
- margin-bottom 16px
- &__detailContent
- font-family 'Roboto'
- font-weight 400
- font-size 12px
- line-height 16px
- letter-spacing 0.4px
- color #898098
-
-.attributeRow
- display flex
- justify-content space-between
- font-family 'Roboto'
- margin-top 8px
- flex-wrap wrap
- &__name
- font-weight 500
- font-size 12px
- line-height 16px
- letter-spacing 0.5px
- color #1F1F1F
- &__value
- font-weight 400
- font-size 12px
- line-height 16px
- letter-spacing 0.4px
- color #1F1F1F
- overflow auto
- &:first-child
- margin-top 0
-
-.projectNav
- margin-top 8px
- cursor pointer
- &:first-child
- margin-top 0
- &__name
- font-weight 500
- font-size 11px
- line-height 16px
- letter-spacing 0.5px
- color #096DD9
- &__date
- font-weight 400
- font-size 12px
- line-height 16px
- letter-spacing 0.4px
- color #898098
-
-@media (max-width 600px)
- .candidate-task-view
- flex-direction column
- &__details
- width auto
- flex 1 auto
\ No newline at end of file
diff --git a/src/components/CandidateTaskView/index.js b/src/components/CandidateTaskView/index.js
deleted file mode 100644
index 755a60b5..00000000
--- a/src/components/CandidateTaskView/index.js
+++ /dev/null
@@ -1,2 +0,0 @@
-import { CandidateTaskView } from "./CandidateTaskView";
-export { CandidateTaskView };
\ No newline at end of file
diff --git a/src/components/CellViews/index.js b/src/components/CellViews/index.js
index af9a0cd5..b4dd6c5f 100644
--- a/src/components/CellViews/index.js
+++ b/src/components/CellViews/index.js
@@ -11,4 +11,5 @@ export { DateTimeCell as Date, DateTimeCell as Datetime } from "./DateTimeCell";
export { ImageCell as Image } from "./ImageCell";
export { NumberCell as Number } from "./NumberCell";
export { StringCell as String } from "./StringCell";
+export { StringCell as Text } from "./StringCell";
export { VideoCell as Video } from "./VideoCell";
diff --git a/src/components/Common/SkeletonLoader/SkeletonGap.tsx b/src/components/Common/SkeletonLoader/SkeletonGap.tsx
new file mode 100644
index 00000000..68b66000
--- /dev/null
+++ b/src/components/Common/SkeletonLoader/SkeletonGap.tsx
@@ -0,0 +1,7 @@
+import { Elem } from '../../../utils/bem';
+
+export const SkeletonGap = ({ height = "4px" }: { height?: string }) => {
+ return (
+
+ );
+};
diff --git a/src/components/Common/SkeletonLoader/SkeletonLine.tsx b/src/components/Common/SkeletonLoader/SkeletonLine.tsx
new file mode 100644
index 00000000..4c9d0abb
--- /dev/null
+++ b/src/components/Common/SkeletonLoader/SkeletonLine.tsx
@@ -0,0 +1,14 @@
+import { Elem } from '../../../utils/bem';
+
+export const SkeletonLine = ({ lineCount = 1, width = "60%", height = "16px" }: { lineCount?: number, width?: string, height?: string }) => {
+ const rows = [];
+
+ for(let i = 0; i < lineCount; i++) {
+ rows.push();
+ }
+ return (
+ <>
+ {rows}
+ >
+ );
+};
diff --git a/src/components/Common/SkeletonLoader/SkeletonLoader.styl b/src/components/Common/SkeletonLoader/SkeletonLoader.styl
new file mode 100644
index 00000000..b8f3cd3b
--- /dev/null
+++ b/src/components/Common/SkeletonLoader/SkeletonLoader.styl
@@ -0,0 +1,45 @@
+.skeletonLoader
+ --skeleton-light-color linear-gradient(0deg, rgba(9, 109, 217, 0.05), rgba(9, 109, 217, 0.05)), #FAFAFA
+ --skeleton-dark-color linear-gradient(0deg, rgba(9, 109, 217, 0.14), rgba(9, 109, 217, 0.14)), #FAFAFA
+ --skeleton-gap 4px
+ box-sizing border-box
+ display flex
+ flex-direction column
+ justify-content space-between
+ gap var(--skeleton-gap)
+ position relative
+ width 100%
+ flex 0 0 auto
+ margin-left 0
+ z-index 1
+ color transparent
+ &__line
+ --line-width 60%
+ --line-height 16px
+ height var(--line-height)
+ width var(--line-width)
+ min-width 20px
+ border-radius 8px
+ display block
+ background var(--skeleton-light-color)
+ animation-name: skeleton-animation;
+ animation-timing-function ease-in-out
+ animation-duration 0.5s
+ animation-iteration-count: infinite;
+ animation-direction: alternate;
+ &__gap
+ --height 8px
+ height var(--height)
+
+
+@keyframes skeleton-animation
+ 0%
+ background var(--skeleton-light-color)
+ opacity 1
+
+ 50%
+ opacity 0.8
+
+ 100%
+ background var(--skeleton-dark-color)
+ opacity 1
\ No newline at end of file
diff --git a/src/components/Common/SkeletonLoader/SkeletonLoader.tsx b/src/components/Common/SkeletonLoader/SkeletonLoader.tsx
new file mode 100644
index 00000000..7144b83b
--- /dev/null
+++ b/src/components/Common/SkeletonLoader/SkeletonLoader.tsx
@@ -0,0 +1,32 @@
+import React, { ReactChildren } from 'react';
+import './SkeletonLoader.styl';
+import { Block } from '../../../utils/bem';
+import { SkeletonLine } from './SkeletonLine';
+import { SkeletonGap } from './SkeletonGap';
+
+interface SkeletonLoaderProps {
+ children?: ReactChildren,
+ gap?: string,
+ lightColor?: string,
+ darkColor?: string,
+}
+
+export const SkeletonLoader = ({ children, gap = "4px", lightColor, darkColor }: SkeletonLoaderProps) => {
+ const styles:any = { "--skeleton-gap": gap };
+
+ lightColor && (styles["--skeleton-light-color"] = lightColor);
+ darkColor && (styles["--skeleton-dark-color"] = darkColor);
+
+ return (
+
+ {children ? children : (
+ <>
+
+
+
+
+ >
+ )}
+
+ );
+};
diff --git a/src/components/Common/SkeletonLoader/index.tsx b/src/components/Common/SkeletonLoader/index.tsx
new file mode 100644
index 00000000..381941a4
--- /dev/null
+++ b/src/components/Common/SkeletonLoader/index.tsx
@@ -0,0 +1,3 @@
+export { SkeletonLoader } from "./SkeletonLoader";
+export { SkeletonLine } from "./SkeletonLine";
+export { SkeletonGap } from "./SkeletonGap";
\ No newline at end of file
diff --git a/src/components/Common/Table/TableRow/TableRow.js b/src/components/Common/Table/TableRow/TableRow.js
index b854d425..0d328a76 100644
--- a/src/components/Common/Table/TableRow/TableRow.js
+++ b/src/components/Common/Table/TableRow/TableRow.js
@@ -5,6 +5,8 @@ import { Block } from "../../../../utils/bem";
import { TableContext, TableElem } from "../TableContext";
import { getProperty, getStyle } from "../utils";
import "./TableRow.styl";
+import { SkeletonLoader } from "../../SkeletonLoader";
+import { FF_LOPS_E_3, isFF } from "../../../../utils/feature-flags";
const CellRenderer = observer(
({ col: colInput, data, decoration, cellViews }) => {
@@ -29,6 +31,7 @@ const CellRenderer = observer(
const renderProps = { column: col, original: data, value };
const Decoration = decoration?.get?.(col);
const style = getStyle(cellViews, col, Decoration);
+ const cellIsLoading = isFF(FF_LOPS_E_3) && data.loading === colInput.alias;
return (
@@ -37,10 +40,10 @@ const CellRenderer = observer(
...(style ?? {}),
display: "flex",
height: "100%",
- alignItems: "center",
+ alignItems: cellIsLoading ? "" : "center",
}}
>
- {Renderer ? : value}
+ {cellIsLoading ? : (Renderer ? : value)}
);
diff --git a/src/components/Common/TableOld/Table.js b/src/components/Common/TableOld/Table.js
index fcf88f9e..4fde4dbd 100644
--- a/src/components/Common/TableOld/Table.js
+++ b/src/components/Common/TableOld/Table.js
@@ -398,6 +398,8 @@ const StickyList = observer(
itemCount={totalCount}
loadMoreItems={loadMore}
isItemLoaded={isItemLoaded}
+ threshold={5}
+ minimumBatchSize={30}
>
{({ onItemsRendered, ref }) => (
{
@@ -29,6 +31,7 @@ const CellRenderer = observer(
const renderProps = { column: col, original: data, value };
const Decoration = decoration?.get?.(col);
const style = getStyle(cellViews, col, Decoration);
+ const cellIsLoading = isFF(FF_LOPS_E_3) && data.loading === colInput.alias;
return (
@@ -37,10 +40,10 @@ const CellRenderer = observer(
...(style ?? {}),
display: "flex",
height: "100%",
- alignItems: "center",
+ alignItems: cellIsLoading ? "" : "center",
}}
>
- {Renderer ? : value}
+ {cellIsLoading ? : (Renderer ? : value)}
);
diff --git a/src/components/DataManager/Toolbar/ActionsButton.js b/src/components/DataManager/Toolbar/ActionsButton.js
index 28c2a91d..a38403f7 100644
--- a/src/components/DataManager/Toolbar/ActionsButton.js
+++ b/src/components/DataManager/Toolbar/ActionsButton.js
@@ -135,7 +135,7 @@ export const ActionsButton = injector(observer(({ store, size, hasSelected, ...r
};
const actionButtons = actions.map(ActionButton);
- const recordTypeLabel = isFFLOPSE3 && store.SDK.type === "DE" ? "Item" : "Task";
+ const recordTypeLabel = isFFLOPSE3 && store.SDK.type === "DE" ? "Record" : "Task";
return (
isFFLOPSE3 && setIsOpen(visible)}
>