Skip to content

Commit 17ef806

Browse files
authored
feat: Pre-emptively decode binary literals (#889)
* Revert "feat: Launch Form Msgpack IDL Supporting (#888)" This reverts commit d1dc889. * Pre-emptively decode binary literals Signed-off-by: Carina Ursu <carina@union.ai> * lint fixes Signed-off-by: Carina Ursu <carina@union.ai> * fix literal.helpers.test.ts Signed-off-by: Carina Ursu <carina@union.ai> --------- Signed-off-by: Carina Ursu <carina@union.ai>
1 parent d1dc889 commit 17ef806

File tree

19 files changed

+342
-184
lines changed

19 files changed

+342
-184
lines changed

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@
5656
"dependencies": {
5757
"@commitlint/cli": "^17.3.0",
5858
"@commitlint/config-conventional": "^17.3.0",
59-
"@msgpack/msgpack": "^3.0.0-beta2",
6059
"@semantic-release/changelog": "^5.0.1",
6160
"@semantic-release/commit-analyzer": "^8.0.1",
6261
"@semantic-release/exec": "^6.0.3",

packages/common/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"tslib": "^2.4.1"
2525
},
2626
"dependencies": {
27-
"@flyteorg/flyteidl": "^1.10.7",
27+
"@flyteorg/flyteidl": "^1.13.5",
2828
"@protobuf-ts/runtime": "^2.6.0",
2929
"@protobuf-ts/runtime-rpc": "^2.6.0"
3030
},
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { google } from '@flyteorg/flyteidl/gen/pb-js/flyteidl';
2+
3+
/** Message classes for google entities */
4+
5+
export default google;

packages/oss-console/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
"lossless-json": "^1.0.3",
8080
"memoize-one": "^5.0.0",
8181
"moment-timezone": "^0.5.28",
82+
"msgpackr": "^1.11.2",
8283
"msw": "^1.3.2",
8384
"notistack": "^3.0.1",
8485
"object-hash": "^1.3.1",

packages/oss-console/src/App/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import '../common/setupProtobuf';
2+
import '../common/decodeMsgPackLiterals';
23
import React, { PropsWithChildren } from 'react';
34
import Collapse from '@mui/material/Collapse';
45
import { FlyteApiProvider } from '@clients/flyte-api/ApiProvider';
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import core from '@clients/common/flyteidl/core';
2+
import google from '@clients/common/flyteidl/google';
3+
import $protobuf from 'protobufjs';
4+
import { unpack } from 'msgpackr';
5+
import isNil from 'lodash/isNil';
6+
import entries from 'lodash/entries';
7+
8+
// Convert a JavaScript object to Protobuf Struct
9+
function convertToStruct(obj: any) {
10+
const struct = new google.protobuf.Struct({
11+
fields: {},
12+
});
13+
14+
entries(obj).forEach(([key, value]) => {
15+
struct.fields[key] = convertToValue(value);
16+
});
17+
18+
return struct;
19+
}
20+
21+
// Convert values to Protobuf Value type
22+
function convertToValue(value: any) {
23+
const protoValue = new google.protobuf.Value();
24+
25+
if (Array.isArray(value)) {
26+
const listValues = value.map(convertToValue);
27+
protoValue.listValue = new google.protobuf.ListValue({ values: listValues });
28+
} else if (typeof value === 'object' && value !== null) {
29+
protoValue.structValue = convertToStruct(value);
30+
} else if (typeof value === 'string') {
31+
protoValue.stringValue = value;
32+
} else if (typeof value === 'number') {
33+
protoValue.numberValue = value;
34+
} else if (typeof value === 'boolean') {
35+
protoValue.boolValue = value;
36+
} else if (value === null) {
37+
protoValue.nullValue = google.protobuf.NullValue.NULL_VALUE;
38+
}
39+
40+
return protoValue;
41+
}
42+
43+
const originalLiteralDecode = core.Literal.decode;
44+
// Overriding the decode method of Literal to convert msgpack binary literals to protobuf structs
45+
core.Literal.decode = (reader: $protobuf.Reader | Uint8Array, length?: number) => {
46+
const result = originalLiteralDecode(reader, length);
47+
48+
if (result?.scalar?.binary?.tag === 'msgpack') {
49+
// We know that a binary literal with tag 'msgpack' is a STRUCT
50+
const value = result?.scalar?.binary?.value;
51+
const msgpackResult = isNil(value) ? value : unpack(value);
52+
// Convert the msgpack result to a protobuf struct
53+
const protobufStruct = convertToStruct(msgpackResult);
54+
55+
return {
56+
metadata: result.metadata,
57+
hash: result.hash,
58+
scalar: {
59+
generic: protobufStruct,
60+
},
61+
} as core.Literal;
62+
}
63+
return result;
64+
};

packages/oss-console/src/components/Executions/ExecutionDetails/ExecutionLabels.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react';
22
import Chip from '@mui/material/Chip';
33
import makeStyles from '@mui/styles/makeStyles';
44

5-
type ValuesType = {[p: string]: string};
5+
type ValuesType = { [p: string]: string };
66
interface Props {
77
values: ValuesType;
88
}
@@ -12,21 +12,20 @@ const useStyles = makeStyles({
1212
display: 'flex',
1313
flexWrap: 'wrap',
1414
width: '100%',
15-
maxWidth: '420px'
15+
maxWidth: '420px',
1616
},
1717
chip: {
1818
margin: '2px 2px 2px 0',
1919
},
2020
});
2121

22-
23-
export const ExecutionLabels: React.FC<Props> = ({values}) => {
22+
export const ExecutionLabels: React.FC<Props> = ({ values }) => {
2423
const classes = useStyles();
2524
return (
2625
<div className={classes.chipContainer}>
2726
{Object.entries(values).map(([key, value]) => (
2827
<Chip
29-
color='info'
28+
color="info"
3029
key={key}
3130
label={value ? `${key}: ${value}` : key}
3231
className={classes.chip}

packages/oss-console/src/components/Executions/ExecutionDetails/ExecutionMetadata.tsx

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,7 @@ export const ExecutionMetadata: React.FC<{}> = () => {
7171
const workflowId = execution?.closure?.workflowId;
7272

7373
const { labels } = execution.spec;
74-
const {
75-
referenceExecution,
76-
systemMetadata ,
77-
parentNodeExecution,
78-
} = execution.spec.metadata;
74+
const { referenceExecution, systemMetadata, parentNodeExecution } = execution.spec.metadata;
7975
const cluster = systemMetadata?.executionCluster ?? dashedValueString;
8076

8177
const details: DetailItem[] = [
@@ -130,11 +126,13 @@ export const ExecutionMetadata: React.FC<{}> = () => {
130126
if (labels != null && labels.values != null) {
131127
details.push({
132128
label: ExecutionMetadataLabels.labels,
133-
value: (
134-
Object.entries(labels.values).length > 0 ?
135-
<ExecutionLabels values={labels.values} /> : dashedValueString
136-
)
137-
})
129+
value:
130+
Object.entries(labels.values).length > 0 ? (
131+
<ExecutionLabels values={labels.values} />
132+
) : (
133+
dashedValueString
134+
),
135+
});
138136
}
139137

140138
return (

packages/oss-console/src/components/Executions/ExecutionDetails/ExecutionNodeURL.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,14 @@ export const ExecutionNodeURL: React.FC<{
3434

3535
const config =
3636
// eslint-disable-next-line no-nested-ternary
37-
env.CODE_SNIPPET_USE_AUTO_CONFIG === "true"
37+
env.CODE_SNIPPET_USE_AUTO_CONFIG === 'true'
3838
? 'Config.auto()'
3939
: isHttps
4040
? // https snippet
4141
`Config.for_endpoint("${window.location.host}")`
4242
: // http snippet
4343
`Config.for_endpoint("${window.location.host}", True)`;
44-
const code = `from flytekit.remote.remote import FlyteRemote
44+
const code = `from flytekit.remote.remote import FlyteRemote
4545
from flytekit.configuration import Config
4646
remote = FlyteRemote(
4747
${config},

packages/oss-console/src/components/Executions/ExecutionDetails/test/ExecutionLabels.test.tsx

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,31 @@ import '@testing-library/jest-dom';
44
import { ExecutionLabels } from '../ExecutionLabels';
55

66
jest.mock('@mui/material/Chip', () => (props: any) => (
7-
<div data-testid="chip" {...props}>{props.label}</div>
7+
<div data-testid="chip" {...props}>
8+
{props.label}
9+
</div>
810
));
911

1012
describe('ExecutionLabels', () => {
1113
it('renders chips with key-value pairs correctly', () => {
1214
const values = {
1315
'random/uuid': 'f8b9ff18-4811-4bcc-aefd-4f4ec4de469d',
14-
'bar': 'baz',
15-
'foo': '',
16+
bar: 'baz',
17+
foo: '',
1618
};
1719

1820
render(<ExecutionLabels values={values} />);
1921

20-
expect(screen.getByText('random/uuid: f8b9ff18-4811-4bcc-aefd-4f4ec4de469d')).toBeInTheDocument();
22+
expect(
23+
screen.getByText('random/uuid: f8b9ff18-4811-4bcc-aefd-4f4ec4de469d'),
24+
).toBeInTheDocument();
2125
expect(screen.getByText('bar: baz')).toBeInTheDocument();
2226
expect(screen.getByText('foo')).toBeInTheDocument();
2327
});
2428

2529
it('applies correct styles to chip container', () => {
2630
const values = {
27-
'key': 'value',
31+
key: 'value',
2832
};
2933

3034
const { container } = render(<ExecutionLabels values={values} />);
@@ -38,9 +42,9 @@ describe('ExecutionLabels', () => {
3842

3943
it('renders correct number of chips', () => {
4044
const values = {
41-
'key1': 'value1',
42-
'key2': 'value2',
43-
'key3': 'value3',
45+
key1: 'value1',
46+
key2: 'value2',
47+
key3: 'value3',
4448
};
4549

4650
render(<ExecutionLabels values={values} />);

packages/oss-console/src/components/Executions/ExecutionDetails/test/ExecutionMetadata.test.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const durationTestId = `metadata-${ExecutionMetadataLabels.duration}`;
1515
const interruptibleTestId = `metadata-${ExecutionMetadataLabels.interruptible}`;
1616
const overwriteCacheTestId = `metadata-${ExecutionMetadataLabels.overwriteCache}`;
1717
const relatedToTestId = `metadata-${ExecutionMetadataLabels.relatedTo}`;
18-
const parentNodeExecutionTestId = `metadata-${ExecutionMetadataLabels.parent}`
18+
const parentNodeExecutionTestId = `metadata-${ExecutionMetadataLabels.parent}`;
1919
const labelsTestId = `metadata-${ExecutionMetadataLabels.labels}`;
2020

2121
jest.mock('../../../../models/Launch/api', () => ({
@@ -113,15 +113,15 @@ describe('ExecutionMetadata', () => {
113113
it('shows related to if metadata is available', () => {
114114
const { getByTestId } = renderMetadata();
115115
expect(getByTestId(relatedToTestId)).toHaveTextContent('name');
116-
})
116+
});
117117

118118
it('shows parent execution if metadata is available', () => {
119119
const { getByTestId } = renderMetadata();
120120
expect(getByTestId(parentNodeExecutionTestId)).toHaveTextContent('name');
121-
})
121+
});
122122

123123
it('shows labels if spec has them', () => {
124124
const { getByTestId } = renderMetadata();
125-
expect(getByTestId(labelsTestId)).toHaveTextContent("key: value");
126-
})
125+
expect(getByTestId(labelsTestId)).toHaveTextContent('key: value');
126+
});
127127
});

packages/oss-console/src/components/Launch/LaunchForm/LaunchFormComponents/StructInput.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import React, { FC, useCallback, useEffect, useMemo, useState } from 'react';
1+
import React, { FC, useCallback, useMemo, useState } from 'react';
22
import { Form } from '@rjsf/mui';
33
import validator from '@rjsf/validator-ajv8';
44
import styled from '@mui/system/styled';
5-
import * as msgpack from '@msgpack/msgpack';
65
import { InputProps } from '../types';
76
import { protobufValueToPrimitive, PrimitiveType } from '../inputHelpers/struct';
87
import { StyledCard } from './StyledCard';

packages/oss-console/src/components/Launch/LaunchForm/inputHelpers/struct.ts

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import Protobuf from '@clients/common/flyteidl/protobuf';
22
import Core from '@clients/common/flyteidl/core';
3-
import * as msgpack from '@msgpack/msgpack';
43
import { InputType, InputValue } from '../types';
54
import { structPath } from './constants';
65
import { ConverterInput, InputHelper, InputValidatorParams } from './types';
76
import { extractLiteralWithCheck, formatParameterValues } from './utils';
87

98
export type PrimitiveType = string | number | boolean | null | object;
109

11-
function asValueWithKind(value: Protobuf.IValue): Protobuf.Value {
10+
export function asValueWithKind(value: Protobuf.IValue): Protobuf.Value {
1211
return value instanceof Protobuf.Value ? value : Protobuf.Value.create(value);
1312
}
1413

@@ -91,25 +90,9 @@ function objectToProtobufStruct(obj: Dictionary<any>): Protobuf.IStruct {
9190
return { fields };
9291
}
9392

94-
function parseBinary(binary: Core.IBinary): string {
95-
if (!binary.value) {
96-
throw new Error('Binary value is empty');
97-
}
98-
99-
if (binary.tag === 'msgpack') {
100-
return JSON.stringify(msgpack.decode(binary.value));
101-
}
102-
103-
// unsupported binary type, it might be temporary
104-
return '';
105-
}
106-
10793
function fromLiteral(literal: Core.ILiteral): InputValue {
108-
if (literal.scalar?.binary) {
109-
return parseBinary(literal.scalar.binary);
110-
}
111-
11294
const structValue = extractLiteralWithCheck<Protobuf.IStruct>(literal, structPath);
95+
11396
const finalValue = formatParameterValues(InputType.Struct, protobufStructToObject(structValue));
11497
return finalValue;
11598
}

0 commit comments

Comments
 (0)