Skip to content

Commit 41398f1

Browse files
committed
Allow derivation group to be changed
1 parent 940e4c1 commit 41398f1

9 files changed

Lines changed: 178 additions & 23 deletions

File tree

src/components/external-source/ExternalSourceManager.svelte

Lines changed: 65 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
<script lang="ts">
44
import { base } from '$app/paths';
5+
import { Label, Select } from '@nasa-jpl/stellar-svelte';
56
import type { ICellRendererParams, ValueGetterParams } from 'ag-grid-community';
67
import { X } from 'lucide-svelte';
78
import ExternalEventIcon from '../../assets/external-event-box-with-arrow.svg?component';
@@ -10,9 +11,11 @@
1011
createDerivationGroupError,
1112
createExternalSourceError,
1213
creatingExternalSource,
14+
derivationGroups,
1315
externalSources,
1416
externalSourceTypes,
1517
planDerivationGroupLinks,
18+
planDerivationGroupLinksByPlan,
1619
} from '../../stores/external-source';
1720
import { field } from '../../stores/form';
1821
import { plans } from '../../stores/plans';
@@ -131,6 +134,8 @@
131134
let selectedSourceTypeParametersMap: ParametersMap = {};
132135
let selectedSourceId: string | null = null;
133136
let selectedSourceEventTypes: ExternalEventType[] = [];
137+
let selectedSourceDerivationGroup: string | undefined;
138+
let selectedSourceTypeDerivationGroups: string[];
134139
135140
// Selected element variables
136141
let selectedEvent: ExternalEvent | null = null;
@@ -167,6 +172,12 @@
167172
]);
168173
}
169174
175+
$: selectedSourceDerivationGroup = selectedSource?.derivation_group_name;
176+
177+
$: selectedSourceTypeDerivationGroups = $derivationGroups
178+
.filter(derivationGroup => derivationGroup.source_type_name === selectedSource?.source_type_name)
179+
.map(derivationGroup => derivationGroup.name);
180+
170181
$: if (selectedSource !== null && Object.keys(selectedSource.attributes).length > 0) {
171182
// Create an ArgumentsMap for the External Source
172183
selectedSourceAttributes = translateJsonSchemaArgumentsToValueSchema(selectedSource.attributes);
@@ -309,7 +320,7 @@
309320
)
310321
.then(fetched => (selectedSourceEventTypes = fetched));
311322
312-
$: selectedSourceLinkedDerivationGroupsPlans = $planDerivationGroupLinks.filter(planDerivationGroupLink => {
323+
$: selectedSourceLinkedDerivationGroupsPlans = $planDerivationGroupLinksByPlan.filter(planDerivationGroupLink => {
313324
return planDerivationGroupLink.derivation_group_name === selectedSource?.derivation_group_name;
314325
});
315326
@@ -318,11 +329,19 @@
318329
// Permissions
319330
$: hasCreatePermission = featurePermissions.externalSource.canCreate(user);
320331
332+
async function changeDerivationGroup(newDerivationGroup: string | undefined) {
333+
if (!selectedSource || !newDerivationGroup) {
334+
return;
335+
}
336+
await effects.updateSourceDerivationGroup(selectedSource, newDerivationGroup, $planDerivationGroupLinks, user);
337+
deselectSource(); // Would actually like this to stay selected, but the table un-selects due to data change
338+
}
339+
321340
async function onDeleteExternalSource(selectedSources: ExternalSourceSlim[] | null | undefined) {
322341
if (selectedSources !== null && selectedSources !== undefined) {
323342
const deleteExternalSourceResult = await effects.deleteExternalSource(
324343
selectedSources,
325-
$planDerivationGroupLinks,
344+
$planDerivationGroupLinksByPlan,
326345
user,
327346
);
328347
if (deleteExternalSourceResult !== undefined && deleteExternalSourceResult !== null) {
@@ -449,16 +468,50 @@
449468
value={selectedSource.source_type_name}
450469
/>
451470
</Input>
452-
453-
<Input layout="inline">
454-
Derivation Group
455-
<input
456-
class="st-input w-full"
457-
disabled={true}
458-
name="derivation-group"
459-
value={selectedSource.derivation_group_name}
460-
/>
461-
</Input>
471+
<div class="grid">
472+
<Field field={derivationGroupField}>
473+
<Label size="sm" for="derivationGroup">Derivation Group</Label>
474+
<div>
475+
<Select.Root
476+
selected={{ label: selectedSourceDerivationGroup, value: selectedSourceDerivationGroup }}
477+
disabled={false}
478+
onSelectedChange={value => {
479+
if (value) {
480+
changeDerivationGroup(value.value);
481+
}
482+
}}
483+
>
484+
<Select.Trigger
485+
value={selectedSourceDerivationGroup}
486+
size="xs"
487+
aria-label="Change Derivation Group"
488+
aria-labelledby={null}
489+
id="derivationGroup"
490+
>
491+
<Select.Value placeholder="Change derivation group" />
492+
</Select.Trigger>
493+
<Select.Content
494+
class="min-w-[240px] overflow-auto p-0"
495+
sameWidth={false}
496+
align="start"
497+
datatype="text"
498+
fitViewport
499+
>
500+
{#each selectedSourceTypeDerivationGroups as derivationGroup}
501+
<Select.Item size="xs" value={derivationGroup} label={derivationGroup} class="flex gap-1">
502+
{derivationGroup}
503+
</Select.Item>
504+
{/each}
505+
</Select.Content>
506+
<Select.Input
507+
type="text"
508+
name="derivationGroup"
509+
aria-label="Change Derivation Group hidden input"
510+
/>
511+
</Select.Root>
512+
</div>
513+
</Field>
514+
</div>
462515

463516
<Input layout="inline">
464517
Owner

src/components/external-source/ExternalSourcesPanel.svelte

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
derivationGroups,
77
derivationGroupsAcknowledged,
88
externalSources,
9-
planDerivationGroupLinks,
9+
planDerivationGroupLinksByPlan,
1010
} from '../../stores/external-source';
1111
import { plan } from '../../stores/plan';
1212
import type { User } from '../../types/app';
@@ -50,7 +50,7 @@
5050
}
5151
}
5252
53-
$: linkedDerivationGroupNames = $planDerivationGroupLinks.map(
53+
$: linkedDerivationGroupNames = $planDerivationGroupLinksByPlan.map(
5454
planDerivationGroup => planDerivationGroup.derivation_group_name,
5555
);
5656
$: filteredDerivationGroups = $derivationGroups
@@ -66,7 +66,7 @@
6666
const includesName = group.name.toLocaleLowerCase().includes(filterTextLowerCase);
6767
return includesName;
6868
});
69-
$: if ($planDerivationGroupLinks) {
69+
$: if ($planDerivationGroupLinksByPlan) {
7070
mappedDerivationGroups = filteredDerivationGroups.reduce(
7171
(aggMappedDerivationGroups: { [key: string]: DerivationGroup[] }, group) => {
7272
if (

src/components/timeline/Row.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import {
1414
derivationGroupVisibilityMap,
1515
externalSources,
16-
planDerivationGroupLinks,
16+
planDerivationGroupLinksByPlan,
1717
} from '../../stores/external-source';
1818
import { planModelActivityTypes } from '../../stores/plan';
1919
import {
@@ -519,7 +519,7 @@
519519
filteredExternalEvents = [];
520520
521521
// Filter what LINKED Derivation Groups are to be shown
522-
let filteredDerivationGroups = $planDerivationGroupLinks
522+
let filteredDerivationGroups = $planDerivationGroupLinksByPlan
523523
.filter(
524524
link => link.plan_id === plan?.id && !($derivationGroupVisibilityMap[link.derivation_group_name] ?? true),
525525
)

src/components/timeline/Timeline.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import { afterUpdate, createEventDispatcher, onDestroy, onMount, tick } from 'svelte';
88
import { SOURCES, TRIGGERS, dndzone } from 'svelte-dnd-action';
99
import { InvalidDate } from '../../constants/time';
10-
import { planDerivationGroupLinks } from '../../stores/external-source';
10+
import { planDerivationGroupLinksByPlan } from '../../stores/external-source';
1111
import { plugins } from '../../stores/plugins';
1212
import { viewAddTimelineRow, viewUpdateTimeline } from '../../stores/views';
1313
import type { ActivityDirectiveId, ActivityDirectivesMap } from '../../types/activity';
@@ -127,7 +127,7 @@
127127
});
128128
129129
$: activityDirectives = activityDirectivesMap ? Object.values(activityDirectivesMap) : null;
130-
$: derivationGroups = $planDerivationGroupLinks
130+
$: derivationGroups = $planDerivationGroupLinksByPlan
131131
.filter(link => link.plan_id === plan?.id)
132132
.map(link => link.derivation_group_name);
133133
$: externalEventsFilteredByDG = externalEvents.filter(externalEvent =>

src/enums/gql.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ export enum Queries {
229229
UPDATE_CONSTRAINT_MODEL_SPECIFICATION = 'update_constraint_model_specification_by_pk',
230230
UPDATE_DERIVATION_GROUP_ACKNOWLEDGED = 'update_plan_derivation_group_by_pk',
231231
UPDATE_EXPANSION_RULE = 'update_expansion_rule_by_pk',
232+
UPDATE_EXTERNAL_SOURCE = 'update_external_source_by_pk',
232233
UPDATE_MISSION_MODEL = 'update_mission_model_by_pk',
233234
UPDATE_PARCEL = 'update_parcel_by_pk',
234235
UPDATE_PLAN_SNAPSHOT = 'update_plan_snapshot_by_pk',

src/stores/external-source.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ export const derivationGroups = gqlSubscribable<DerivationGroup[]>(
3232
);
3333
export const planDerivationGroupLinks = gqlSubscribable<PlanDerivationGroup[]>(
3434
gql.SUB_PLAN_DERIVATION_GROUP,
35+
{},
36+
[],
37+
null,
38+
);
39+
export const planDerivationGroupLinksByPlan = gqlSubscribable<PlanDerivationGroup[]>(
40+
gql.SUB_PLAN_DERIVATION_GROUP_BY_PLAN,
3541
{
3642
plan_id: planId,
3743
},
@@ -68,7 +74,7 @@ export const externalSourceTypeAssociations: Readable<ExternalSourceTypeAssociat
6874

6975
// Reorganization of unacknowledged planDerivationGroupLinks so that it is easy to the derivation groups and when their updates were last acknowledged
7076
export const derivationGroupsAcknowledged: Readable<Record<string, { last_acknowledged_at: string }>> = derived(
71-
planDerivationGroupLinks,
77+
planDerivationGroupLinksByPlan,
7278
$planDerivationGroupLinks => {
7379
const result: Record<string, { last_acknowledged_at: string }> = {};
7480
for (const entry of $planDerivationGroupLinks) {
@@ -82,7 +88,7 @@ export const derivationGroupsAcknowledged: Readable<Record<string, { last_acknow
8288
);
8389

8490
export const selectedPlanDerivationGroupNames: Readable<string[]> = derived(
85-
[planDerivationGroupLinks],
91+
[planDerivationGroupLinksByPlan],
8692
([$planDerivationGroupLinks]) => $planDerivationGroupLinks.map(link => link.derivation_group_name),
8793
);
8894

@@ -91,7 +97,7 @@ export function resetExternalSourceStores(): void {
9197
createExternalSourceError.set(null);
9298
createDerivationGroupError.set(null);
9399
derivationGroupPlanLinkError.set(null);
94-
planDerivationGroupLinks.updateValue(() => []);
100+
planDerivationGroupLinksByPlan.updateValue(() => []);
95101
}
96102

97103
function transformDerivationGroups(

src/utilities/effects.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8404,6 +8404,58 @@ const effects = {
84048404
}
84058405
},
84068406

8407+
async updateSourceDerivationGroup(
8408+
externalSource: ExternalSourceSlim,
8409+
newDerivationGroupName: string,
8410+
planDerivationGroupLinks: PlanDerivationGroup[],
8411+
user: User | null,
8412+
): Promise<ExternalSourceSlim> {
8413+
try {
8414+
// if (!queryPermissions.UPDATE_DERIVATION_GROUP(user, plan)) { throwPermissionError("update this source's derivation group"); }
8415+
8416+
// Check if any plans are using the derivation group this source is a part of
8417+
const plansUsingDerivationGroup = planDerivationGroupLinks.filter(
8418+
planDerivationGroupLink =>
8419+
planDerivationGroupLink.derivation_group_name === externalSource.derivation_group_name,
8420+
);
8421+
// If any plans are using this derivation group, warn the user
8422+
if (plansUsingDerivationGroup.length > 0) {
8423+
const { confirm } = await showConfirmModal(
8424+
'Confirm',
8425+
`There ${plansUsingDerivationGroup.length > 1 ? 'are' : 'is'} currently ${plansUsingDerivationGroup.length}${
8426+
plansUsingDerivationGroup.length > 1 ? 'plans' : 'plan'
8427+
} using the derivation group this source is a part of. The events of this source will no longer be included in the current derivation group.`,
8428+
'Change Derivation Group',
8429+
true,
8430+
);
8431+
if (!confirm) {
8432+
return externalSource;
8433+
}
8434+
}
8435+
8436+
const updateVariables = {
8437+
externalSourceKey: externalSource.key,
8438+
newDerivationGroup: newDerivationGroupName,
8439+
originalDerivationGroup: externalSource.derivation_group_name,
8440+
};
8441+
const { updated_external_source_by_pk: updatedExternalSource } = await reqHasura<ExternalSourceSlim>(
8442+
gql.UPDATE_SOURCE_DERIVATION_GROUP,
8443+
updateVariables,
8444+
user,
8445+
);
8446+
if (!updatedExternalSource) {
8447+
throw new Error('Derivation Group Update Failed');
8448+
} else {
8449+
showSuccessToast('Derivation Group Updated Successfully');
8450+
return updatedExternalSource;
8451+
}
8452+
} catch (e) {
8453+
catchError('Derivation Group Update Failed', e as Error);
8454+
showFailureToast('Derivation Group Update Failed');
8455+
return externalSource;
8456+
}
8457+
},
8458+
84078459
async updateTag(
84088460
id: number,
84098461
tagSetInput: TagsSetInput,

src/utilities/gql.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2875,7 +2875,18 @@ const gql = {
28752875
`,
28762876

28772877
SUB_PLAN_DERIVATION_GROUP: `#graphql
2878-
subscription SubPlanExternalSource($plan_id: Int!) {
2878+
subscription SubPlanDerivationGroups {
2879+
links: ${Queries.PLAN_DERIVATION_GROUP}(order_by: { plan_id: asc }) {
2880+
derivation_group_name
2881+
plan_id
2882+
acknowledged
2883+
last_acknowledged_at
2884+
}
2885+
}
2886+
`,
2887+
2888+
SUB_PLAN_DERIVATION_GROUP_BY_PLAN: `#graphql
2889+
subscription SubPlanDerivationGroupByPlan($plan_id: Int!) {
28792890
links: ${Queries.PLAN_DERIVATION_GROUP}(order_by: { plan_id: asc }, where: {plan_id: {_eq: $plan_id}}) {
28802891
derivation_group_name
28812892
plan_id
@@ -4159,6 +4170,34 @@ const gql = {
41594170
}
41604171
`,
41614172

4173+
UPDATE_SOURCE_DERIVATION_GROUP: `#graphql
4174+
mutation UpdateSourceDerivationGroup(
4175+
$externalSourceKey: String!,
4176+
$originalDerivationGroup: String!,
4177+
$newDerivationGroup: String!
4178+
) {
4179+
${Queries.UPDATE_EXTERNAL_SOURCE} (
4180+
pk_columns: {
4181+
derivation_group_name: $originalDerivationGroup,
4182+
key: $externalSourceKey
4183+
},
4184+
_set: {
4185+
derivation_group_name: $newDerivationGroup
4186+
}
4187+
) {
4188+
attributes
4189+
created_at
4190+
derivation_group_name
4191+
end_time
4192+
key
4193+
owner
4194+
source_type_name
4195+
start_time
4196+
valid_at
4197+
}
4198+
}
4199+
`,
4200+
41624201
UPDATE_TAG: `#graphql
41634202
mutation UpdateTag($id: Int!, $tagSetInput: tags_set_input!) {
41644203
${Queries.UPDATE_TAGS}(pk_columns: {id: $id}, _set: $tagSetInput) {

src/utilities/permissions.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,6 +1005,7 @@ const queryPermissions: Record<GQLKeys, (user: User | null, ...args: any[]) => b
10051005
SUB_PLANS_USER_WRITABLE: () => true,
10061006
SUB_PLAN_DATASET: () => true,
10071007
SUB_PLAN_DERIVATION_GROUP: () => true,
1008+
SUB_PLAN_DERIVATION_GROUP_BY_PLAN: () => true,
10081009
SUB_PLAN_EXTERNAL_EVENTS_DERIVATION_GROUP: () => true,
10091010
SUB_PLAN_LOCKED: () => true,
10101011
SUB_PLAN_MERGE_CONFLICTING_ACTIVITIES: () => true,
@@ -1293,6 +1294,9 @@ const queryPermissions: Record<GQLKeys, (user: User | null, ...args: any[]) => b
12931294
UPDATE_SIMULATION_TEMPLATE: (user: User | null, plan: PlanWithOwners): boolean => {
12941295
return isUserAdmin(user) || (getPermission([Queries.UPDATE_SIMULATION_TEMPLATE], user) && isUserOwner(user, plan));
12951296
},
1297+
UPDATE_SOURCE_DERIVATION_GROUP: (user: User | null) => {
1298+
return isUserAdmin(user) || getPermission([getFunctionPermission(Queries.UPDATE_EXTERNAL_SOURCE)], user);
1299+
},
12961300
UPDATE_TAG: (user: User | null, tag: AssetWithOwner<Tag>): boolean => {
12971301
return isUserAdmin(user) || (getPermission([Queries.UPDATE_TAGS], user) && isUserOwner(user, tag));
12981302
},

0 commit comments

Comments
 (0)