Skip to content

Commit 766e80a

Browse files
committed
wip[frontend]: add subscriptions for campaigns
- Added subscriptions to DeploymentCampaign page - Added subscriptions to UpdateCampaign page TODO: - Add subscriptions to Channels and Channel page - Add subscriptions to DeploymentCampaigns and UpdateCampaigns page - figure out how to update Target Tabs component on DeploymentCampaign and UpdateCampaign pages Signed-off-by: ArnelaL <arnela.lisic@secomind.com>
1 parent ea9fa5f commit 766e80a

3 files changed

Lines changed: 134 additions & 128 deletions

File tree

frontend/src/api/schema.graphql

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -900,6 +900,12 @@ type LocalizedAttribute {
900900
languageTag: String!
901901
}
902902

903+
type base_image_collection_result {
904+
created: BaseImageCollection
905+
updated: BaseImageCollection
906+
destroyed: ID
907+
}
908+
903909
"The result of the :delete_base_image_collection mutation"
904910
type DeleteBaseImageCollectionResult {
905911
"The record that was successfully deleted"
@@ -1092,6 +1098,12 @@ type BaseImageCollection implements Node {
10921098
): BaseImageConnection!
10931099
}
10941100

1101+
type base_image_result {
1102+
created: BaseImage
1103+
updated: BaseImage
1104+
destroyed: ID
1105+
}
1106+
10951107
"The result of the :delete_base_image mutation"
10961108
type DeleteBaseImageResult {
10971109
"The record that was successfully deleted"
@@ -5005,6 +5017,15 @@ type Tag {
50055017
name: String!
50065018
}
50075019

5020+
"The result of the :cancel_ota_operation mutation"
5021+
type CancelOtaOperationResult {
5022+
"The successful result of the mutation"
5023+
result: OtaOperation
5024+
5025+
"Any errors generated, if the mutation failed"
5026+
errors: [MutationError!]!
5027+
}
5028+
50085029
"The result of the :create_manual_ota_operation mutation"
50095030
type CreateManualOtaOperationResult {
50105031
"The successful result of the mutation"
@@ -5239,6 +5260,12 @@ type TenantInfo {
52395260
defaultLocale: String!
52405261
}
52415262

5263+
type channels_result {
5264+
created: Channel
5265+
updated: Channel
5266+
destroyed: ID
5267+
}
5268+
52425269
"The result of the :delete_channel mutation"
52435270
type DeleteChannelResult {
52445271
"The record that was successfully deleted"
@@ -5450,6 +5477,11 @@ type Channel implements Node {
54505477
): CampaignConnection!
54515478
}
54525479

5480+
type campaign_target_changed_result {
5481+
created: CampaignTarget
5482+
updated: CampaignTarget
5483+
}
5484+
54535485
enum CampaignTargetSortField {
54545486
ID
54555487
STATUS
@@ -5614,6 +5646,25 @@ type CampaignTarget {
56145646
otaOperation: OtaOperation
56155647
}
56165648

5649+
type campaign_result {
5650+
updated: Campaign
5651+
}
5652+
5653+
type update_campaigns_result {
5654+
created: Campaign
5655+
updated: Campaign
5656+
}
5657+
5658+
type deployment_campaigns_result {
5659+
created: Campaign
5660+
updated: Campaign
5661+
}
5662+
5663+
type campaigns_result {
5664+
created: Campaign
5665+
updated: Campaign
5666+
}
5667+
56175668
"The result of the :create_campaign mutation"
56185669
type CreateCampaignResult {
56195670
"The successful result of the mutation"
@@ -6261,6 +6312,9 @@ type RootMutationType {
62616312
input: CreateManualOtaOperationInput!
62626313
): CreateManualOtaOperationResult
62636314

6315+
"Cancels an OTA update operation"
6316+
cancelOtaOperation(id: ID!): CancelOtaOperationResult
6317+
62646318
"Creates a new device group."
62656319
createDeviceGroup(input: CreateDeviceGroupInput!): CreateDeviceGroupResult
62666320

@@ -6399,10 +6453,48 @@ type RootMutationType {
63996453
}
64006454

64016455
type RootSubscriptionType {
6456+
campaigns(
6457+
"A filter to limit the results"
6458+
filter: CampaignFilterInput
6459+
): campaigns_result
6460+
deploymentCampaigns(
6461+
"A filter to limit the results"
6462+
filter: CampaignFilterInput
6463+
6464+
types: [String!]
6465+
): deployment_campaigns_result
6466+
updateCampaigns(
6467+
"A filter to limit the results"
6468+
filter: CampaignFilterInput
6469+
6470+
types: [String!]
6471+
): update_campaigns_result
6472+
campaign(
6473+
"A filter to limit the results"
6474+
filter: CampaignFilterInput
6475+
6476+
id: ID!
6477+
): campaign_result
6478+
campaignTargetChanged(
6479+
"A filter to limit the results"
6480+
filter: CampaignTargetFilterInput
6481+
): campaign_target_changed_result
6482+
channels(
6483+
"A filter to limit the results"
6484+
filter: ChannelFilterInput
6485+
): channels_result
64026486
deviceChanged(
64036487
"A filter to limit the results"
64046488
filter: DeviceFilterInput
64056489
): device_changed_result
6490+
baseImage(
6491+
"A filter to limit the results"
6492+
filter: BaseImageFilterInput
6493+
): base_image_result
6494+
baseImageCollection(
6495+
"A filter to limit the results"
6496+
filter: BaseImageCollectionFilterInput
6497+
): base_image_collection_result
64066498
}
64076499

64086500
"""

frontend/src/pages/DeploymentCampaign.tsx

Lines changed: 21 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,19 @@
1818
* SPDX-License-Identifier: Apache-2.0
1919
*/
2020

21-
import { Suspense, useCallback, useEffect, useRef, useState } from "react";
21+
import { Suspense, useCallback, useEffect } from "react";
2222
import { useParams } from "react-router-dom";
2323
import { ErrorBoundary } from "react-error-boundary";
2424
import { FormattedMessage } from "react-intl";
2525
import {
26-
fetchQuery,
2726
graphql,
28-
useFragment,
2927
usePreloadedQuery,
30-
useRelayEnvironment,
3128
useQueryLoader,
29+
useSubscription,
3230
} from "react-relay/hooks";
3331
import type { PreloadedQuery } from "react-relay/hooks";
34-
import type { Subscription } from "relay-runtime";
3532

3633
import type { DeploymentCampaign_getCampaign_Query } from "@/api/__generated__/DeploymentCampaign_getCampaign_Query.graphql";
37-
import type { DeploymentCampaign_RefreshFragment$key } from "@/api/__generated__/DeploymentCampaign_RefreshFragment.graphql";
3834

3935
import Center from "@/components/Center";
4036
import Col from "@/components/Col";
@@ -57,7 +53,6 @@ const GET_CAMPAIGN_QUERY = graphql`
5753
name
5854
...DeploymentCampaignForm_CampaignFragment
5955
...CampaignStatsChart_CampaignStatsChartFragment
60-
...DeploymentCampaign_RefreshFragment
6156
...DeploymentTargetsTabs_SuccessfulFragment @arguments(first: $first)
6257
...DeploymentTargetsTabs_FailedFragment @arguments(first: $first)
6358
...DeploymentTargetsTabs_InProgressFragment @arguments(first: $first)
@@ -66,65 +61,21 @@ const GET_CAMPAIGN_QUERY = graphql`
6661
}
6762
`;
6863

69-
const CAMPAIGN_REFRESH_FRAGMENT = graphql`
70-
fragment DeploymentCampaign_RefreshFragment on Campaign {
71-
id
72-
status
73-
}
74-
`;
75-
76-
type DeploymentCampaignRefreshProps = {
77-
campaignRef: DeploymentCampaign_RefreshFragment$key;
78-
};
79-
80-
const DeploymentCampaignRefresh = ({
81-
campaignRef,
82-
}: DeploymentCampaignRefreshProps) => {
83-
const relayEnvironment = useRelayEnvironment();
84-
const { id, status } = useFragment(CAMPAIGN_REFRESH_FRAGMENT, campaignRef);
85-
const [isRefreshing, setIsRefreshing] = useState(false);
86-
87-
// TODO: use GraphQL subscription (when available) to get deployments about Deployment Campaign
88-
const subscriptionRef = useRef<Subscription | null>(null);
89-
useEffect(() => {
90-
return () => {
91-
if (subscriptionRef.current) {
92-
subscriptionRef.current.unsubscribe();
64+
const CAMPAIGN_UPDATE_SUBSCRIPTION = graphql`
65+
subscription DeploymentCampaign_campaignUpdated_Subscription($id: ID!) {
66+
campaign(id: $id) {
67+
updated {
68+
id
69+
status
70+
outcome
71+
idleTargetCount
72+
inProgressTargetCount
73+
failedTargetCount
74+
successfulTargetCount
9375
}
94-
};
95-
}, []);
96-
97-
useEffect(() => {
98-
if (status === "FINISHED" || isRefreshing) {
99-
return;
10076
}
101-
const refreshTimerId = setTimeout(() => {
102-
setIsRefreshing(true);
103-
subscriptionRef.current = fetchQuery(
104-
relayEnvironment,
105-
GET_CAMPAIGN_QUERY,
106-
{
107-
deploymentCampaignId: id,
108-
first: RECORDS_TO_LOAD_FIRST,
109-
},
110-
{ fetchPolicy: "network-only" },
111-
).subscribe({
112-
complete: () => {
113-
setIsRefreshing(false);
114-
},
115-
error: () => {
116-
setIsRefreshing(false);
117-
},
118-
});
119-
}, 10000);
120-
121-
return () => {
122-
clearTimeout(refreshTimerId);
123-
};
124-
}, [id, status, relayEnvironment, isRefreshing, setIsRefreshing]);
125-
126-
return isRefreshing ? <Spinner className="ms-2 mx-auto" /> : null;
127-
};
77+
}
78+
`;
12879

12980
type DeploymentCampaignContentProps = {
13081
getCampaignQuery: PreloadedQuery<DeploymentCampaign_getCampaign_Query>;
@@ -157,9 +108,7 @@ const DeploymentCampaignContent = ({
157108

158109
return (
159110
<Page>
160-
<Page.Header title={campaign.name}>
161-
<DeploymentCampaignRefresh campaignRef={campaign} />
162-
</Page.Header>
111+
<Page.Header title={campaign.name} />
163112
<Page.Main>
164113
<Row>
165114
<Col lg={9}>
@@ -179,6 +128,11 @@ const DeploymentCampaignContent = ({
179128
const DeploymentCampaignPage = () => {
180129
const { deploymentCampaignId = "" } = useParams();
181130

131+
useSubscription({
132+
subscription: CAMPAIGN_UPDATE_SUBSCRIPTION,
133+
variables: { id: deploymentCampaignId },
134+
});
135+
182136
const [getCampaignQuery, getCampaign] =
183137
useQueryLoader<DeploymentCampaign_getCampaign_Query>(GET_CAMPAIGN_QUERY);
184138

0 commit comments

Comments
 (0)