Skip to content

Commit

Permalink
Fixed many bugs. Policy and connection creation disabled. Parent and …
Browse files Browse the repository at this point in the history
…child type management added.
  • Loading branch information
juliarobles committed Feb 21, 2024
1 parent e41b6d5 commit f909d03
Show file tree
Hide file tree
Showing 27 changed files with 650 additions and 161 deletions.
2 changes: 1 addition & 1 deletion .config/webpack/webpack.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const config = async (env): Promise<Configuration> => {

context: path.join(process.cwd(), SOURCE_DIR),

devtool: env.production ? 'source-map' : 'eval-source-map',
devtool: env.production ? false : 'eval-source-map', // previously it was not false, it was source-map

entry: await getEntries(),

Expand Down
4 changes: 2 additions & 2 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ version: '3.0'

services:
grafana:
container_name: 'ertis-digitaltwin-app'
container_name: 'ertis-opentwins'
platform: "linux/amd64"
build:
context: ./.config
Expand All @@ -12,5 +12,5 @@ services:
ports:
- 3000:3000/tcp
volumes:
- ./dist:/var/lib/grafana/plugins/ertis-digitaltwin-app
- ./dist:/var/lib/grafana/plugins/ertis-opentwins
- ./provisioning:/etc/grafana/provisioning
25 changes: 21 additions & 4 deletions src/components/auxiliary/dittoThing/form/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ interface Parameters {
isType: boolean
meta: AppPluginMeta<KeyValue<any>>
funcFromType?: any
funcFromZero: any
funcFromZero: (thingId: string, data: IDittoThingData, num?: number) => Promise<any>
}

export const ThingForm = ({ path, parentId, thingToEdit, isType, funcFromType, funcFromZero }: Parameters) => {
Expand All @@ -40,6 +40,8 @@ export const ThingForm = ({ path, parentId, thingToEdit, isType, funcFromType, f
const [selectedPolicy, setSelectedPolicy] = useState<SelectableValue<string>>()
const [showNotification, setShowNotification] = useState<INotification>({state: enumNotification.HIDE, title: ""})
const [staticAttributes, setStaticAttributes] = useState<any>([])
const [numChildren, setNumChildren] = useState<number>(1)


const context = useContext(StaticContext)

Expand All @@ -48,7 +50,8 @@ export const ThingForm = ({ path, parentId, thingToEdit, isType, funcFromType, f
const descriptionID = "Identity associated with the authentication credentials"
const descriptionInformation = "Basic information for creating the Ditto thing"
const descriptionThingId = `Thing ID. This must be unique within the scope of the ${title}. The name of the ${title} will precede it automatically.`
const descriptionNamespace = "AA"
const descriptionNamespace = `Name of the context to which the ${title} belongs.`
const descriptionChildren = "Number of children of this type owned by parent"


// -----------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -118,7 +121,8 @@ export const ThingForm = ({ path, parentId, thingToEdit, isType, funcFromType, f
attributes: {
...basicAttributes,
...currentThing.attributes
}
},
features: thing.features
})
setThingIdField(splitThingId(thing.thingId))

Expand Down Expand Up @@ -174,6 +178,8 @@ export const ThingForm = ({ path, parentId, thingToEdit, isType, funcFromType, f
} else {
funcToExecute = funcFromType(thingId, type.value.thingId)
}
} else if(isType) {
funcToExecute = funcFromZero(thingId, finalData, numChildren)
} else {
funcToExecute = funcFromZero(thingId, finalData)
}
Expand All @@ -200,6 +206,10 @@ export const ThingForm = ({ path, parentId, thingToEdit, isType, funcFromType, f
})
}

const handleOnChangeNumChildren = (event: ChangeEvent<HTMLInputElement>) => {
setNumChildren(Number(event.target.value))
}

const handleOnChangeFrom = (value: number) => {
setSelected(value)
const aux = currentThing
Expand Down Expand Up @@ -324,7 +334,7 @@ export const ThingForm = ({ path, parentId, thingToEdit, isType, funcFromType, f
<h2 style={{marginBottom: '0px', paddingBottom: '0px'}}>Edit {title} with id {thingToEdit.thingId}</h2>
: <h2 style={{marginBottom: '0px', paddingBottom: '0px'}}>Create new {title}</h2>

const headerIfIsChild = (parentId !== null) ?
const headerIfIsChild = (parentId !== null && parentId !== undefined) ?
<h4 style={{color:useTheme2().colors.text.secondary}}>To be child of {title} with id: {parentId}</h4>
: <div style={{height: '0px'}}></div>

Expand Down Expand Up @@ -369,6 +379,12 @@ export const ThingForm = ({ path, parentId, thingToEdit, isType, funcFromType, f
)
}

const numChildrenInput = (parentId !== null && parentId !== undefined && isType) ?
<Field label="Number of children" description={descriptionChildren} required={true} className="mt-4">
<Input type="number" value={numChildren} onChange={handleOnChangeNumChildren}/>
</Field>
: <div></div>

return (
<Fragment>
<CustomNotification notification={showNotification} setNotificationFunc={setShowNotification}/>
Expand All @@ -380,6 +396,7 @@ export const ThingForm = ({ path, parentId, thingToEdit, isType, funcFromType, f
{({register, errors, control}: FormAPI<IDittoThingForm>) => {
return(
<Fragment>
{numChildrenInput}
<ElementHeader className="mt-5" title="Identification" description={descriptionID} isLegend={true}/>

<Field label="Namespace" description={descriptionNamespace} required={!thingToEdit} disabled={thingToEdit !== undefined}>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { ConfirmModal, IconButton, Modal, Spinner, VerticalGroup } from "@grafana/ui"
import React, { useState, useContext } from "react"
import { enumNotification } from "utils/auxFunctions/general"
import { StaticContext } from "utils/context/staticContext"

interface Parameters {
path: string
thingId: string
isType: boolean
funcDelete: any
funcDeleteChildren?: any
}

export const ButtonsInfo = ({ path, thingId, isType, funcDelete, funcDeleteChildren }: Parameters) => {
const title = (isType) ? "type" : "twin"
const messageDelete = `Delete ${title}`
const descriptionDelete = `Are you sure you want to remove the ${title} with id `
const descriptionDeleteChildren = "Choose if you want to remove the twin alone, unlinking its children, or remove the twin and all its children."
const messageSuccess = `The ${title} has been deleted correctly.`
const messageError = `The ${title} has not been deleted correctly.`
const descriptionError = "Refresh the page or check for errors."

const context = useContext(StaticContext)

const [showDeleteModal, setShowDeleteModal] = useState<string>()
const [showNotification, setShowNotification] = useState<string>(enumNotification.HIDE)

const hideNotification = (success: boolean) => {
setShowDeleteModal(undefined)
setShowNotification(enumNotification.HIDE)
if (success) {
window.location.replace(path + "?tab=" + title + "s")
}
}

const deleteThing = (funcToExecute: any, context: any, thingId: string) => {
setShowDeleteModal(undefined)
setShowNotification(enumNotification.LOADING)
try {
funcToExecute(context, thingId).then(() => {
console.log("OK")
setShowNotification(enumNotification.SUCCESS)
}).catch(() => {
console.log("error")
setShowNotification(enumNotification.ERROR)
})
} catch (e) {
console.log("error")
setShowNotification(enumNotification.ERROR)
}

}

const notification = () => {
if (showDeleteModal !== undefined) {
const thingId = showDeleteModal
if (!isType && funcDeleteChildren !== undefined) {
return <ConfirmModal isOpen={true} title={messageDelete} body={descriptionDelete + `${thingId}?`} description={descriptionDeleteChildren} confirmationText={thingId} confirmText={"With children"} alternativeText={"Without children"} dismissText={"Cancel"} onAlternative={() => deleteThing(funcDelete, context, thingId)} onDismiss={() => hideNotification(false)} onConfirm={() => deleteThing(funcDeleteChildren, context, thingId)} />
} else {
return <ConfirmModal isOpen={true} title={messageDelete} body={descriptionDelete + `${thingId}?`} confirmText={"Delete"} onConfirm={() => deleteThing(funcDelete, context, thingId)} onDismiss={() => hideNotification(false)} />
}
}
switch (showNotification) {
case enumNotification.SUCCESS:
return <Modal title={messageSuccess} icon='check' isOpen={true} onDismiss={() => hideNotification(true)} />
case enumNotification.ERROR:
return <Modal title={messageError} icon='exclamation-triangle' isOpen={true} onDismiss={() => hideNotification(false)}>{descriptionError}</Modal>
case enumNotification.LOADING:
return (
<VerticalGroup align="center">
<h4 className="mb-0 mt-4">Loading...</h4>
<Spinner size={30} />
</VerticalGroup>
)
default:
return <div></div>
}
}

const handleOnDelete = (e: any, thingId: string) => {
e.preventDefault()
setShowDeleteModal(thingId)
}

return <div>
{notification()}
<div style={{ display: "flex", width: "100%", justifyContent: "center"}} className="m-2">
<a href={path + '&mode=edit&element=' + title + '&id=' + thingId} style={{ all: 'unset', marginRight: "10px"}} >
<IconButton key="edit" name="pen" tooltip="Edit" />
</a>
<IconButton key="delete" name="trash-alt" tooltip="Delete" onClick={(e) => handleOnDelete(e, thingId)} />
</div>
</div>
}
52 changes: 26 additions & 26 deletions src/components/auxiliary/dittoThing/list/info.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react'
import { AppPluginMeta, KeyValue } from '@grafana/data'
import { IDittoThing } from 'utils/interfaces/dittoThing'
import { capitalize, defaultIfNoExist } from 'utils/auxFunctions/general'
import { capitalize, defaultIfNoExist} from 'utils/auxFunctions/general'
import { basicAttributesConst } from 'utils/data/consts'

interface Parameters {
Expand All @@ -11,60 +11,60 @@ interface Parameters {
isType: boolean
}

export function InformationThing ({path, thingInfo, meta, isType}: Parameters) {
export function InformationThing({ path, thingInfo, meta, isType }: Parameters) {

const tab = '\u00A0\u00A0\u00A0'

const arrayToJSXElement = (array: any, str="", isCapitalize=true) => {
const arrayToJSXElement = (array: any, str = "", isCapitalize = true) => {
return array.map((item: any, index: number) => {
if (Array.isArray(item)){
if (Array.isArray(item)) {
return arrayToJSXElement(item, str, isCapitalize)
} else if(item.constructor === String || item.constructor === Number || item.constructor === Boolean) {
const className = (index !== array.length-1) ? "mb-0" : ""
} else if (item.constructor === String || item.constructor === Number || item.constructor === Boolean) {
const className = (index !== array.length - 1) ? "mb-0" : ""
return <p className={className}>{str + item}</p>
} else {
return objectToJSXElement(item, str, isCapitalize)
}
})
}

const objectToJSXElement = (object: any, str="", isCapitalize=true) => {
if (object !== undefined && object != null && Object.keys(object).length > 0){
const objectToJSXElement = (object: any, str = "", isCapitalize = true) => {
if (object !== undefined && object != null && Object.keys(object).length > 0) {
const keys = Object.keys(object)
return keys.map((key: string, index: number) => {
const value = object[key]
if(isCapitalize) {key = capitalize(key)}
if (isCapitalize) { key = capitalize(key) }
if (Array.isArray(value)) {
return (
<div>
<h6 className='mb-0'>{str + key}</h6>
<span>{arrayToJSXElement(value, str+tab, isCapitalize)}</span>
<span>{arrayToJSXElement(value, str + tab, isCapitalize)}</span>
</div>
)
}else if (value === null || value === undefined || value.constructor === String || value.constructor === Number || value.constructor === Boolean) {
const className = (index !== keys.length-1 && str !== "") ? "mb-0" : ""
} else if (value === null || value === undefined || value.constructor === String || value.constructor === Number || value.constructor === Boolean) {
const className = (index !== keys.length - 1 && str !== "") ? "mb-0" : ""
return (
<div>
<h6 className='mb-0'>{str + key}</h6>
<p className={className}>{str}{(value != null && value !== undefined) ? value : "NULL"}</p>
<p className={className}>{str}{(value != null && value !== undefined) ? value : "No data"}</p>
</div>
)
} else {
return (
<div>
<h6 className='mb-0'>{str + key}</h6>
<span>{objectToJSXElement(value, str+tab, isCapitalize)}</span>
<span>{objectToJSXElement(value, str + tab, isCapitalize)}</span>
</div>
)
}
}
})
}
}
return <div></div>
}

const attributes = () => {
let thingAttributes = Object.assign({},defaultIfNoExist(thingInfo, "attributes", {}))
for (let key in thingAttributes) {
let thingAttributes = Object.assign({}, defaultIfNoExist(thingInfo, "attributes", {}))
for (let key in thingAttributes) {
if (thingAttributes.hasOwnProperty(key) && (key.startsWith("_") || basicAttributesConst.includes(key))) {
delete thingAttributes[key]
}
Expand All @@ -73,18 +73,18 @@ export function InformationThing ({path, thingInfo, meta, isType}: Parameters) {
}

const features = () => {
return objectToJSXElement(Object.assign({},defaultIfNoExist(thingInfo, "features", {})), "", false)
return objectToJSXElement(Object.assign({}, defaultIfNoExist(thingInfo, "features", {})), "", false)
}

const attributeIfExist = (object: any, nameAttribute: string, isImage = false) => {
if(defaultIfNoExist(object, nameAttribute, undefined) !== undefined){
const jsxElement = (!isImage) ? <div></div> :
<img src={object[nameAttribute]} style={{ height: "200px", width: "100%", objectFit: "cover", objectPosition: "center"}}/>
if (defaultIfNoExist(object, nameAttribute, undefined) !== undefined) {
const jsxElement = (!isImage) ? <div></div> :
<img src={object[nameAttribute]} style={{ height: "200px", width: "100%", objectFit: "cover", objectPosition: "center" }} />

return (
<div>
<h6 className='mb-0'>{capitalize(nameAttribute)}</h6>
<p style={{ wordWrap: 'break-word', overflowWrap: 'break-word'}}>{object[nameAttribute]}</p>
<p style={{ wordWrap: 'break-word', overflowWrap: 'break-word' }}>{object[nameAttribute]}</p>
{jsxElement}
</div>
)
Expand All @@ -98,10 +98,10 @@ export function InformationThing ({path, thingInfo, meta, isType}: Parameters) {
<div className="col-4">
<h5>Basic information</h5>
{attributeIfExist(thingInfo, "thingId", false)}
{attributeIfExist(thingInfo.attributes,"name", false)}
{attributeIfExist(thingInfo.attributes, "name", false)}
{attributeIfExist(thingInfo, "policyId", false)}
{attributeIfExist(thingInfo.attributes,"description", false)}
{attributeIfExist(thingInfo.attributes,"image", true)}
{attributeIfExist(thingInfo.attributes, "description", false)}
{attributeIfExist(thingInfo.attributes, "image", true)}
</div>
<div className="col-4">
<h5>Attributes</h5>
Expand Down
Loading

0 comments on commit f909d03

Please sign in to comment.