Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dh): apollo data source #3517

Merged
merged 47 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
cbb7f6c
Save working state
ManBearTM Sep 10, 2024
9af81b0
Refactor codegen plugin
ManBearTM Sep 12, 2024
d1f5270
chore: add license
github-actions[bot] Sep 12, 2024
791aeee
Add docs
ManBearTM Sep 12, 2024
ba7a202
style: format
github-actions[bot] Sep 12, 2024
0c1f91e
Remove .vscode folder
ManBearTM Sep 12, 2024
79ffd31
Make getOptions instead of getVariables for consistency
ManBearTM Sep 12, 2024
a37e92e
Keep the non-nullable data
ManBearTM Sep 12, 2024
24b0436
Bring back comment
ManBearTM Sep 12, 2024
6e7a1f5
Fix type
ManBearTM Sep 12, 2024
189107f
Improve some things
ManBearTM Sep 12, 2024
0ac629f
More refactorings
Sep 16, 2024
a1ae76c
Merge branch 'main' into feat/apollo-data-source
ManBearTM Sep 18, 2024
5357c0f
style: format
github-actions[bot] Sep 18, 2024
6299f07
Save working state
ManBearTM Sep 18, 2024
39d6bbe
chore: add license
github-actions[bot] Sep 18, 2024
54fb024
Restore swagger.json
ManBearTM Sep 18, 2024
96101c2
Revert nswag
ManBearTM Sep 18, 2024
e39d57e
Tweak paging defaults in GraphQL
ManBearTM Sep 18, 2024
8e51b21
Add paging util
ManBearTM Sep 18, 2024
21a5827
Make options observable shared to prevent duplicate queries + remove if
ManBearTM Sep 18, 2024
c26b91c
Lots of tweaks to dataSource.ts
ManBearTM Sep 18, 2024
47adfa5
chore: add license
github-actions[bot] Sep 18, 2024
e3c6c6d
Remove unneeded properties from interface
ManBearTM Sep 18, 2024
1e70144
Make watt-paginator signal based
ManBearTM Sep 18, 2024
46f7077
Add error to dataSource
ManBearTM Sep 18, 2024
4483904
Do not reset order on input change
ManBearTM Sep 18, 2024
b4283d7
Add subscribeToMore functionality to dataSource
ManBearTM Sep 18, 2024
977ce9c
Missing newline
ManBearTM Sep 18, 2024
3336725
Use dataSource.error in view
ManBearTM Sep 18, 2024
c6cff1f
Change calculation subscription to only handle updates
ManBearTM Sep 18, 2024
4f2af8d
Make it so that dataSources do not require a refetch
ManBearTM Sep 18, 2024
b3d4ef5
Make CalculationUpdated query work with calculations
ManBearTM Sep 18, 2024
edaa4e6
Refetch on create
ManBearTM Sep 18, 2024
78b21cf
Bring back create calculation event in subscription
ManBearTM Sep 18, 2024
e37d693
Revert prettier change
ManBearTM Sep 18, 2024
8cb2dd5
style: format
github-actions[bot] Sep 18, 2024
3e16d1a
Merge branch 'main' into feat/apollo-data-source
ManBearTM Sep 18, 2024
e93ec11
AddSorting in GraphQL test service
ManBearTM Sep 18, 2024
79a949f
Update schema snapshot
ManBearTM Sep 18, 2024
9a0f820
Fix mocks
ManBearTM Sep 18, 2024
f0acc6c
Ignore dist from eslint
ManBearTM Sep 18, 2024
d8ebad3
Remove test target
ManBearTM Sep 18, 2024
df665a6
Fix eo paginator usage
ManBearTM Sep 18, 2024
1416ebe
Guard against empty calculation
ManBearTM Sep 18, 2024
afd8689
Less concise, more correct
ManBearTM Sep 18, 2024
82b4764
Try parse
ManBearTM Sep 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,24 @@ type CalculationProgress {
status: ProgressStatus!
}

"A connection to a list of items."
type CalculationsConnection {
"Information to aid in pagination."
pageInfo: PageInfo!
"A list of edges."
edges: [CalculationsEdge!]
"A flattened list of the nodes."
nodes: [Calculation!]
}

"An edge in a connection."
type CalculationsEdge {
"A cursor for use in pagination."
cursor: String!
"The item at the end of the edge."
node: Calculation!
}

type CancelScheduledCalculationPayload {
boolean: Boolean
}
Expand Down Expand Up @@ -405,6 +423,18 @@ type OrganizationAuditedChangeAuditLogDto {
previousValue: String
}

"Information about pagination in a connection."
type PageInfo {
"Indicates whether more edges exist following the set defined by the clients arguments."
hasNextPage: Boolean!
"Indicates whether more edges exist prior the set defined by the clients arguments."
hasPreviousPage: Boolean!
"When paginating backwards, the cursor to continue."
startCursor: String
"When paginating forwards, the cursor to continue."
endCursor: String
}

type Permission {
userRoles: [UserRoleDto!]!
id: Int!
Expand Down Expand Up @@ -447,7 +477,7 @@ type Query {
filteredActors: [Actor!]!
selectionActors: [SelectionActorDto!]!
calculationById(id: UUID!): Calculation!
calculations(input: CalculationQueryInput!): [Calculation!]!
calculations(input: CalculationQueryInput! filter: String "Returns the first _n_ elements from the list." first: Int "Returns the elements in the list that come after the specified cursor." after: String "Returns the last _n_ elements from the list." last: Int "Returns the elements in the list that come before the specified cursor." before: String order: [CalculationSortInput!]): CalculationsConnection
latestBalanceFixing(period: DateRange!): Calculation @deprecated(reason: "Use `latestCalculation` instead")
latestCalculation(period: DateRange! calculationType: CalculationType!): Calculation
esettServiceStatus: [ReadinessStatusDto!]!
Expand Down Expand Up @@ -712,6 +742,17 @@ input CalculationQueryInput {
period: DateRange
}

"An immutable calculation."
input CalculationSortInput {
"Defines the wholesale calculation type"
calculationType: SortEnumType
isInternalCalculation: SortEnumType
executionTime: SortEnumType
status: SortEnumType
period: SortEnumType
executionType: SortEnumType
}

input CancelScheduledCalculationInput {
calculationId: UUID!
}
Expand Down Expand Up @@ -1208,6 +1249,11 @@ enum SortDirection {
DESCENDING
}

enum SortEnumType {
ASC
DESC
}

enum UserAuditedChange {
FIRST_NAME
LAST_NAME
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public GraphQLTestService()
.AddMutationConventions(applyToAllMutations: true)
.AddMutationType<Mutation>()
.AddTypes()
.AddSorting()
.BindRuntimeType<NodaTime.Interval, DateRangeType>()
.Services
.AddSingleton(WholesaleClientV3Mock.Object)
Expand Down
11 changes: 6 additions & 5 deletions apps/dh/api-dh/source/DataHub.WebApi/DataHub.WebApi.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ limitations under the License.
</PropertyGroup>

<Target Name="NSwag" AfterTargets="PostBuildEvent" Condition="'$(Configuration)' == 'Debug'">
<Exec WorkingDirectory="$(ProjectDir)" EnvironmentVariables="ASPNETCORE_ENVIRONMENT=Development" Command="$(NSwagExe_Net80) run Clients/Wholesale/V3/nswag.json /variables:Configuration=$(Configuration)" Condition="!Exists('Clients/Wholesale/V3/swagger.json')"/>
<Exec WorkingDirectory="$(ProjectDir)" EnvironmentVariables="ASPNETCORE_ENVIRONMENT=Development" Command="$(NSwagExe_Net80) run Clients/EDI/B2CWebApi/V1/nswag.json /variables:Configuration=$(Configuration)" Condition="!Exists('Clients/EDI/B2CWebApi/V1/swagger.json')"/>
<Exec WorkingDirectory="$(ProjectDir)" EnvironmentVariables="ASPNETCORE_ENVIRONMENT=Development" Command="$(NSwagExe_Net80) run Clients/ESettExchange/V1/nswag.json /variables:Configuration=$(Configuration) &amp;&amp; powershell -File default-api-version-param.ps1 Clients/ESettExchange/V1/ESettExchangeClient.cs &amp;&amp; dotnet build" Condition="!Exists('Clients/ESettExchange/V1/swagger.json')"/>
<Exec WorkingDirectory="$(ProjectDir)" EnvironmentVariables="ASPNETCORE_ENVIRONMENT=Development" Command="$(NSwagExe_Net80) run Clients/ImbalancePrices/V1/nswag.json /variables:Configuration=$(Configuration) &amp;&amp; powershell -File default-api-version-param.ps1 Clients/ImbalancePrices/V1/ImbalancePricesClient.cs &amp;&amp; dotnet build" Condition="!Exists('Clients/ImbalancePrices/V1/swagger.json')"/>
<Exec WorkingDirectory="$(ProjectDir)" EnvironmentVariables="ASPNETCORE_ENVIRONMENT=Development" Command="$(NSwagExe_Net80) run Clients/MarketParticipant/V1/nswag.json /variables:Configuration=$(Configuration) &amp;&amp; powershell -File default-api-version-param.ps1 Clients/MarketParticipant/V1/MarketParticipantClient.cs &amp;&amp; dotnet build" Condition="!Exists('Clients/MarketParticipant/V1/swagger.json')"/>
<Exec WorkingDirectory="$(ProjectDir)" EnvironmentVariables="ASPNETCORE_ENVIRONMENT=Development" Command="$(NSwagExe_Net80) run Clients/Wholesale/V3/nswag.json /variables:Configuration=$(Configuration)" Condition="!Exists('Clients/Wholesale/V3/swagger.json')" />
<Exec WorkingDirectory="$(ProjectDir)" EnvironmentVariables="ASPNETCORE_ENVIRONMENT=Development" Command="$(NSwagExe_Net80) run Clients/EDI/B2CWebApi/V1/nswag.json /variables:Configuration=$(Configuration)" Condition="!Exists('Clients/EDI/B2CWebApi/V1/swagger.json')" />
<Exec WorkingDirectory="$(ProjectDir)" EnvironmentVariables="ASPNETCORE_ENVIRONMENT=Development" Command="$(NSwagExe_Net80) run Clients/ESettExchange/V1/nswag.json /variables:Configuration=$(Configuration) &amp;&amp; powershell -File default-api-version-param.ps1 Clients/ESettExchange/V1/ESettExchangeClient.cs &amp;&amp; dotnet build" Condition="!Exists('Clients/ESettExchange/V1/swagger.json')" />
<Exec WorkingDirectory="$(ProjectDir)" EnvironmentVariables="ASPNETCORE_ENVIRONMENT=Development" Command="$(NSwagExe_Net80) run Clients/ImbalancePrices/V1/nswag.json /variables:Configuration=$(Configuration) &amp;&amp; powershell -File default-api-version-param.ps1 Clients/ImbalancePrices/V1/ImbalancePricesClient.cs &amp;&amp; dotnet build" Condition="!Exists('Clients/ImbalancePrices/V1/swagger.json')" />
<Exec WorkingDirectory="$(ProjectDir)" EnvironmentVariables="ASPNETCORE_ENVIRONMENT=Development" Command="$(NSwagExe_Net80) run Clients/MarketParticipant/V1/nswag.json /variables:Configuration=$(Configuration) &amp;&amp; powershell -File default-api-version-param.ps1 Clients/MarketParticipant/V1/MarketParticipantClient.cs &amp;&amp; dotnet build" Condition="!Exists('Clients/MarketParticipant/V1/swagger.json')" />
</Target>

<Target Name="PostBuild" AfterTargets="PostBuildEvent">
Expand All @@ -51,6 +51,7 @@ limitations under the License.
<PackageReference Include="HotChocolate.AspNetCore" Version="13.9.0" />
<PackageReference Include="HotChocolate.AspNetCore.Authorization" Version="13.9.0" />
<PackageReference Include="HotChocolate.AspNetCore.CommandLine" Version="13.9.0" />
<PackageReference Include="HotChocolate.Data" Version="13.9.0" />
<PackageReference Include="HotChocolate.Diagnostics" Version="13.9.0" />
<PackageReference Include="HotChocolate.Types.Analyzers" Version="13.9.0">
<PrivateAssets>all</PrivateAssets>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,28 @@ public async Task<CalculationDto> GetCalculationByIdAsync(
[Service] IWholesaleClient_V3 client) =>
await client.GetCalculationAsync(id);

[UsePaging]
[UseSorting]
public async Task<IEnumerable<CalculationDto>> GetCalculationsAsync(
CalculationQueryInput input,
[Service] IWholesaleClient_V3 client) =>
await client.QueryCalculationsAsync(input);
string? filter,
[Service] IWholesaleClient_V3 client)
{
if (string.IsNullOrWhiteSpace(filter))
{
return await client.QueryCalculationsAsync(input);
}

try
{
var calculationId = Guid.Parse(filter);
return [await client.GetCalculationAsync(calculationId)];
}
catch (Exception)
{
return [];
}
}

[GraphQLDeprecated("Use `latestCalculation` instead")]
public async Task<CalculationDto?> GetLatestBalanceFixingAsync(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,27 +22,22 @@ namespace Energinet.DataHub.WebApi.GraphQL.Subscription;

public class Subscription
{
public IObservable<CalculationDto> OnCalculationProgressAsync(
CalculationQueryInput input,
public IObservable<CalculationDto> OnCalculationUpdatedAsync(
[Service] ITopicEventReceiver eventReceiver,
[Service] IWholesaleClient_V3 client,
CancellationToken cancellationToken)
{
var states = input.States ?? [];
var calculationIdStream = eventReceiver
.Observe<Guid>(nameof(Mutation.Mutation.CreateCalculationAsync), cancellationToken);

// Prevent starting a subscription for calculations that are not in progress
if (states.Length > 0 && !states.Any(IsInProgress))
{
return Observable.Empty<CalculationDto>();
}
.Observe<Guid>(nameof(Mutation.Mutation.CreateCalculationAsync), cancellationToken);

// Filter the list of states to only include those that are in progress
var inProgressCalculations = input with { States = states.Where(IsInProgress).ToArray() };
var input = new CalculationQueryInput()
{
States = Enum.GetValues<CalculationOrchestrationState>().Where(IsInProgress).ToArray(),
};

return Observable
.FromAsync(() => client.QueryCalculationsAsync(inProgressCalculations))
.FromAsync(() => client.QueryCalculationsAsync(input))
.SelectMany(calculations => calculations)
.Select(calculation => calculation.CalculationId)
.Merge(calculationIdStream)
Expand All @@ -55,8 +50,8 @@ public IObservable<CalculationDto> OnCalculationProgressAsync(
.TakeUntil(calculation => !IsInProgress(calculation.OrchestrationState)));
}

[Subscribe(With = nameof(OnCalculationProgressAsync))]
public CalculationDto CalculationProgress([EventMessage] CalculationDto calculation) =>
[Subscribe(With = nameof(OnCalculationUpdatedAsync))]
public CalculationDto CalculationUpdated([EventMessage] CalculationDto calculation) =>
calculation;

public bool IsInProgress(CalculationOrchestrationState state) =>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2020 Energinet DataHub A/S
//
// Licensed under the Apache License, Version 2.0 (the "License2");
// 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.

using Energinet.DataHub.WebApi.Clients.Wholesale.v3;
using Energinet.DataHub.WebApi.GraphQL.Enums;
using HotChocolate.Data.Sorting;

namespace Energinet.DataHub.WebApi.GraphQL.Types.Calculation;

public class CalculationSortType : SortInputType<CalculationDto>
{
protected override void Configure(ISortInputTypeDescriptor<CalculationDto> descriptor)
{
descriptor.Name("CalculationSortInput");
descriptor.BindFieldsExplicitly();
descriptor.Field(f => f.CalculationType);
descriptor.Field(f => f.IsInternalCalculation);
descriptor.Field(f => f.ExecutionTimeStart ?? f.ScheduledAt).Name("executionTime");
descriptor.Field(f => f.OrchestrationState).Name("status");
descriptor.Field(f => f.PeriodStart).Name("period");
descriptor
.Field(f => f.IsInternalCalculation ? CalculationExecutionType.Internal : CalculationExecutionType.External)
.Name("executionType");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
using Energinet.DataHub.WebApi.GraphQL.Scalars;
using Energinet.DataHub.WebApi.GraphQL.Subscription;
using HotChocolate.Execution.Configuration;
using HotChocolate.Types.Pagination;
using NodaTime;

namespace Energinet.DataHub.WebApi.Registration;
Expand All @@ -35,6 +36,13 @@ public static IRequestExecutorBuilder AddGraphQLServices(this IServiceCollection
.AddMutationType<Mutation>()
.AddSubscriptionType<Subscription>()
.AddTypes()
.BindRuntimeType<Interval, DateRangeType>();
.AddSorting()
.BindRuntimeType<Interval, DateRangeType>()
.SetPagingOptions(new PagingOptions
{
RequirePagingBoundaries = true,
MaxPageSize = 250,
IncludeTotalCount = true,
});
}
}
1 change: 1 addition & 0 deletions codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const config: CodegenConfig = {
'typed-document-node',
'typescript-msw',
'@homebound/graphql-typescript-scalar-type-policies',
'libs/dh/shared/feature-graphql-codegen/dist/apollo-data-source.js',
],
config: {
nonOptionalTypename: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export class DhRolesTabTableComponent implements OnChanges, AfterViewInit {

ngOnChanges() {
this.dataSource.data = this.roles();
this.dataSource.paginator = this.paginator()?.instance;
this.dataSource.paginator = this.paginator()?.instance();
this.updateFilteredAndSortedData();
}

Expand All @@ -122,7 +122,7 @@ export class DhRolesTabTableComponent implements OnChanges, AfterViewInit {
this.updateFilteredAndSortedData();
});

this.dataSource.paginator = this.paginator()?.instance;
this.dataSource.paginator = this.paginator()?.instance();

this.dataSource.sortingDataAccessor = (data, header) =>
header === 'marketRole'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -901,7 +901,7 @@
"emptyMessage": "Prøv at ændre dine søgeindstillinger",
"errorTitle": "{{shared.error.title}}",
"errorMessage": "{{shared.error.message}}",
"search": "Søg",
"search": "Søg på ID",
"new": "Ny beregning",
"scheduledCalculationTooltip": "Det faktiske tidspunkt kan afvige fra det planlagte tidspunkt",
"create": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -902,7 +902,7 @@
"emptyMessage": "Try changing the search criteria",
"errorTitle": "{{shared.error.title}}",
"errorMessage": "{{shared.error.message}}",
"search": "Search",
"search": "Search by ID",
"new": "New calculation",
"scheduledCalculationTooltip": "The actual time may differ from the scheduled time",
"create": {
Expand Down
16 changes: 15 additions & 1 deletion libs/dh/shared/data-access-mocks/src/lib/wholesale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,21 @@ function getCalculations() {
} else {
await delay(mswConfig.delay);
return HttpResponse.json({
data: { __typename: 'Query', calculations: mockedCalculations },
data: {
__typename: 'Query',
calculations: {
__typename: 'CalculationsConnection',
pageInfo: {
__typename: 'PageInfo',
hasNextPage: true,
hasPreviousPage: false,
startCursor: 'startCursor',
endCursor: 'endCursor',
},
totalCount: mockedCalculations.length,
nodes: mockedCalculations,
},
},
});
//return res(ctx.status(404), ctx.delay(300));
}
Expand Down
4 changes: 4 additions & 0 deletions libs/dh/shared/domain/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
"executor": "nx:run-commands",
"cache": true,
"inputs": [
"{workspaceRoot}/codegen.ts",
"{workspaceRoot}/libs/dh/shared/feature-graphql-codegen/**/*.js",
"{workspaceRoot}/libs/**/*.graphql",
"!{projectRoot}/src/lib/generated/graphql.ts"
],
Expand All @@ -30,6 +32,8 @@
"executor": "nx:run-commands",
"cache": false,
"inputs": [
"{workspaceRoot}/codegen.ts",
"{workspaceRoot}/libs/dh/shared/util-apollo/src/lib/codegen.js",
"{workspaceRoot}/libs/**/*.graphql",
"!{projectRoot}/src/lib/generated/graphql.ts"
],
Expand Down
36 changes: 36 additions & 0 deletions libs/dh/shared/feature-graphql-codegen/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"extends": ["../../../../.eslintrc.json"],
"ignorePatterns": ["!**/*", "dist/**/*"],
"overrides": [
{
"files": ["*.ts"],
"extends": [
"plugin:@nx/angular",
"plugin:@angular-eslint/template/process-inline-templates"
],
"rules": {
"@angular-eslint/directive-selector": [
"error",
{
"type": "attribute",
"prefix": "dh",
"style": "camelCase"
}
],
"@angular-eslint/component-selector": [
"error",
{
"type": "element",
"prefix": "dh",
"style": "kebab-case"
}
]
}
},
{
"files": ["*.html"],
"extends": ["plugin:@nx/angular-template"],
"rules": {}
}
]
}
17 changes: 17 additions & 0 deletions libs/dh/shared/feature-graphql-codegen/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Graphql Codegen

This library is for custom GraphQL Codegen plugins.

## Development

Paths to plugins are specificed in the `codegen.ts` file. These files must be in CommonJS
format, which is why this project has a custom `build` target. When the desired changes
have been made to the TypeScript file, run the below command to generate the CommonJS
file in the `dist` folder:

```sh
bun nx run dh-shared-feature-graphql-codegen:build
```

_For convenience and a simpler setup, the contents of the `dist` folder is intentionally
checked into source control._
Loading
Loading