Skip to content

Commit

Permalink
Merge branch 'main' into update-dist
Browse files Browse the repository at this point in the history
  • Loading branch information
sjd78 authored Sep 9, 2024
2 parents 2a04002 + 7cd3ebb commit 66190cd
Show file tree
Hide file tree
Showing 10 changed files with 271 additions and 75 deletions.
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# - https://github.com/konveyor/tackle2-ui/pull/1781

# Builder image
FROM registry.access.redhat.com/ubi9/nodejs-20:1-54.1724037697 as builder
FROM registry.access.redhat.com/ubi9/nodejs-20:1-59 as builder

USER 1001
COPY --chown=1001 . .
Expand All @@ -21,7 +21,7 @@ RUN \
npm run dist

# Runner image
FROM registry.access.redhat.com/ubi9/nodejs-20-minimal:1-57.1724037293
FROM registry.access.redhat.com/ubi9/nodejs-20-minimal:1-63

# Add ps package to allow liveness probe for k8s cluster
# Add tar package to allow copying files with kubectl scp
Expand Down
3 changes: 2 additions & 1 deletion client/public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@
"issuesEffortTooltip": "This column shows the effort weight for a single issue incident.",
"dependentQuestionTooltip": "This question is conditionally included or excluded based on tags:",
"jiraInstanceNotConnected": "Jira instance {{name}} is not connected.",
"loadingTripleDot": "Loading...",
"manageDependenciesInstructions": "Add northbound and southbound dependencies for the selected application here. Note that any selections made will be saved automatically. To undo any changes, you must manually delete the applications from the dropdowns.",
"noDataAvailableBody": "No data available to be shown here.",
"noDataAvailableTitle": "No data available",
Expand Down Expand Up @@ -526,7 +527,7 @@
},
"tooltip": {
"priority": "Tasks priority, a non-negative number, impacts tasks scheduling policy. Lowest priority is 0. Higher priority tasks run before lower priority tasks.",
"preemption": "If enabled, allows the scheduler to cancel a running task and free the resources for higher priority tasks."
"preemption": "If enabled, allows the scheduler to reschedule other running tasks to free cluster resources needed to run higher priority tasks."
},
"validation": {
"email": "This field requires a valid email.",
Expand Down
1 change: 1 addition & 0 deletions client/src/app/components/FilterToolbar/FilterToolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ export const FilterToolbar = <TItem, TFilterCategoryKey extends string>({
{!showFiltersSideBySide && (
<ToolbarItem>
<Dropdown
onOpenChange={(flag) => setIsCategoryDropdownOpen(flag)}
toggle={(toggleRef) => (
<MenuToggle
id="filtered-by"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.infinite-scroll-sentinel {
width: 100%;
text-align: center;
font-style: italic;
font-weight: bold;
}
61 changes: 61 additions & 0 deletions client/src/app/components/InfiniteScroller/InfiniteScroller.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React, { ReactNode, useEffect, useRef } from "react";
import { useTranslation } from "react-i18next";
import { useVisibilityTracker } from "./useVisibilityTracker";
import "./InfiniteScroller.css";

export interface InfiniteScrollerProps {
// content to display
children: ReactNode;
// function triggered if sentinel node is visible to load more items
// returns false if call was rejected by the scheduler
fetchMore: () => boolean;
hasMore: boolean;
// number of items currently displayed/known
itemCount: number;
}

export const InfiniteScroller = ({
children,
fetchMore,
hasMore,
itemCount,
}: InfiniteScrollerProps) => {
const { t } = useTranslation();
// Track how many items were known at time of triggering the fetch.
// This allows to detect edge case when second(or more) fetchMore() is triggered before
// IntersectionObserver is able to detect out-of-view event.
// Initializing with zero ensures that the effect will be triggered immediately
// (parent is expected to display empty state until some items are available).
const itemCountRef = useRef(0);
const { visible: isSentinelVisible, nodeRef: sentinelRef } =
useVisibilityTracker({
enable: hasMore,
});

useEffect(
() => {
if (
isSentinelVisible &&
itemCountRef.current !== itemCount &&
fetchMore() // fetch may be blocked if background refresh is in progress (or other manual fetch)
) {
// fetchMore call was triggered (it may fail but will be subject to React Query retry policy)
itemCountRef.current = itemCount;
}
},
// reference to fetchMore() changes based on query state and ensures that the effect is triggered in the right moment
// i.e. after fetch triggered by the previous fetchMore() call finished
[isSentinelVisible, fetchMore, itemCount]
);

return (
<div>
{children}
{hasMore && (
<div ref={sentinelRef} className="infinite-scroll-sentinel">
{t("message.loadingTripleDot")}
</div>
)}
</div>
);
};
1 change: 1 addition & 0 deletions client/src/app/components/InfiniteScroller/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./InfiniteScroller";
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { useEffect, useRef, useState, useCallback } from "react";

export function useVisibilityTracker({ enable }: { enable: boolean }) {
const nodeRef = useRef<HTMLDivElement>(null);
const [visible, setVisible] = useState(false);
const node = nodeRef.current;

// state is set from IntersectionObserver callbacks which may not align with React lifecycle
// we can add extra safety by using the same approach as Console's useSafetyFirst() hook
// https://github.com/openshift/console/blob/9d4a9b0a01b2de64b308f8423a325f1fae5f8726/frontend/packages/console-dynamic-plugin-sdk/src/app/components/safety-first.tsx#L10
const mounted = useRef(true);
useEffect(
() => () => {
mounted.current = false;
},
[]
);
const setVisibleSafe = useCallback((newValue) => {
if (mounted.current) {
setVisible(newValue);
}
}, []);

useEffect(() => {
if (!enable || !node) {
return undefined;
}

// Observer with default options - the whole view port used.
// Note that if root element is used then it needs to be the ancestor of the target.
// In case of infinite scroller the target is always within the (scrollable!)parent
// even if the node is technically hidden from the user.
// https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#root
const observer = new IntersectionObserver(
(entries: IntersectionObserverEntry[]) =>
entries.forEach(({ isIntersecting }) => {
if (isIntersecting) {
setVisibleSafe(true);
} else {
setVisibleSafe(false);
}
})
);
observer.observe(node);

return () => {
observer.disconnect();
setVisibleSafe(false);
};
}, [enable, node, setVisibleSafe]);

return {
/**
* Is the node referenced via `nodeRef` currently visible on the page?
*/
visible,
/**
* A ref to a node whose visibility will be tracked. This should be set as a ref to a
* relevant dom element by the component using this hook.
*/
nodeRef,
};
}
4 changes: 4 additions & 0 deletions client/src/app/components/ToolbarBulkSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export const ToolbarBulkSelector = <T,>({
<DropdownItem
onClick={() => {
handleSelectAll(false);
setIsOpen(false);
}}
data-action="none"
key="select-none"
Expand All @@ -91,6 +92,7 @@ export const ToolbarBulkSelector = <T,>({
currentPageItems.map((item: T) => item),
true
);
setIsOpen(false);
}}
data-action="page"
key="select-page"
Expand All @@ -101,6 +103,7 @@ export const ToolbarBulkSelector = <T,>({
<DropdownItem
onClick={() => {
handleSelectAll(true);
setIsOpen(false);
}}
data-action="all"
key="select-all"
Expand All @@ -116,6 +119,7 @@ export const ToolbarBulkSelector = <T,>({
<ToolbarItem>
<Dropdown
isOpen={isOpen}
onOpenChange={(flag) => setIsOpen(flag)}
toggle={(toggleRef) => (
<MenuToggle
ref={toggleRef}
Expand Down
Loading

0 comments on commit 66190cd

Please sign in to comment.