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

FPrime Dictionary and Sequence Support #1447

Merged
merged 6 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 0 additions & 6 deletions src/enums/dictionaryHeaders.ts

This file was deleted.

34 changes: 2 additions & 32 deletions src/routes/dictionaries/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@
import CssGrid from '../../components/ui/CssGrid.svelte';
import Panel from '../../components/ui/Panel.svelte';
import SectionTitle from '../../components/ui/SectionTitle.svelte';
import { DictionaryTypes } from '../../enums/dictionaryTypes';
import { sequenceAdaptations } from '../../stores/sequence-adaptation';
import { channelDictionaries, commandDictionaries, parameterDictionaries } from '../../stores/sequencing';
import effects from '../../utilities/effects';
import { permissionHandler } from '../../utilities/permissionHandler';
import { featurePermissions } from '../../utilities/permissions';
import { showFailureToast, showSuccessToast } from '../../utilities/toast';
import type { PageData } from './$types';

export let data: PageData;
Expand Down Expand Up @@ -51,34 +49,7 @@
creatingDictionary = true;

try {
const uploadedDictionaryOrAdaptation = await effects.uploadDictionaryOrAdaptation(
file,
data.user,
sequenceAdaptationName,
);

if (uploadedDictionaryOrAdaptation === null) {
throw Error('Failed to upload file');
}

switch (uploadedDictionaryOrAdaptation.type) {
case DictionaryTypes.COMMAND: {
showSuccessToast('Command Dictionary Created Successfully');
break;
}
case DictionaryTypes.CHANNEL: {
showSuccessToast('Channel Dictionary Created Successfully');
break;
}
case DictionaryTypes.PARAMETER: {
showSuccessToast('Parameter Dictionary Created Successfully');
break;
}
case DictionaryTypes.ADAPTATION: {
showSuccessToast('Sequence Adaptation Created Successfully');
break;
}
}
await effects.uploadDictionaryOrAdaptation(file, data.user, sequenceAdaptationName);

// Set files to undefined to reset the input form and set the value to empty string to clear the uploaded file.
files = undefined;
Expand All @@ -87,7 +58,6 @@
sequenceAdaptationName = '';
} catch (e) {
createDictionaryError = (e as Error).message;
showFailureToast('Command Dictionary Create Failed');
}

creatingDictionary = false;
Expand Down Expand Up @@ -130,7 +100,7 @@
<fieldset>
<label for="file">AMPCS XML File or Sequence Adaptation</label>
<input
accept=".xml,.js"
accept=".xml,.js,.json"
class="w-100 st-typography-body"
name="file"
required
Expand Down
4 changes: 2 additions & 2 deletions src/utilities/codemirror/sequence.grammar
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,14 @@ HardwareCommands {
TimeTag { TimeAbsolute | (TimeGroundEpoch Name { String } whiteSpace) | TimeEpoch | TimeRelative | TimeComplete }

Args {
(whiteSpace (arg | RepeatArg))* whiteSpace?
(whiteSpace (arg))* whiteSpace?
}

RepeatArg {
"[" (whiteSpace? arg)* whiteSpace? "]"
}

arg[@isGroup=Arguments] { Number | String | Boolean | Enum }
arg[@isGroup=Arguments] { Number | String | Boolean | Enum | RepeatArg }

Command {
TimeTag?
Expand Down
78 changes: 34 additions & 44 deletions src/utilities/effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
} from '@nasa-jpl/aerie-ampcs';
import { get } from 'svelte/store';
import { SchedulingType } from '../constants/scheduling';
import { DictionaryHeaders } from '../enums/dictionaryHeaders';
import { DictionaryTypes } from '../enums/dictionaryTypes';
import { SearchParameters } from '../enums/searchParameters';
import { Status } from '../enums/status';
Expand Down Expand Up @@ -5667,31 +5666,28 @@ const effects = {

async uploadDictionary(
dictionary: string,
type: DictionaryTypes,
user: User | null,
): Promise<CommandDictionary | ChannelDictionary | ParameterDictionary | null> {
const typeString = type.charAt(0).toUpperCase() + type.slice(1);

): Promise<{ channel?: ChannelDictionary; command?: CommandDictionary; parameter?: ParameterDictionary } | null> {
duranb marked this conversation as resolved.
Show resolved Hide resolved
try {
if (!queryPermissions.CREATE_DICTIONARY(user)) {
throwPermissionError(`upload a ${typeString} dictionary`);
throwPermissionError(`upload a dictionary`);
}

const data = await reqHasura<CommandDictionary | ChannelDictionary | ParameterDictionary>(
gql.CREATE_DICTIONARY,
{ dictionary, type },
user,
);
const data = await reqHasura<{
channel?: ChannelDictionary;
command?: CommandDictionary;
parameter?: ParameterDictionary;
}>(gql.CREATE_DICTIONARY, { dictionary }, user);

const { createDictionary: newDictionary } = data;
const { createDictionary: newDictionaries } = data;

if (newDictionary === null) {
throw Error(`Unable to upload ${typeString} Dictionary`);
if (newDictionaries === null) {
throw Error(`Unable to upload Dictionary`);
}

return newDictionary;
return newDictionaries;
} catch (e) {
catchError(`${typeString} Dictionary Upload Failed`, e as Error);
catchError(`Dictionary Upload Failed`, e as Error);
return null;
}
},
Expand All @@ -5700,40 +5696,34 @@ const effects = {
file: File,
user: User | null,
sequenceAdaptationName?: string | undefined,
): Promise<CommandDictionary | ChannelDictionary | ParameterDictionary | SequenceAdaptation | null> {
): Promise<void> {
const text = await file.text();
const splitLineDictionary = text.split('\n');

let type: DictionaryTypes = DictionaryTypes.COMMAND;

switch (splitLineDictionary[1]) {
case `<${DictionaryHeaders.command_dictionary}>`: {
type = DictionaryTypes.COMMAND;
break;
if (sequenceAdaptationName) {
const seqAdaptation = await this.createCustomAdaptation({ adaptation: text, name: sequenceAdaptationName }, user);
if (seqAdaptation === null) {
showFailureToast('Unable to upload sequence adaptation');
throw Error('Unable to upload sequence adaptation');
}
case `<${DictionaryHeaders.telemetry_dictionary}>`: {
type = DictionaryTypes.CHANNEL;
break;
showSuccessToast('Sequence Adaptation Created Successfully');
} else {
const uploadedDictionaries = await this.uploadDictionary(text, user);
if (uploadedDictionaries === null) {
showFailureToast('Failed to upload dictionary file');
throw Error('Failed to upload dictionary file');
} else if (Object.keys(uploadedDictionaries).length === 0) {
showFailureToast('Dictionary Parser return empty data, verify the parser is correctly implemented.');
throw Error('Dictionary Parser return empty data, verify the parser is correctly implemented.');
}
case `<${DictionaryHeaders.param_def}>`: {
type = DictionaryTypes.PARAMETER;
break;
if ('channel' in uploadedDictionaries) {
showSuccessToast('Channel Dictionary Created Successfully');
}
default: {
if (sequenceAdaptationName) {
const adaptation = await this.createCustomAdaptation(
{ adaptation: text, name: sequenceAdaptationName },
user,
);
return adaptation;
}
break;
if ('command' in uploadedDictionaries) {
showSuccessToast('Command Dictionary Created Successfully');
}
if ('parameter' in uploadedDictionaries) {
showSuccessToast('Parameter Dictionary Created Successfully');
}
}

const dictionary = await this.uploadDictionary(text, type, user);

return dictionary;
},

async uploadFile(file: File, user: User | null): Promise<number | null> {
Expand Down
14 changes: 5 additions & 9 deletions src/utilities/gql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -387,15 +387,11 @@ const gql = {
`,

CREATE_DICTIONARY: `#graphql
mutation CreateDictionary($dictionary: String!, $type: String!) {
createDictionary: ${Queries.UPLOAD_DICTIONARY}(dictionary: $dictionary, type : $type) {
dictionary_path
created_at
id
mission
parsed_json
version
type
mutation CreateDictionary($dictionary: String!) {
createDictionary: ${Queries.UPLOAD_DICTIONARY}(dictionary: $dictionary) {
command
parameter
channel
}
}
`,
Expand Down
7 changes: 4 additions & 3 deletions src/utilities/sequence-editor/command-dictionary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ export function fswCommandArgDefault(fswCommandArg: FswCommandArgument, enumMap:
const enumArg = fswCommandArg as FswCommandArgumentEnum;
const enumSymbolValue =
enumMap[enumArg.enum_name]?.values[0]?.symbol ?? fswCommandArg.default_value ?? fswCommandArg.name;
return `"${enumSymbolValue}"` ?? 'UNKNOWN_ENUM';
return enumSymbolValue ? `"${enumSymbolValue}"` : 'UNKNOWN_ENUM';
}
case 'fill' || 'fixed_string':
case 'fill':
case 'fixed_string':
return '""';
case 'float': {
const floatArg = fswCommandArg as FswCommandArgumentFloat;
Expand Down Expand Up @@ -134,7 +135,7 @@ export function fswCommandArgDefault(fswCommandArg: FswCommandArgument, enumMap:
const varStringArg = fswCommandArg as FswCommandArgumentVarString;
const { default_value } = varStringArg;

if (default_value !== null) {
if (default_value) {
return default_value;
} else {
return '""';
Expand Down
5 changes: 2 additions & 3 deletions src/utilities/sequence-editor/grammar.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -417,9 +417,8 @@ Command(Stem,⚠,Args)
CMD2 [
CMD3 ]`,
`Sequence(Commands(
Command(Stem,Args(RepeatArg(⚠))),
Command(Stem,Args(RepeatArg(⚠,Enum)))
))`,
Command(Stem,Args(RepeatArg(RepeatArg,⚠))),
Command(Stem,Args(RepeatArg(⚠))),Command(Stem,Args(⚠))))`,
],
['locals with wrong value types', `@LOCALS "string_not_enum"`, `Sequence(LocalDeclaration(⚠(String)))`],
];
Expand Down
Loading