Skip to content

Commit 8f426c2

Browse files
fix: handling of url/base64 query parameters (#531)
1 parent a70b60e commit 8f426c2

File tree

6 files changed

+76
-34
lines changed

6 files changed

+76
-34
lines changed

src/components/Editor/MonacoWrapper.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export const MonacoWrapper: FunctionComponent<MonacoEditorProps> = ({
1717

1818
const onChange = useMemo(() => {
1919
return debounce((v: string) => {
20-
editorSvc.updateState({ content: v });
20+
editorSvc.updateState({ content: v, file: { from: 'storage', source: undefined } });
2121
autoSaving && editorSvc.saveToLocalStorage(v, false);
2222
parserSvc.parse('asyncapi', v);
2323
}, savingDelay);

src/services/app.service.ts

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,27 @@ import { show } from '@ebay/nice-modal-react';
44

55
import { RedirectedModal } from '../components/Modals';
66

7-
import { appState } from '../state';
7+
import { appState, filesState } from '../state';
88

99
export class ApplicationService extends AbstractService {
10-
public override onInit(): void {
10+
override async onInit() {
1111
// subscribe to state to hide preloader
1212
this.hidePreloader();
1313

1414
const { readOnly, url, base64, redirectedFrom } = this.svcs.navigationSvc.getUrlParameters();
1515

1616
// readOnly state should be only set to true when someone pass also url or base64 parameter
1717
const isStrictReadonly = Boolean(readOnly && (url || base64));
18-
if (isStrictReadonly) {
18+
19+
let error: any;
20+
try {
21+
await this.fetchResource(url, base64);
22+
} catch (err) {
23+
error = err;
24+
console.error(err);
25+
}
26+
27+
if (isStrictReadonly && !error) {
1928
appState.setState({
2029
readOnly,
2130
initialized: true,
@@ -28,6 +37,30 @@ export class ApplicationService extends AbstractService {
2837
}
2938
}
3039

40+
private async fetchResource(url: string | null, base64: string | null) {
41+
if (!url && !base64) {
42+
return;
43+
}
44+
45+
const { updateFile } = filesState.getState();
46+
let content = '';
47+
if (url) {
48+
content = await fetch(url).then(res => res.text());
49+
} else if (base64) {
50+
content = this.svcs.formatSvc.decodeBase64(base64);
51+
}
52+
53+
const language = this.svcs.formatSvc.retrieveLangauge(content);
54+
const source = url || undefined;
55+
updateFile('asyncapi', {
56+
content,
57+
language,
58+
source,
59+
from: url ? 'url' : 'base64',
60+
});
61+
await this.svcs.parserSvc.parse('asyncapi', content, { source });
62+
}
63+
3164
private hidePreloader() {
3265
const unsunscribe = appState.subscribe((state, prevState) => {
3366
if (!prevState.initialized && state.initialized) {

src/services/editor.service.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export interface UpdateState {
2121
}
2222

2323
export class EditorService extends AbstractService {
24+
private created = false;
2425
private decorations: Map<string, string[]> = new Map();
2526
private instance: monacoAPI.editor.IStandaloneCodeEditor | undefined;
2627

@@ -29,9 +30,19 @@ export class EditorService extends AbstractService {
2930
}
3031

3132
async onDidCreate(editor: monacoAPI.editor.IStandaloneCodeEditor) {
33+
if (this.created) {
34+
return;
35+
}
36+
this.created = true;
3237
this.instance = editor;
33-
// parse on first run the spec
34-
await this.svcs.parserSvc.parse('asyncapi', editor.getValue());
38+
39+
// parse on first run - only when document is undefined
40+
const document = documentsState.getState().documents.asyncapi;
41+
if (!document) {
42+
await this.svcs.parserSvc.parse('asyncapi', editor.getValue());
43+
} else {
44+
this.applyMarkersAndDecorations(document.diagnostics.filtered);
45+
}
3546

3647
// apply save command
3748
editor.addCommand(

src/services/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,13 @@ export const ServicesProvider = servicesCtx.Provider;
3737
export async function createServices() {
3838
const services: Services = {} as Services;
3939

40+
services.parserSvc = new ParserService(services);
4041
services.appSvc = new ApplicationService(services);
4142
services.converterSvc = new ConverterService(services);
4243
services.editorSvc = new EditorService(services);
4344
services.formatSvc = new FormatService(services);
4445
services.monacoSvc = new MonacoService(services);
4546
services.navigationSvc = new NavigationService(services);
46-
services.parserSvc = new ParserService(services);
4747
services.serverAPISvc = new ServerAPIService(services);
4848
services.settingsSvc = new SettingsService(services);
4949
services.socketClientSvc = new SocketClient(services);

src/services/parser.service.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,13 @@ export class ParserService extends AbstractService {
9999
private updateDocument = documentsState.getState().updateDocument;
100100

101101
private createDiagnostics(diagnostics: Diagnostic[]) {
102+
// map messages of invalid ref to file
103+
diagnostics.forEach(diagnostic => {
104+
if (diagnostic.code === 'invalid-ref' && diagnostic.message.endsWith('readFile is not a function')) {
105+
diagnostic.message = 'File references are not yet supported in Studio';
106+
}
107+
});
108+
102109
const collections: DocumentDiagnostics = {
103110
original: diagnostics,
104111
filtered: [],

src/state/files.state.ts

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import create from 'zustand';
2-
import { persist } from 'zustand/middleware';
32

43
const schema =
54
localStorage.getItem('document') || `asyncapi: '2.5.0'
@@ -176,32 +175,24 @@ export type FilesActions = {
176175
updateFile: (uri: string, file: Partial<File>) => void;
177176
}
178177

179-
export const filesState = create(
180-
persist<FilesState & FilesActions>(set =>
181-
({
182-
files: {
183-
asyncapi: {
184-
uri: 'asyncapi',
185-
name: 'asyncapi',
186-
content: schema,
187-
from: 'storage',
188-
source: undefined,
189-
language: schema.trimStart()[0] === '{' ? 'json' : 'yaml',
190-
modified: false,
191-
stat: {
192-
mtime: (new Date()).getTime(),
193-
}
194-
}
195-
},
196-
updateFile(uri: string, file: Partial<File>) {
197-
set(state => ({ files: { ...state.files, [String(uri)]: { ...state.files[String(uri)] || {}, ...file } } }));
198-
},
199-
}),
200-
{
201-
name: 'studio-files',
202-
getStorage: () => localStorage,
178+
export const filesState = create<FilesState & FilesActions>(set => ({
179+
files: {
180+
asyncapi: {
181+
uri: 'asyncapi',
182+
name: 'asyncapi',
183+
content: schema,
184+
from: 'storage',
185+
source: undefined,
186+
language: schema.trimStart()[0] === '{' ? 'json' : 'yaml',
187+
modified: false,
188+
stat: {
189+
mtime: (new Date()).getTime(),
190+
}
191+
}
192+
},
193+
updateFile(uri: string, file: Partial<File>) {
194+
set(state => ({ files: { ...state.files, [String(uri)]: { ...state.files[String(uri)] || {}, ...file } } }));
203195
}
204-
),
205-
);
196+
}));
206197

207198
export const useFilesState = filesState;

0 commit comments

Comments
 (0)