function JobProperties()

in frontend/src/old-pages/Clusters/Accounting.tsx [268:714]


function JobProperties({job}: any) {
  console.log("Processing job properties for job", job)
  return (
    <Container>
      <SpaceBetween direction="vertical" size="l">
        <ColumnLayout columns={3} variant="text-grid">
          <SpaceBetween direction="vertical" size="l">
            <ValueWithLabel label="Job Id">{job.job_id}</ValueWithLabel>
            <ValueWithLabel label="Cluster">{job.cluster}</ValueWithLabel>
            <ValueWithLabel label="Group">{job.group}</ValueWithLabel>
            <ValueWithLabel label="User">{job.user}</ValueWithLabel>
            <ValueWithLabel label="Time">
              {getIn(job, ['time', 'elapsed'])} s
            </ValueWithLabel>
          </SpaceBetween>
          <SpaceBetween direction="vertical" size="l">
            <ValueWithLabel label="State">
              {<JobStatusIndicator status={getIn(job, ['state', 'current'])} />}
            </ValueWithLabel>
            <ValueWithLabel label="Name">{job.name}</ValueWithLabel>
            <ValueWithLabel label="Nodes">{job.nodes}</ValueWithLabel>
            <ValueWithLabel label="Account">{job.account}</ValueWithLabel>
            <ValueWithLabel label="Nodes">
              {job.allocation_nodes}
            </ValueWithLabel>
          </SpaceBetween>
          <SpaceBetween direction="vertical" size="l">
            <ValueWithLabel label="Queue">{job.partition}</ValueWithLabel>
            <ValueWithLabel label="Return Code">
              {getIn(job, ['exit_code', 'return_code', 'number'])}
            </ValueWithLabel>
            <ValueWithLabel label="Exit Status">
              {
                <JobStatusIndicator
                  status={getIn(job, ['exit_code', 'status'])}
                />
              }
            </ValueWithLabel>
            {getIn(job, ['price_estimate']) && (
              <ValueWithLabel label="Cost Estimate">
                <CostEstimate job={job} />
              </ValueWithLabel>
            )}
          </SpaceBetween>
        </ColumnLayout>
        <ValueWithLabel label="Steps">{<JobSteps job={job} />}</ValueWithLabel>
      </SpaceBetween>
    </Container>
  )
}

function JobModal() {
  const clusterName = useState(['app', 'clusters', 'selected'])
  const open = useState([
    'clusters',
    'index',
    clusterName,
    'accounting',
    'dialog',
  ])
  const selectedJob = useState([
    'clusters',
    'index',
    clusterName,
    'accounting',
    'selectedJob',
  ])
  const job = useState([
    'clusters',
    'index',
    clusterName,
    'accounting',
    'job',
    selectedJob,
  ])

  const close = () => {
    setState(['clusters', 'index', clusterName, 'accounting', 'dialog'], false)
  }

  return (
    <Modal
      onDismiss={close}
      visible={open}
      closeAriaLabel="Close modal"
      size="large"
      footer={
        <Box float="right">
          <SpaceBetween direction="horizontal" size="xs">
            <Button onClick={close}>Close</Button>
          </SpaceBetween>
        </Box>
      }
      header={`Job Info: ${job ? job.name : ''}`}
    >
      {job && <JobProperties job={job} />}
      {!job && <div>Loading...</div>}
    </Modal>
  )
}

export default function ClusterAccounting() {
  const {t} = useTranslation()
  const clusterName = useState(['app', 'clusters', 'selected'])
  //const accounting = useState(['clusters', 'index', clusterName, 'accounting']);
  //const errors = useState(['clusters', 'index', clusterName, 'accounting', 'errors']) || [];

  const pending = useState(['app', 'clusters', 'accounting', 'pending'])
  //const startTime = useState(['app', 'clusters', 'accounting', 'startTime']) || '';
  //const endTime = useState(['app', 'clusters', 'accounting', 'endTime']) || '';
  const nodes = useState(['app', 'clusters', 'accounting', 'nodes']) || []
  const user = useState(['app', 'clusters', 'accounting', 'user']) || ''
  const jobName = useState(['app', 'clusters', 'accounting', 'jobName']) || []
  const jobs: AccountingJobSummary[] = useState([
    'clusters',
    'index',
    clusterName,
    'accounting',
    'jobs',
  ]) || []

  React.useEffect(() => {
    refreshAccounting({}, null, true)
  }, [])

  const setDateRange = (val: any) => {
    if (!val) {
      clearState(['app', 'clusters', 'accounting', 'startTime'])
      clearState(['app', 'clusters', 'accounting', 'endTime'])
    } else {
      if (val.type === 'relative') {
        if (val.unit === 'month') {
          setState(
            ['app', 'clusters', 'accounting', 'startTime'],
            `now-${val.amount * 4}weeks`,
          )
          setState(['app', 'clusters', 'accounting', 'endTime'], 'now')
        } else if (val.unit === 'year') {
          setState(
            ['app', 'clusters', 'accounting', 'startTime'],
            `now-${val.amount * 52}weeks`,
          )
          setState(['app', 'clusters', 'accounting', 'endTime'], 'now')
        } else {
          setState(
            ['app', 'clusters', 'accounting', 'startTime'],
            `now-${val.amount}${val.unit}s`,
          )
          setState(['app', 'clusters', 'accounting', 'endTime'], 'now')
        }
      } else {
        const start = new Date(val.startDate)
        const end = new Date(val.endDate)
        setState(
          ['app', 'clusters', 'accounting', 'startTime'],
          start.toISOString().substring(0, 19),
        )
        setState(
          ['app', 'clusters', 'accounting', 'endTime'],
          end.toISOString().substring(0, 19),
        )
      }
    }
    refreshAccounting({}, null, true)
  }

  const {
    items,
    actions,
    filteredItemsCount,
    collectionProps,
    filterProps,
    paginationProps,
  } = useCollection(
    jobs || [],
    extendCollectionsOptions({
      filtering: {
        empty: (
          <EmptyState
            title={t('cluster.accounting.filter.empty.title')}
            subtitle={t('cluster.accounting.filter.empty.subtitle')}
          />
        ),
        noMatch: (
          <EmptyState
            title="No matches"
            subtitle="No jobs match the filters."
            action={
              <Button onClick={() => actions.setFiltering('')}>
                Clear filter
              </Button>
            }
          />
        ),
      },
      sorting: {
        defaultState: {
          sortingColumn: {
            sortingField: 'job_id',
          },
        },
      },
      selection: {},
    }),
  )

  const selectJob = (job_id: any) => {
    setState(['clusters', 'index', clusterName, 'accounting', 'dialog'], true)
    clearState(['clusters', 'index', clusterName, 'accounting', 'selectedJob'])
    clearState(['clusters', 'index', clusterName, 'accounting', 'job', job_id])
    refreshAccounting(
      {jobs: job_id},
      (ret: any) => {
        setState(
          ['clusters', 'index', clusterName, 'accounting', 'selectedJob'],
          job_id,
        )
        setState(
          ['clusters', 'index', clusterName, 'accounting', 'job', job_id],
          ret.jobs[0],
        )
      },
      false,
    )
  }

  const [dateValue, setDateValue] = React.useState(undefined)

  return (
    <>
      <JobModal />
      <SpaceBetween direction="vertical" size="s">
        <Container
          header={
            <Header
              variant="h2"
              actions={
                <Button
                  loading={pending}
                  onClick={() => refreshAccounting({}, null, true)}
                >
                  Refresh
                </Button>
              }
            >
              Filters
            </Header>
          }
        >
          <SpaceBetween direction="horizontal" size="s">
            <FormField label="Time range filter">
              <div
                onKeyPress={e =>
                  e.key === 'Enter' && refreshAccounting({}, null, true)
                }
              >
                <DateRangePicker
                  onChange={({detail}) => {
                    setDateRange(detail.value)
                    /* @ts-expect-error TS(2345) FIXME: Argument of type 'Value | null' is not assignable ... Remove this comment to see the full error message */
                    setDateValue(detail.value)
                  }}
                  /* @ts-expect-error FIXME: Argument of type 'Value | null' is not assignable ... Remove this comment to see the full error message */
                  value={dateValue}
                  relativeOptions={[
                    {
                      key: 'previous-5-minutes',
                      amount: 5,
                      unit: 'minute',
                      type: 'relative',
                    },
                    {
                      key: 'previous-30-minutes',
                      amount: 30,
                      unit: 'minute',
                      type: 'relative',
                    },
                    {
                      key: 'previous-1-hour',
                      amount: 1,
                      unit: 'hour',
                      type: 'relative',
                    },
                    {
                      key: 'previous-6-hours',
                      amount: 6,
                      unit: 'hour',
                      type: 'relative',
                    },
                  ]}
                  i18nStrings={{
                    todayAriaLabel: 'Today',
                    nextMonthAriaLabel: 'Next month',
                    previousMonthAriaLabel: 'Previous month',
                    customRelativeRangeDurationLabel: 'Duration',
                    customRelativeRangeDurationPlaceholder: 'Enter duration',
                    customRelativeRangeOptionLabel: 'Custom range',
                    customRelativeRangeOptionDescription:
                      'Set a custom range in the past',
                    customRelativeRangeUnitLabel: 'Unit of time',
                    formatRelativeRange: e => {
                      const t = 1 === e.amount ? e.unit : `${e.unit}s`
                      return `Last ${e.amount} ${t}`
                    },
                    formatUnit: (e, t) => (1 === t ? e : `${e}s`),
                    dateTimeConstraintText:
                      'Range must be between 6 - 30 days. Use 24 hour format.',
                    relativeModeTitle: 'Relative range',
                    absoluteModeTitle: 'Absolute range',
                    relativeRangeSelectionHeading: 'Choose a range',
                    startDateLabel: 'Start date',
                    endDateLabel: 'End date',
                    startTimeLabel: 'Start time',
                    endTimeLabel: 'End time',
                    clearButtonLabel: 'Clear',
                    cancelButtonLabel: 'Cancel',
                    applyButtonLabel: 'Apply',
                  }}
                  placeholder="Filter by a date and time range"
                />
              </div>
            </FormField>
            <FormField label="Queue">
              <QueueSelect />
            </FormField>
            <FormField label="Job State">
              <JobStateSelect />
            </FormField>
            <FormField label="User">
              <div
                onKeyPress={e =>
                  e.key === 'Enter' && refreshAccounting({}, null, true)
                }
              >
                <Input
                  value={user}
                  placeholder="ec2-user"
                  onChange={({detail}) => {
                    setState(
                      ['app', 'clusters', 'accounting', 'user'],
                      detail.value,
                    )
                  }}
                />
              </div>
            </FormField>
            <FormField label="Nodes">
              <div
                onKeyPress={e =>
                  e.key === 'Enter' && refreshAccounting({}, null, true)
                }
              >
                <Input
                  value={nodes}
                  placeholder="queue0-c5n-large-1"
                  onChange={({detail}) => {
                    setState(
                      ['app', 'clusters', 'accounting', 'nodes'],
                      detail.value,
                    )
                  }}
                />
              </div>
            </FormField>
            <FormField label="Job Name">
              <div
                onKeyPress={e =>
                  e.key === 'Enter' && refreshAccounting({}, null, true)
                }
              >
                <Input
                  value={jobName}
                  placeholder="job0"
                  onChange={({detail}) => {
                    setState(
                      ['app', 'clusters', 'accounting', 'jobName'],
                      detail.value,
                    )
                  }}
                />
              </div>
            </FormField>
          </SpaceBetween>
        </Container>

        {jobs ? (
          <SpaceBetween direction="vertical" size="s">
            <Table
              {...collectionProps}
              trackBy={i => `${i.job_id}-${i.name}`}
              columnDefinitions={[
                {
                  id: 'id',
                  header: t('cluster.accounting.id'),
                  cell: job => (
                    <Link onFollow={() => selectJob(job.job_id)}>
                      {job.job_id}
                    </Link>
                  ),
                  sortingField: 'job_id',
                },
                {
                  id: 'name',
                  header: t('cluster.accounting.name'),
                  cell: job => job.name,
                  sortingField: 'name',
                },
                {
                  id: 'queue',
                  header: t('cluster.accounting.queue'),
                  cell: job => job.partition,
                  sortingField: 'partition',
                },
                {
                  id: 'user',
                  header: t('cluster.accounting.user'),
                  cell: job => job.user,
                  sortingField: 'user',
                },
                {
                  id: 'state',
                  header: t('cluster.accounting.state'),
                  cell: job => (
                    <JobStatusIndicator
                      status={getIn(job, ['state', 'current'])}
                    />
                  ),
                  sortingField: 'job_state',
                },
              ]}
              items={items}
              loadingText={t('cluster.accounting.loadingJobs')}
              pagination={<Pagination {...paginationProps} />}
              filter={
                <TextFilter
                  {...filterProps}
                  countText={`Results: ${filteredItemsCount}`}
                  filteringAriaLabel={t('cluster.accounting.filterJobs')}
                />
              }
            />
          </SpaceBetween>
        ) : (
          <div style={{textAlign: 'center', paddingTop: '40px'}}>
            <Loading />
          </div>
        )}