Skip to content

Commit

Permalink
Merge pull request #797 from OmarBrbutovic/hardware_type_ssp
Browse files Browse the repository at this point in the history
Enable server-side pagination hardware_types
  • Loading branch information
davidebriani authored Jan 14, 2025
2 parents 62105c6 + 587b22d commit 04560ac
Show file tree
Hide file tree
Showing 8 changed files with 189 additions and 74 deletions.
72 changes: 66 additions & 6 deletions frontend/src/api/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -1186,6 +1186,27 @@ enum HardwareTypePartNumberSortField {
PART_NUMBER
}

":hardware_type_part_number connection"
type HardwareTypePartNumberConnection {
"Total count on all pages"
count: Int

"Page information"
pageInfo: PageInfo!

":hardware_type_part_number edges"
edges: [HardwareTypePartNumberEdge!]
}

":hardware_type_part_number edge"
type HardwareTypePartNumberEdge {
"Cursor"
cursor: String!

":hardware_type_part_number node"
node: HardwareTypePartNumber!
}

input HardwareTypePartNumberFilterPartNumber {
isNil: Boolean
eq: String
Expand Down Expand Up @@ -1301,6 +1322,27 @@ enum HardwareTypeSortField {
NAME
}

":hardware_type connection"
type HardwareTypeConnection {
"Total count on all pages"
count: Int

"Page information"
pageInfo: PageInfo!

":hardware_type edges"
edges: [HardwareTypeEdge!]
}

":hardware_type edge"
type HardwareTypeEdge {
"Cursor"
cursor: String!

":hardware_type node"
node: HardwareType!
}

input HardwareTypeFilterName {
isNil: Boolean
eq: String
Expand Down Expand Up @@ -1395,12 +1437,18 @@ type HardwareType implements Node {
"A filter to limit the results"
filter: HardwareTypePartNumberFilterInput

"The number of records to return."
limit: Int
"The number of records to return from the beginning. Maximum 250"
first: Int

"The number of records to skip."
offset: Int
): [HardwareTypePartNumber!]!
"Show records before the specified keyset."
before: String

"Show records after the specified keyset."
after: String

"The number of records to return to the end. Maximum 250"
last: Int
): HardwareTypePartNumberConnection!
}

"The result of the :set_device_led_behavior mutation"
Expand Down Expand Up @@ -2879,7 +2927,19 @@ type RootQueryType {

"A filter to limit the results"
filter: HardwareTypeFilterInput
): [HardwareType!]!

"The number of records to return from the beginning. Maximum 250"
first: Int

"Show records before the specified keyset."
before: String

"Show records after the specified keyset."
after: String

"The number of records to return to the end. Maximum 250"
last: Int
): HardwareTypeConnection

"Returns a single system model."
systemModel("The id of the record" id: ID!): SystemModel
Expand Down
59 changes: 39 additions & 20 deletions frontend/src/components/HardwareTypesTable.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
This file is part of Edgehog.
Copyright 2024 SECO Mind Srl
Copyright 2024-2025 SECO Mind Srl
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -29,15 +29,14 @@ import type { HardwareTypesTable_getHardwareTypes_Query } from "api/__generated_
import HardwareTypesTable from "./HardwareTypesTable";

const GET_HARDWARE_TYPES_QUERY = graphql`
query HardwareTypesTable_getHardwareTypes_Query @relay_test_operation {
hardwareTypes {
...HardwareTypesTable_HardwareTypesFragment
}
query HardwareTypesTable_getHardwareTypes_Query($first: Int, $after: String)
@relay_test_operation {
...HardwareTypesTable_HardwareTypesFragment
}
`;

const ComponentWithQuery = () => {
const { hardwareTypes } =
const hardwareTypes =
useLazyLoadQuery<HardwareTypesTable_getHardwareTypes_Query>(
GET_HARDWARE_TYPES_QUERY,
{},
Expand All @@ -50,16 +49,30 @@ type HardwareType = {
handle: string;
name: string;
partNumbers: {
id: string;
partNumber: string;
}[];
edges: {
node: {
id: string;
partNumber: string;
};
}[];
};
};

const renderComponent = (hardwareTypes: HardwareType[] = []) => {
const relayEnvironment = createMockEnvironment();
relayEnvironment.mock.queueOperationResolver((_operation) => ({
data: { hardwareTypes },

relayEnvironment.mock.queueOperationResolver(() => ({
data: {
hardwareTypes: {
edges: hardwareTypes.map((model) => ({
node: model,
})),
},
},
}));

relayEnvironment.mock.queuePendingOperation(GET_HARDWARE_TYPES_QUERY, {});

renderWithProviders(<ComponentWithQuery />, { relayEnvironment });
};

Expand All @@ -81,7 +94,9 @@ it("renders Hardware Type data", () => {
id: "HW-ID",
handle: "hw-handle",
name: "HW name",
partNumbers: [{ id: "HW-PN1", partNumber: "HW-PN1" }],
partNumbers: {
edges: [{ node: { id: "HW-PN1", partNumber: "HW-PN1" } }],
},
},
]);

Expand All @@ -100,10 +115,12 @@ it("renders multiple Part Numbers separated by comma", () => {
id: "HW-ID",
handle: "hw-handle",
name: "HW name",
partNumbers: [
{ id: "HW-PN1", partNumber: "HW-PN1" },
{ id: "HW-PN2", partNumber: "HW-PN2" },
],
partNumbers: {
edges: [
{ node: { id: "HW-PN1", partNumber: "HW-PN1" } },
{ node: { id: "HW-PN2", partNumber: "HW-PN2" } },
],
},
},
]);

Expand All @@ -116,10 +133,12 @@ it("renders Hardware Type data in correct columns", () => {
id: "HW-ID",
handle: "hw-handle",
name: "HW name",
partNumbers: [
{ id: "HW-PN1", partNumber: "HW-PN1" },
{ id: "HW-PN2", partNumber: "HW-PN2" },
],
partNumbers: {
edges: [
{ node: { id: "HW-PN1", partNumber: "HW-PN1" } },
{ node: { id: "HW-PN2", partNumber: "HW-PN2" } },
],
},
},
]);

Expand Down
55 changes: 37 additions & 18 deletions frontend/src/components/HardwareTypesTable.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
This file is part of Edgehog.
Copyright 2021-2024 SECO Mind Srl
Copyright 2021-2025 SECO Mind Srl
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand All @@ -20,30 +20,47 @@

import React from "react";
import { FormattedMessage } from "react-intl";
import { graphql, useFragment } from "react-relay/hooks";
import { graphql, usePaginationFragment } from "react-relay/hooks";

import Table, { createColumnHelper } from "components/Table";
import { Link, Route } from "Navigation";
import type { HardwareTypesTable_PaginationQuery } from "api/__generated__/HardwareTypesTable_PaginationQuery.graphql";
import type {
HardwareTypesTable_HardwareTypesFragment$key,
HardwareTypesTable_HardwareTypesFragment$data,
} from "api/__generated__/HardwareTypesTable_HardwareTypesFragment.graphql";

import Table, { createColumnHelper } from "components/Table";
import { Link, Route } from "Navigation";

// We use graphql fields below in columns configuration
/* eslint-disable relay/unused-fields */
const HARDWARE_TYPES_TABLE_FRAGMENT = graphql`
fragment HardwareTypesTable_HardwareTypesFragment on HardwareType
@relay(plural: true) {
id
handle
name
partNumbers {
partNumber
fragment HardwareTypesTable_HardwareTypesFragment on RootQueryType
@refetchable(queryName: "HardwareTypesTable_PaginationQuery") {
hardwareTypes(first: $first, after: $after)
@connection(key: "HardwareTypesTable_hardwareTypes") {
edges {
node {
id
handle
name
partNumbers {
edges {
node {
partNumber
}
}
}
}
}
}
}
`;

type TableRecord = HardwareTypesTable_HardwareTypesFragment$data[number];
type TableRecord = NonNullable<
NonNullable<
HardwareTypesTable_HardwareTypesFragment$data["hardwareTypes"]
>["edges"]
>[number]["node"];

const columnHelper = createColumnHelper<TableRecord>();
const columns = [
Expand Down Expand Up @@ -81,7 +98,7 @@ const columns = [
/>
),
cell: ({ getValue }) =>
getValue().map(({ partNumber }, index) => (
getValue().edges?.map(({ node: { partNumber } }, index) => (
<React.Fragment key={partNumber}>
{index > 0 && ", "}
<span className="text-nowrap">{partNumber}</span>
Expand All @@ -96,12 +113,14 @@ type Props = {
};

const HardwareTypesTable = ({ className, hardwareTypesRef }: Props) => {
const hardwareTypes = useFragment(
HARDWARE_TYPES_TABLE_FRAGMENT,
hardwareTypesRef,
);
const { data } = usePaginationFragment<
HardwareTypesTable_PaginationQuery,
HardwareTypesTable_HardwareTypesFragment$key
>(HARDWARE_TYPES_TABLE_FRAGMENT, hardwareTypesRef);

const tableData = data.hardwareTypes?.edges?.map((edge) => edge.node) ?? [];

return <Table className={className} columns={columns} data={hardwareTypes} />;
return <Table className={className} columns={columns} data={tableData} />;
};

export default HardwareTypesTable;
16 changes: 10 additions & 6 deletions frontend/src/forms/CreateSystemModel.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
This file is part of Edgehog.
Copyright 2021-2024 SECO Mind Srl
Copyright 2021-2025 SECO Mind Srl
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand All @@ -24,6 +24,8 @@ import { FormattedMessage, useIntl } from "react-intl";
import { graphql, useFragment } from "react-relay/hooks";
import { yupResolver } from "@hookform/resolvers/yup";

import type { CreateSystemModel_OptionsFragment$key } from "api/__generated__/CreateSystemModel_OptionsFragment.graphql";

import Button from "components/Button";
import CloseButton from "components/CloseButton";
import Col from "components/Col";
Expand All @@ -35,13 +37,15 @@ import Spinner from "components/Spinner";
import Stack from "components/Stack";
import { systemModelHandleSchema, messages, yup } from "forms";

import type { CreateSystemModel_OptionsFragment$key } from "api/__generated__/CreateSystemModel_OptionsFragment.graphql";

const CREATE_SYSTEM_MODEL_FRAGMENT = graphql`
fragment CreateSystemModel_OptionsFragment on RootQueryType {
hardwareTypes {
id
name
edges {
node {
id
name
}
}
}
tenantInfo {
defaultLocale
Expand Down Expand Up @@ -303,7 +307,7 @@ const CreateSystemModelForm = ({
defaultMessage: "Select a Hardware Type",
})}
</option>
{hardwareTypes.map((hardwareType) => (
{hardwareTypes?.edges?.map(({ node: hardwareType }) => (
<option key={hardwareType.id} value={hardwareType.id}>
{hardwareType.name}
</option>
Expand Down
Loading

0 comments on commit 04560ac

Please sign in to comment.