import React from "react"; import { observable, makeObservable } from "mobx"; import { validators } from "eez-studio-shared/validation"; import { showGenericDialog } from "eez-studio-ui/generic-dialog"; import { ClassInfo, registerClass, IEezObject, EezObject, PropertyType, MessageType, IMessage } from "project-editor/core/object"; import { createObject, getChildOfObject, getProjectStore, Message, propertyInvalidValueMessage, propertyNotSetMessage, propertyNotUniqueMessage } from "project-editor/store"; import { ProjectContext } from "project-editor/project/context"; import { ListNavigation } from "project-editor/ui-components/ListNavigation"; import { fileExistsSync } from "eez-studio-shared/util-electron"; import type { ProjectEditorFeature } from "project-editor/store/features"; import { isNotScpiProject } from "project-editor/project/project-type-traits"; //////////////////////////////////////////////////////////////////////////////// export class ExtensionDefinitionsTab extends React.Component { static contextType = ProjectContext; declare context: React.ContextType; render() { return ( ); } } //////////////////////////////////////////////////////////////////////////////// export class UseDashboardProject extends EezObject { projectFilePath: string; static classInfo: ClassInfo = { properties: [ { name: "projectFilePath", type: PropertyType.RelativeFile, fileFilters: [ { name: "EEZ Project", extensions: ["eez-project"] }, { name: "All Files", extensions: ["*"] } ], isOptional: false } ], defaultValue: {}, check: (object: UseDashboardProject, messages: IMessage[]) => { if (object.projectFilePath) { if ( !fileExistsSync( getProjectStore(object).getAbsoluteFilePath( object.projectFilePath ) ) ) { messages.push( new Message( MessageType.ERROR, "File doesn't exists", getChildOfObject(object, "projectFilePath") ) ); } } else { messages.push(propertyNotSetMessage(object, "projectFilePath")); } } }; override makeEditable() { super.makeEditable(); makeObservable(this, { projectFilePath: observable }); } } registerClass("UseDashboardProject", UseDashboardProject); //////////////////////////////////////////////////////////////////////////////// export class ExtensionDefinition extends EezObject { name: string; description: string; doNotBuild: boolean; buildConfiguration: string; buildFolder: string; image: string; extensionName: string; idn: string; properties: string; idfName: string; idfShortName: string; idfFirmwareVersion: string; idfGuid: string; idfRevisionNumber: string; idfDescription: string; idfSupportedModels: string; idfRevisionComments: string; idfAuthor: string; sdlFriendlyName: string; useDashboardProjects: UseDashboardProject[]; static classInfo: ClassInfo = { listLabel: (extensionDefinition: ExtensionDefinition) => { return ( extensionDefinition.name + (extensionDefinition.doNotBuild ? " (build disabled)" : "") ); }, properties: [ { name: "name", type: PropertyType.String, unique: true }, { name: "description", type: PropertyType.MultilineText, defaultValue: undefined }, { name: "doNotBuild", type: PropertyType.Boolean, defaultValue: false }, { name: "buildConfiguration", type: PropertyType.ObjectReference, referencedObjectCollectionPath: "settings/build/configurations", defaultValue: undefined }, { name: "buildFolder", type: PropertyType.String, defaultValue: undefined }, { name: "extensionName", displayName: "IEXT name", type: PropertyType.String, defaultValue: undefined }, { name: "image", type: PropertyType.Image, defaultValue: undefined }, { name: "idn", displayName: "IDN", type: PropertyType.String, defaultValue: undefined, disabled: isNotScpiProject }, { name: "properties", type: PropertyType.JSON, defaultValue: undefined }, { name: "idfName", displayName: "IDF name", type: PropertyType.String, disabled: isNotScpiProject }, { name: "idfShortName", displayName: "IDF short name", type: PropertyType.String, defaultValue: undefined, disabled: isNotScpiProject }, { name: "idfFirmwareVersion", displayName: "IDF firmware version", type: PropertyType.String, defaultValue: undefined, disabled: isNotScpiProject }, { name: "idfGuid", displayName: object => isNotScpiProject(object) ? "GUID" : "IDF GUID", type: PropertyType.GUID }, { name: "idfRevisionNumber", displayName: object => isNotScpiProject(object) ? "Extension version" : "IDF revision number (extension version)", type: PropertyType.String, defaultValue: undefined }, { name: "idfDescription", displayName: object => isNotScpiProject(object) ? "Description" : "IDF description", type: PropertyType.String, defaultValue: undefined }, { name: "idfSupportedModels", displayName: "IDF supported models", type: PropertyType.String, defaultValue: undefined, disabled: isNotScpiProject }, { name: "idfRevisionComments", displayName: "IDF revision comments", type: PropertyType.String, defaultValue: undefined, disabled: isNotScpiProject }, { name: "idfAuthor", displayName: object => isNotScpiProject(object) ? "Author" : "IDF author", type: PropertyType.String, defaultValue: undefined }, { name: "sdlFriendlyName", displayName: "SDL friendly name", type: PropertyType.String, defaultValue: undefined, disabled: isNotScpiProject }, { name: "useDashboardProjects", displayName: "Dashboard projects", type: PropertyType.Array, typeClass: UseDashboardProject, defaultValue: [] } ], newItem: async (parent: IEezObject) => { const result = await showGenericDialog({ dialogDefinition: { title: "New Instrument Definition File", fields: [ { name: "name", type: "string", validators: [ validators.required, validators.unique({}, parent) ] } ] }, values: {}, modal: true, backdrop: "static" }); const projectStore = getProjectStore(parent); const extensionDefinitionProperties: Partial = { name: result.values.name }; const extensionDefinition = createObject( projectStore, extensionDefinitionProperties, ExtensionDefinition ); return extensionDefinition; }, hideInProperties: true, icon: "material:extension", check: (object: ExtensionDefinition, messages: IMessage[]) => { const projectStore = getProjectStore(object); if (!object.extensionName) { messages.push(propertyNotSetMessage(object, "extensionName")); } if (projectStore.isScpiInstrument && !object.idn) { messages.push(propertyNotSetMessage(object, "idn")); } if (!object.idfGuid) { messages.push(propertyNotSetMessage(object, "idfGuid")); } if (!object.idfRevisionNumber) { messages.push( propertyNotSetMessage(object, "idfRevisionNumber") ); } if (projectStore.isScpiInstrument && !object.idfName) { messages.push(propertyNotSetMessage(object, "idfName")); } if (projectStore.isScpiInstrument && !object.idfShortName) { messages.push(propertyNotSetMessage(object, "idfShortName")); } let extensionDefinitions = projectStore.project.extensionDefinitions; if ( extensionDefinitions.find( extensionDefinition => extensionDefinition !== object && extensionDefinition.idfGuid === object.idfGuid ) ) { messages.push(propertyNotUniqueMessage(object, "idfGuid")); } if (object.properties) { try { JSON.parse(object.properties); } catch (err) { messages.push( propertyInvalidValueMessage(object, "properties") ); } } } }; override makeEditable() { super.makeEditable(); makeObservable(this, { name: observable, description: observable, doNotBuild: observable, buildConfiguration: observable, buildFolder: observable, image: observable, extensionName: observable, idn: observable, properties: observable, idfName: observable, idfShortName: observable, idfFirmwareVersion: observable, idfGuid: observable, idfRevisionNumber: observable, idfDescription: observable, idfSupportedModels: observable, idfRevisionComments: observable, idfAuthor: observable, sdlFriendlyName: observable, useDashboardProjects: observable }); } } registerClass("ExtensionDefinition", ExtensionDefinition); //////////////////////////////////////////////////////////////////////////////// const feature: ProjectEditorFeature = { name: "eezstudio-project-feature-extension-definitions", version: "0.1.0", description: "This feature adds support for IEXT definitions into your project", author: "EEZ", authorLogo: "../eez-studio-ui/_images/eez_logo.png", displayName: "IEXT defs", mandatory: false, key: "extensionDefinitions", type: PropertyType.Array, typeClass: ExtensionDefinition, icon: "material:extension", create: () => { return []; } }; export default feature;