diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/AllApplicationsTable.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/AllApplicationsTable.jsx
new file mode 100644
index 000000000..671734358
--- /dev/null
+++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/AllApplicationsTable.jsx
@@ -0,0 +1,144 @@
+/*
+Copyright 2019 Iguazio Systems Ltd.
+
+Licensed under the Apache License, Version 2.0 (the "License") with
+an addition restriction as set forth herein. You may not use this
+file except in compliance with the License. You may obtain a copy of
+the License at http://www.apache.org/licenses/LICENSE-2.0.
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+implied. See the License for the specific language governing
+permissions and limitations under the License.
+
+In addition, you may not use the software for any purposes that are
+illegal under applicable law, and the grant of the foregoing license
+under the Apache 2.0 license is conditioned upon your compliance with
+such restriction.
+*/
+import React, { useMemo } from 'react'
+import { useNavigate, useParams } from 'react-router-dom'
+import PropTypes from 'prop-types'
+
+import ApplicationTableRow from '../../../elements/ApplicationTableRow/ApplicationTableRow'
+import NoData from '../../../common/NoData/NoData'
+import Table from '../../Table/Table'
+import { Loader } from 'igz-controls/components'
+
+import { MODEL_ENDPOINTS_TAB, MONITORING_APP_PAGE } from '../../../constants'
+import { createApplicationContent } from '../../../utils/createApplicationContent'
+import { saveAndTransformSearchParams } from 'igz-controls/utils/filter.util'
+import { MONITORING_APPLICATIONS_NO_DATA_MESSAGE } from '../MonitoringApplicationsPage.util'
+import { getScssVariableValue } from 'igz-controls/utils/common.util'
+import { isRowRendered, useVirtualization } from '../../../hooks/useVirtualization.hook'
+
+import PresentMetricsIcon from 'igz-controls/images/present-metrics-icon.svg?react'
+
+import '../monitoringApplicationsPage.scss'
+
+const AllApplicationsTable = ({ applications, loading, error = null }) => {
+ const params = useParams()
+ const navigate = useNavigate()
+
+ const applicationsRowHeight = useMemo(() => getScssVariableValue('--applicationRowHeight'), [])
+ const applicationRowHeightExtended = useMemo(
+ () => getScssVariableValue('--applicationRowHeightExtended'),
+ []
+ )
+ const applicationsHeaderRowHeight = useMemo(
+ () => getScssVariableValue('--applicationHeaderRowHeight'),
+ []
+ )
+
+ const applicationsTableContent = useMemo(() => {
+ return applications.map(contentItem =>
+ createApplicationContent(contentItem, params.projectName)
+ )
+ }, [applications, params.projectName])
+
+ const applicationsTableHeaders = useMemo(
+ () => applicationsTableContent[0]?.content ?? [],
+ [applicationsTableContent]
+ )
+
+ const applicationsTableActionsMenu = useMemo(
+ () => [
+ [],
+ [
+ {
+ id: 'open-metrics',
+ label: 'Open metrics',
+ icon: ,
+ onClick: data =>
+ navigate(
+ `/projects/${params.projectName}/${MONITORING_APP_PAGE}/${data.name}/${MODEL_ENDPOINTS_TAB}${saveAndTransformSearchParams(
+ window.location.search,
+ true
+ )}`
+ )
+ }
+ ]
+ ],
+ [navigate, params.projectName]
+ )
+
+ const virtualizationConfig = useVirtualization({
+ rowsData: {
+ content: applicationsTableContent
+ },
+ heightData: {
+ headerRowHeight: applicationsHeaderRowHeight,
+ rowHeight: applicationsRowHeight,
+ rowHeightExtended: applicationRowHeightExtended
+ }
+ })
+
+ return (
+
+
+ All applications
+
+ {applications.length === 0 && !loading ? (
+
+ ) : loading ? (
+
+ ) : (
+
+ {applicationsTableContent.map(
+ (tableItem, index) =>
+ isRowRendered(virtualizationConfig, index) && (
+
+ )
+ )}
+
+ )}
+
+ )
+}
+
+AllApplicationsTable.propTypes = {
+ applications: PropTypes.array.isRequired,
+ loading: PropTypes.bool.isRequired,
+ error: PropTypes.object
+}
+
+export default AllApplicationsTable
diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.jsx
index e93ce64f8..fba71215c 100644
--- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.jsx
+++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.jsx
@@ -40,7 +40,7 @@ import './monitoringApplication.scss'
const MonitoringApplication = () => {
const dispatch = useDispatch()
- const { artifacts } = useSelector(store => store.artifactsStore)
+ const { artifacts, loading: loadingArtifacts } = useSelector(store => store.artifactsStore)
const { monitoringApplication, loading } = useSelector(store => store.monitoringApplicationsStore)
const params = useParams()
@@ -71,11 +71,17 @@ const MonitoringApplication = () => {
Artifacts
- {artifacts.length === 0 && !loading ? (
+ {artifacts.length === 0 && !loadingArtifacts ? (
) : (
<>
-
+
{
const dispatch = useDispatch()
const params = useParams()
- const navigate = useNavigate()
const {
monitoringApplications: { applications = [], operatingFunctions = [] },
loading,
error
} = useSelector(store => store.monitoringApplicationsStore)
- const applicationsTableActionsMenu = useMemo(
- () => [
- [],
- [
- {
- id: 'open-metrics',
- label: 'Open metrics',
- icon: ,
- onClick: data =>
- navigate(
- `/projects/${params.projectName}/${MONITORING_APP_PAGE}/${data.name}/${MODEL_ENDPOINTS_TAB}${saveAndTransformSearchParams(
- window.location.search,
- true
- )}`
- )
- }
- ]
- ],
- [navigate, params.projectName]
- )
const operatingFunctionsTable = useMemo(
() => generateOperatingFunctionsTable(operatingFunctions, params.projectName),
[operatingFunctions, params.projectName]
)
- const applicationsTableContent = useMemo(() => {
- return applications.map(contentItem =>
- createApplicationContent(contentItem, params.projectName)
- )
- }, [applications, params.projectName])
-
- const applicationsTableHeaders = useMemo(
- () => applicationsTableContent[0]?.content ?? [],
- [applicationsTableContent]
- )
useEffect(() => {
return () => {
@@ -110,44 +73,17 @@ const MonitoringApplications = () => {
}
/>
) : (
-
+
)}
-
-
- All applications
-
- {applications.length === 0 && !loading ? (
-
- ) : loading ? (
-
- ) : (
-
- {applicationsTableContent.map((tableItem, index) => (
-
- ))}
-
- )}
-
+
)
diff --git a/src/components/MonitoringApplicationsPage/monitoringApplicationsPage.scss b/src/components/MonitoringApplicationsPage/monitoringApplicationsPage.scss
index db6aeb07b..cddb71497 100644
--- a/src/components/MonitoringApplicationsPage/monitoringApplicationsPage.scss
+++ b/src/components/MonitoringApplicationsPage/monitoringApplicationsPage.scss
@@ -7,6 +7,32 @@ $applicationRowHeight: variables.$rowHeight;
$applicationHeaderRowHeight: variables.$headerRowHeight;
$applicationRowHeightExtended: variables.$rowHeightExtended;
+:root {
+ --applicationRowHeight: #{$applicationRowHeight};
+ --applicationHeaderRowHeight: #{$applicationHeaderRowHeight};
+ --applicationRowHeightExtended: #{$applicationRowHeightExtended};
+}
+
+.all-applications-table {
+ max-height: 450px;
+
+ .table__flex {
+ max-height: calc(100% - 25px);
+
+ .table__content {
+ height: 100%;
+
+ & > div {
+ height: 100%;
+
+ table.applications-table {
+ height: 100%;
+ }
+ }
+ }
+ }
+}
+
.monitoring-app-content {
.monitoring-apps-title {
color: colors.$primary;
@@ -59,9 +85,9 @@ $applicationRowHeightExtended: variables.$rowHeightExtended;
.applications-table {
@include mixins.rowsHeight(
- $applicationHeaderRowHeight,
- $applicationRowHeight,
- $applicationRowHeightExtended
+ $applicationHeaderRowHeight,
+ $applicationRowHeight,
+ $applicationRowHeightExtended
);
}
@@ -92,8 +118,8 @@ $applicationRowHeightExtended: variables.$rowHeightExtended;
left: 50%;
font-weight: 500;
font-size: 13px;
- transform: translate(-50%, 0);
- }
+ transform: translate(-50%, 0);
+ }
&.loading {
visibility: hidden;
diff --git a/src/elements/SectionTable/SectionTable.jsx b/src/elements/SectionTable/SectionTable.jsx
index 0836042da..4b9f82300 100644
--- a/src/elements/SectionTable/SectionTable.jsx
+++ b/src/elements/SectionTable/SectionTable.jsx
@@ -17,180 +17,237 @@ illegal under applicable law, and the grant of the foregoing license
under the Apache 2.0 license is conditioned upon your compliance with
such restriction.
*/
-import React from 'react'
+import React, { useMemo, useState } from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import { Link } from 'react-router-dom'
+import { v4 as uuidv4 } from 'uuid'
import { TableTypeCell } from 'igz-controls/elements'
import { TextTooltipTemplate, Tooltip, Tip, Loader, ReadOnlyChips } from 'igz-controls/components'
+import { isRowRendered, useVirtualization } from '../../hooks/useVirtualization.hook'
import './SectionTable.scss'
-const SectionTable = ({ loading = false, params, table }) => {
+const SPACE_FOR_BORDER = 2
+const DEFAULT_ROW_HEIGHT = 41
+const DEFAULT_MAX_TABLE_HEIGHT = 369
+
+const SectionTable = ({
+ headerHeight = DEFAULT_ROW_HEIGHT,
+ loading = false,
+ params,
+ rowHeight = DEFAULT_ROW_HEIGHT,
+ table,
+ maxTableHeight = DEFAULT_MAX_TABLE_HEIGHT
+}) => {
+ const [tableId] = useState(`section-table-${uuidv4()}`)
+ const [tableBodyId] = useState(`section-table-body-${uuidv4()}`)
+
+ const rowsSizes = useMemo(
+ () => (table?.body?.length ? new Array(table.body.length).fill(parseInt(rowHeight)) : []),
+ [rowHeight, table.body.length]
+ )
+
+ const heightData = useMemo(
+ () => ({
+ headerRowHeight: headerHeight,
+ rowHeight: rowHeight,
+ rowHeightExtended: rowHeight
+ }),
+ [headerHeight, rowHeight]
+ )
+
+ const tableContainerHeight = useMemo(() => {
+ return Math.min(headerHeight + rowHeight * table.body.length + SPACE_FOR_BORDER, maxTableHeight)
+ }, [headerHeight, maxTableHeight, rowHeight, table])
+
+ const virtualizationConfig = useVirtualization({
+ renderTriggerItem: table,
+ heightData,
+ rowsSizes,
+ tableBodyId: tableBodyId,
+ tableId: tableId
+ })
+
return loading ? (
) : (
- <>
-
-
-
- <>
- {table.header.map(
- header =>
- !header.hidden && (
- |
- }>
- {header.value}
-
- {header.tip && }
- |
- )
- )}
- >
-
-
-
- {table.body.map((body, index) => {
- const extractedItemName = body['name'].value.startsWith(params.projectName)
- ? body['name'].value.slice(params.projectName.length + 1)
- : body['name'].value
-
- return (
-
- <>
- {Object.keys(body).map((key, index) => {
- const tableValueClassName = classnames(
- 'section-table__table-cell',
- body[key].className,
- key === 'name' && 'name-wrapper',
- key === 'status' && 'status-cell',
- key === 'status' &&
- !Array.isArray(body[key].value) &&
- `status_${body?.[key]?.value?.toLowerCase?.()} capitalize`
+
+
+
+
+
+ <>
+ {table.header.map(
+ header =>
+ !header.hidden && (
+ |
+ }>
+ {header.value}
+
+ {header.tip && }
+ |
)
+ )}
+ >
+
+
+
+ {table.body.map((body, index) => {
+ const extractedItemName = body['name'].value.startsWith(params.projectName)
+ ? body['name'].value.slice(params.projectName.length + 1)
+ : body['name'].value
- return (
- !body[key].hidden &&
- (key === 'type' ? (
-
- ) : (
-
- {key === 'name' ? (
- <>
- {body[key].href ? (
-
- }
- textShow={true}
- >
- {extractedItemName}
-
-
- ) : body[key].link ? (
-
+ return (
+ isRowRendered(virtualizationConfig, index) && (
+ |
+ <>
+ {Object.keys(body).map((key, index) => {
+ const tableValueClassName = classnames(
+ 'section-table__table-cell',
+ body[key].className,
+ key === 'name' && 'name-wrapper',
+ key === 'status' && 'status-cell',
+ key === 'status' &&
+ !Array.isArray(body[key].value) &&
+ `status_${body?.[key]?.value?.toLowerCase?.()} capitalize`
+ )
+
+ return (
+ !body[key].hidden &&
+ (key === 'type' ? (
+
+ ) : (
+ |
+ {key === 'name' ? (
+ <>
+ {body[key].href ? (
+
+ }
+ textShow={true}
+ >
+ {extractedItemName}
+
+
+ ) : body[key].link ? (
+
+ }
+ >
+ {body[key].value}
+
+
+ ) : (
+ }
+ >
+ {body[key].value}
+
+ )}
+
+ {body[key].tag ? (
+ }
+ >
+ {body[key].tag}
+
+ ) : null}
+ >
+ ) : key === 'labels' ? (
+
+ ) : key === 'status' ? (
+ <>
+ {Array.isArray(body.status.value) ? (
+ body.status.value.map((status, index) => {
+ return (
+ }
+ >
+
+
+ )
+ })
+ ) : (
+
+ }
+ >
+ {body[key].value}
+
+ )}
+ >
+ ) : (
+ <>
}
+ template={
+
+ }
>
{body[key].value}
-
- ) : (
- }
- >
- {body[key].value}
-
- )}
-
- {body[key].tag ? (
- }
- >
- {body[key].tag}
-
- ) : null}
- >
- ) : key === 'labels' ? (
-
- ) : key === 'status' ? (
- <>
- {Array.isArray(body.status.value) ? (
- body.status.value.map((status, index) => {
- return (
+ {body[key].status && (
}
+ key={body[key].status + index}
+ template={}
>
-
+
- )
- })
- ) : (
-
- }
- >
- {body[key].value}
-
- )}
- >
- ) : (
- <>
-
- }
- >
- {body[key].value}
-
- {body[key].status && (
- }
- >
-
-
+ )}
+ >
)}
- >
- )}
- |
- ))
- )
- })}
- >
-
- )
- })}
-
-
- >
+
+ ))
+ )
+ })}
+ >
+
+ )
+ )
+ })}
+
+
+
+
)
}
SectionTable.propTypes = {
+ headerHeight: PropTypes.number,
loading: PropTypes.bool,
params: PropTypes.object.isRequired,
- table: PropTypes.object.isRequired
+ rowHeight: PropTypes.number,
+ table: PropTypes.object.isRequired,
+ maxTableHeight: PropTypes.number
}
export default React.memo(SectionTable)
diff --git a/src/elements/SectionTable/SectionTable.scss b/src/elements/SectionTable/SectionTable.scss
index 2da8cf9e5..b87bae1ba 100644
--- a/src/elements/SectionTable/SectionTable.scss
+++ b/src/elements/SectionTable/SectionTable.scss
@@ -18,72 +18,100 @@
}
}
-.section-table {
- min-width: fit-content;
- height: 100%;
- border: borders.$dividerBorder;
- border-radius: 8px;
-
- &__table {
- &-body {
- display: flex;
- flex: 1;
- flex-direction: column;
- }
+.section-table__content {
+ position: relative;
+ width: 100%;
+}
- &-row {
- display: flex;
- flex: 1;
- flex-direction: row;
- border-bottom: borders.$tertiaryBorder;
- }
+.section-table__wrapper {
+ position: absolute;
+ top: 0;
+ right: 0;
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ height: 100%;
+ overflow-y: auto;
- &-link {
+ .section-table {
+ position: relative;
+ display: flex;
+ flex: 1;
+ flex-flow: column nowrap;
+ width: 100%;
+ height: 100%;
+ overflow-y: auto;
+ border: borders.$dividerBorder;
+ border-radius: 8px;
+ will-change: scroll-position;
+
+ thead {
+ position: sticky;
+ top: 0;
+ z-index: 3;
min-width: 100%;
- max-width: 50px;
+ background: colors.$white;
}
- &-cell {
- display: flex;
- align-items: center;
- padding: 8px 5px 8px 0;
- color: colors.$primary;
- line-height: 24px;
-
- &.status {
- color: colors.$supernova;
- text-transform: none;
-
- &_completed,
- &_ready,
- &_running {
- color: colors.$java;
- }
+ &__table {
+ &-body {
+ display: flex;
+ flex-direction: column;
+ }
+
+ &-row {
+ display: flex;
+ flex-direction: row;
+ min-width: 100%;
+ border-bottom: borders.$tertiaryBorder;
+ }
- &-nuclio {
- &_ready {
- color: colors.$brightTurquoise;
+ &-link {
+ min-width: 100%;
+ max-width: 50px;
+ }
- &.disabled {
+ &-cell {
+ display: flex;
+ align-items: center;
+ padding: 8px 5px 8px 0;
+ color: colors.$primary;
+ line-height: 24px;
+
+ &.status {
+ color: colors.$supernova;
+ text-transform: none;
+
+ &_completed,
+ &_ready,
+ &_running {
+ color: colors.$java;
+ }
+
+ &-nuclio {
+ &_ready {
+ color: colors.$brightTurquoise;
+
+ &.disabled {
+ color: colors.$topaz;
+ }
+ }
+
+ &_scaledToZero {
color: colors.$topaz;
}
}
- &_scaledToZero {
- color: colors.$topaz;
+ &_failed,
+ &_error,
+ &_unhealthy {
+ color: colors.$amaranth;
}
- }
-
- &_failed,
- &_error,
- &_unhealthy {
- color: colors.$amaranth;
- }
- &_imported {
- color: colors.$topaz;
+ &_imported {
+ color: colors.$topaz;
+ }
}
- }
.tooltip-wrapper {
min-width: 8px;
@@ -93,60 +121,60 @@
margin-left: 5px;
}
- &.name-wrapper {
- display: flex;
- flex-wrap: wrap;
+ &.name-wrapper {
+ display: flex;
+ flex-wrap: wrap;
+
+ &.table-cell_with-tag {
+ gap: 4px;
+ height: 57px;
+ }
- &.table-cell_with-tag {
- gap: 4px;
- height: 57px;
+ .item-name {
+ width: 100%;
+ }
+
+ .item-tag {
+ display: inline;
+ max-width: 150px;
+ color: colors.$topaz;
+ line-height: 16px;
+ }
}
- .item-name {
- width: 100%;
+ .table-body__cell {
+ &_type {
+ display: flex;
+ align-items: center;
+ padding: 0;
+ }
}
- .item-tag {
- display: inline;
- max-width: 150px;
- color: colors.$topaz;
- line-height: 16px;
+ &:first-child {
+ padding-left: 15px;
}
}
- .table-body__cell {
- &_type {
- display: flex;
- align-items: center;
- padding: 0;
+ &-header {
+ display: flex;
+ font-size: 14px;
+ line-height: 24px;
+ border-bottom: borders.$tertiaryBorder;
+
+ .table-header-item {
+ color: colors.$topaz;
+ font-weight: bold;
}
}
- &:first-child {
- padding-left: 15px;
+ .table-body__cell {
+ align-items: center;
+ border: none;
}
- }
-
- &-header {
- display: flex;
- flex: 1;
- font-size: 14px;
- line-height: 24px;
- border-bottom: borders.$tertiaryBorder;
- .table-header-item {
- color: colors.$topaz;
- font-weight: bold;
+ .tooltip__text {
+ display: initial;
}
}
-
- .table-body__cell {
- align-items: center;
- border: none;
- }
-
- .tooltip__text {
- display: initial;
- }
}
}