Skip to content

Commit

Permalink
feat: add spec 3.0 validation support (#747)
Browse files Browse the repository at this point in the history
  • Loading branch information
Amzani authored Aug 9, 2023
1 parent 1476812 commit 94215e6
Show file tree
Hide file tree
Showing 13 changed files with 1,815 additions and 2,618 deletions.
5 changes: 5 additions & 0 deletions .changeset/selfish-ducks-hear.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@asyncapi/studio": minor
---

Support spec V3.0.0 in studio
4 changes: 2 additions & 2 deletions apps/studio/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@
"@asyncapi/avro-schema-parser": "^3.0.2",
"@asyncapi/converter": "^1.3.1",
"@asyncapi/openapi-schema-parser": "^3.0.4",
"@asyncapi/parser": "^2.0.3",
"@asyncapi/parser": "^2.1.0-next-major-spec.3",
"@asyncapi/react-component": "^1.0.0-next.48",
"@asyncapi/specs": "^4.2.1",
"@asyncapi/specs": "^6.0.0-next-major-spec.6",
"@ebay/nice-modal-react": "^1.2.10",
"@headlessui/react": "^1.7.4",
"@hookstate/core": "^4.0.0-rc21",
Expand Down
8 changes: 5 additions & 3 deletions apps/studio/src/components/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@ import { Template } from './Template';
import { VisualiserTemplate } from './Visualiser';

import { debounce } from '../helpers';
import { usePanelsState } from '../state';
import { usePanelsState, useDocumentsState, useSettingsState } from '../state';

import type { FunctionComponent } from 'react';

interface ContentProps {}

export const Content: FunctionComponent<ContentProps> = () => { // eslint-disable-line sonarjs/cognitive-complexity
const { show, secondaryPanelType } = usePanelsState();

const navigationEnabled = show.primarySidebar;
const document = useDocumentsState(state => state.documents['asyncapi']?.document) || null;
const v3Enabled = useSettingsState(state => state.editor.v3support) || false;
const isV3 = document?.version() === '3.0.0' && v3Enabled;
const navigationEnabled = isV3 ? false : show.primarySidebar;
const editorEnabled = show.primaryPanel;
const viewEnabled = show.secondaryPanel;
const viewType = secondaryPanelType;
Expand Down
20 changes: 18 additions & 2 deletions apps/studio/src/components/Modals/Settings/SettingsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,14 @@ export const SettingsModal = create<SettingsModalProps>(({ activeTab = 'editor'
const [governanceHints, setGovernanceHints] = useState(settings.governance.show.hints);
const [autoRendering, setAutoRendering] = useState(settings.templates.autoRendering);
const [confirmDisabled, setConfirmDisabled] = useState(true);
const [v3support, setV3support] = useState(settings.editor.v3support);

const createNewState = (): SettingsState => {
return {
editor: {
autoSaving,
savingDelay,
v3support
},
governance: {
show: {
Expand All @@ -86,7 +88,7 @@ export const SettingsModal = create<SettingsModalProps>(({ activeTab = 'editor'
const newState = createNewState();
const isThisSameObjects = settingsSvc.isEqual(newState);
setConfirmDisabled(isThisSameObjects);
}, [autoSaving, savingDelay, autoRendering, governanceWarnings, governanceInformations, governanceHints]);
}, [autoSaving, savingDelay, autoRendering, governanceWarnings, governanceInformations, governanceHints, v3support]);

const onCancel = useCallback(() => {
modal.hide();
Expand Down Expand Up @@ -129,7 +131,21 @@ export const SettingsModal = create<SettingsModalProps>(({ activeTab = 'editor'
Save automatically after each change in the document or manually.
</div>
</div>
<div className={`flex flex-col mt-4 text-sm pl-8 ${autoSaving ? 'opacity-1' : 'opacity-25'}`}>
<div className="flex flex-col mt-4 text-sm">
<div className="flex flex-row content-center justify-between">
<label
htmlFor="settings-auto-saving"
className="flex justify-right items-center w-1/2 content-center font-medium text-gray-700"
>
Enable v3 support
</label>
<Switch
toggle={v3support}
onChange={(v) => setV3support(v)}
/>
</div>
</div>
<div className="flex flex-col mt-4 text-sm">
<div className="flex flex-row content-center justify-between">
<label
htmlFor="settings-template-delay"
Expand Down
16 changes: 14 additions & 2 deletions apps/studio/src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { show as showModal } from '@ebay/nice-modal-react';
import { Tooltip } from './common';
import { SettingsModal, NewFileModal } from './Modals';

import { usePanelsState, panelsState } from '../state';
import { usePanelsState, panelsState, useDocumentsState, useSettingsState } from '../state';

import type { FunctionComponent, ReactNode } from 'react';
import type { PanelsState } from '../state/panels.state';
Expand Down Expand Up @@ -45,17 +45,22 @@ interface NavItem {
onClick: () => void;
icon: ReactNode;
tooltip: ReactNode;
enabled: boolean;
}

interface SidebarProps {}

export const Sidebar: FunctionComponent<SidebarProps> = () => {
const { show, secondaryPanelType } = usePanelsState();
const document = useDocumentsState(state => state.documents['asyncapi']?.document) || null;
const v3Enabled = useSettingsState(state => state.editor.v3support) || false;
const isV3 = document?.version() === '3.0.0' && v3Enabled;

if (show.activityBar === false) {
return null;
}

const navigation: NavItem[] = [
let navigation: NavItem[] = [
// navigation
{
name: 'primarySidebar',
Expand All @@ -64,6 +69,7 @@ export const Sidebar: FunctionComponent<SidebarProps> = () => {
onClick: () => updateState('primarySidebar'),
icon: <VscListSelection className="w-5 h-5" />,
tooltip: 'Navigation',
enabled: !isV3
},
// editor
{
Expand All @@ -73,6 +79,7 @@ export const Sidebar: FunctionComponent<SidebarProps> = () => {
onClick: () => updateState('primaryPanel'),
icon: <VscCode className="w-5 h-5" />,
tooltip: 'Editor',
enabled: true
},
// template
{
Expand All @@ -82,6 +89,7 @@ export const Sidebar: FunctionComponent<SidebarProps> = () => {
onClick: () => updateState('secondaryPanel', 'template'),
icon: <VscOpenPreview className="w-5 h-5" />,
tooltip: 'HTML preview',
enabled: !isV3
},
// visuliser
{
Expand All @@ -91,6 +99,7 @@ export const Sidebar: FunctionComponent<SidebarProps> = () => {
onClick: () => updateState('secondaryPanel', 'visualiser'),
icon: <VscGraph className="w-5 h-5" />,
tooltip: 'Blocks visualiser',
enabled: !isV3
},
// newFile
{
Expand All @@ -100,9 +109,12 @@ export const Sidebar: FunctionComponent<SidebarProps> = () => {
onClick: () => showModal(NewFileModal),
icon: <VscNewFile className="w-5 h-5" />,
tooltip: 'New file',
enabled: true
},
];

navigation = navigation.filter(item => item.enabled);

return (
<div className="flex flex-col bg-gray-800 shadow-lg border-r border-gray-700 justify-between">
<div className="flex flex-col">
Expand Down
8 changes: 8 additions & 0 deletions apps/studio/src/components/Template/HTMLWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ export const HTMLWrapper: React.FunctionComponent<HTMLWrapperProps> = () => {
);
}

if (document?.version() === '3.0.0') {
return (
<div className="flex flex-1 overflow-hidden h-full justify-center items-center text-2xl mx-auto px-6 text-center">
<p>Documentation preview is not supported yet for v3.0.0 specifications.</p>
</div>
);
}

return (
parsedSpec && (
<div className="flex flex-1 flex-col h-full overflow-hidden">
Expand Down
7 changes: 5 additions & 2 deletions apps/studio/src/components/Terminal/TerminalTabs.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useState } from 'react';

import { TerminalInfo } from './TerminalInfo';
import { otherState } from '../../state';
import { otherState, useSettingsState, useDocumentsState } from '../../state';

export interface TerminalTab {
name: string;
Expand All @@ -19,6 +19,9 @@ export const TerminalTabs: React.FunctionComponent<TerminalTabsProps> = ({
active = 0,
}) => {
const [activeTab, setActiveTab] = useState(active);
const document = useDocumentsState(state => state.documents['asyncapi']?.document) || null;
const v3Enabled = useSettingsState(state => state.editor.v3support) || false;
const isV3 = document?.version() === '3.0.0' && v3Enabled;
if (tabs.length === 0) {
return null;
}
Expand Down Expand Up @@ -55,7 +58,7 @@ export const TerminalTabs: React.FunctionComponent<TerminalTabsProps> = ({
}}
>
<ul className="flex flex-row">
{tabs.map(tab => (
{!isV3 && tabs.map(tab => (
<li
key={tab.name}
className="px-2 cursor-pointer"
Expand Down
3 changes: 2 additions & 1 deletion apps/studio/src/services/parser.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ export class ParserService extends AbstractService {
try {
const { document, diagnostics: _diagnostics, extras } = await this.parser.parse(spec, options);
diagnostics = _diagnostics;

if (document) {
// This is needed as we are still using the old Parser API
// @todo: migrate to Parser API v2
const oldDocument = convertToOldAPI(document);
this.updateDocument(uri, {
uri,
Expand Down
24 changes: 18 additions & 6 deletions apps/studio/src/services/specification.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,30 @@ import { show } from '@ebay/nice-modal-react';

import { ConvertToLatestModal } from '../components/Modals';

import { documentsState } from '../state';
import { documentsState, settingsState } from '../state';

import type { SpecVersions } from '../types';

export class SpecificationService extends AbstractService {
private keySessionStorage = 'informed-about-latest';
override onInit() {
this.subcribeToDocuments();
this.subscribeToSettings();
}

get specs() {
return specs;
return specs.schemas;
}

get latestVersion(): SpecVersions {
return Object.keys(specs).pop() as SpecVersions;
const { editor: { v3support } } = settingsState.getState();
return v3support ?
Object.keys(this.specs).pop() as SpecVersions :
Object.keys(this.specs).at(-2) as SpecVersions;
}

getSpec(version: SpecVersions) {
return specs[String(version) as SpecVersions];
return this.specs[String(version) as SpecVersions];
}

private subcribeToDocuments() {
Expand All @@ -42,14 +47,21 @@ export class SpecificationService extends AbstractService {
});
}

private subscribeToSettings() {
settingsState.subscribe((state, prevState) => {
if (state.editor.v3support === prevState.editor.v3support) return;
sessionStorage.removeItem(this.keySessionStorage);
});
}

private tryInformAboutLatestVersion(
version: string,
): boolean {
const oneDay = 24 * 60 * 60 * 1000; /* ms */

const nowDate = new Date();
let dateOfLastQuestion = nowDate;
const localStorageItem = sessionStorage.getItem('informed-about-latest');
const localStorageItem = sessionStorage.getItem(this.keySessionStorage);
if (localStorageItem) {
dateOfLastQuestion = new Date(localStorageItem);
}
Expand All @@ -58,7 +70,7 @@ export class SpecificationService extends AbstractService {
nowDate === dateOfLastQuestion ||
nowDate.getTime() - dateOfLastQuestion.getTime() > oneDay;
if (isOvertime && version !== this.latestVersion) {
sessionStorage.setItem('informed-about-latest', nowDate.toString());
sessionStorage.setItem(this.keySessionStorage, nowDate.toString());
return true;
}

Expand Down
2 changes: 2 additions & 0 deletions apps/studio/src/state/settings.state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export type SettingsState = {
editor: {
autoSaving: boolean;
savingDelay: number;
v3support: boolean;
};
governance: {
show: {
Expand All @@ -24,6 +25,7 @@ export const settingsState = create(
editor: {
autoSaving: true,
savingDelay: 625,
v3support: false,
},
governance: {
show: {
Expand Down
2 changes: 1 addition & 1 deletion apps/studio/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import type specs from '@asyncapi/specs';

export type SpecVersions = keyof typeof specs;
export type SpecVersions = keyof typeof specs.schemas;
Loading

0 comments on commit 94215e6

Please sign in to comment.