Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support TypeWrapper and new get_message_fields Service #26

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions src/components/JSONInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,18 @@
-->
<script setup lang="ts">
import { useEditNodeStore } from '@/stores/edit_node'
import { useROSStore } from '@/stores/ros'
import { RosTopicType_Name, type RosType } from '@/types/python_types'
import type { GetMessageFieldsRequest, GetMessageFieldsResponse } from '@/types/services/GetMessageFields'
import type { ParamData } from '@/types/types'
import { notify } from '@kyvg/vue3-notification'
import JSONEditor from 'jsoneditor'

import 'jsoneditor/dist/jsoneditor.min.css'
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'

const edit_node_store = useEditNodeStore()
const ros_store = useROSStore()

const props = defineProps<{
category: 'options'
Expand All @@ -51,6 +56,25 @@ const is_valid = ref<boolean>(true)
const editor_ref = ref<HTMLDivElement>()
let editor: JSONEditor | undefined = undefined

// Checks if there is a parameter that could be used to fetch
// a default value for Ros Messages
const is_topic_ref = computed<boolean>(() => {
if (param.value === undefined) {
return false
}
if (param.value.value.type === 'dict(ros)') {
return true
}
return false
})

const topic_ref_param = computed<ParamData | undefined>(() => {
if (!is_topic_ref.value) {
return undefined
}
return edit_node_store.new_node_options.find((x) => x.value.type === RosTopicType_Name)
})

function onFocus() {
edit_node_store.changeCopyMode(false)
}
Expand All @@ -68,6 +92,49 @@ function handleChange() {
}
}

function fetchRosMessageDefault() {
if (topic_ref_param.value === undefined) {
console.warn("Nothing to fetch")
return
}
const message_type = (topic_ref_param.value.value.value as RosType).type_str
console.log(message_type)
ros_store.get_message_fields_service.callService(
{
message_type: message_type
} as GetMessageFieldsRequest,
(response: GetMessageFieldsResponse) => {
console.log(response)
if (response.success) {
const fields_json = JSON.parse(response.fields)
if (editor !== undefined) {
editor.update(fields_json)
}
edit_node_store.updateParamValue(props.category, props.data_key, fields_json)
notify({
title: 'Successfully loaded message fields!',
text: '',
type: 'success'
})
} else {
notify({
title: 'Failed to load message fields!',
text: response.error_message,
type: 'warn'
})
}
},
(error: string) => {
notify({
title: 'Failed to call GetMessageFields service!',
text: error,
type: 'error'
})
}
)
console.log("Sent message fields request")
}

// This fires when param type changes and updates the editor accordingly
watch(
() => {
Expand Down Expand Up @@ -109,5 +176,16 @@ onUnmounted(() => {
</script>

<template>
<div class="d-flex align-items-center justify-content-between mb-1">
<label>
{{ param?.key }}
</label>
<button v-if="topic_ref_param"
class="btn btn-primary btn-sm"
@click="fetchRosMessageDefault"
>
Fetch default message fields
</button>
</div>
<div id="editor" ref="editor_ref" @focus="onFocus"></div>
</template>
10 changes: 2 additions & 8 deletions src/components/PackageLoader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,10 @@
* POSSIBILITY OF SUCH DAMAGE.
-->
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { useROSStore } from '@/stores/ros'
import type {
GetAvailableNodesRequest,
GetAvailableNodesResponse
} from '@/types/services/GetAvailableNodes'
import { ref } from 'vue'
import { useNodesStore } from '@/stores/nodes'
import { notify } from '@kyvg/vue3-notification'

const ros_store = useROSStore()

const nodes_store = useNodesStore()

const collapsed = ref<boolean>(false)
Expand Down
64 changes: 26 additions & 38 deletions src/components/ParamInputs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
MathOperandType_Name,
MathUnaryOperandType_Name,
MathUnaryOperator_Name,
OrderedDict_Name,
RosTopicType_Name,
RosTopicName_Name,
RosServiceType_Name,
Expand All @@ -53,6 +52,7 @@
} from '@/types/python_types'
import RosTypeParam from './param_inputs/RosTypeParam.vue'
import RosNameParam from './param_inputs/RosNameParam.vue'
import { getTypeAndInfo } from '@/utils'

const props = defineProps<{
category: 'options'
Expand All @@ -66,11 +66,20 @@
edit_node_store.new_node_options.find((x) => x.key === props.data_key)
)

const param_type = computed<string>(() => {
if (param.value === undefined) {
return ''
}
return getTypeAndInfo(param.value.value.type)[0]
})

// Below lists the data types that are handled by <input>...
const input_type_values = ['int', 'float', 'bool', 'string', 'unset_optionref']
// ...and gives the appropriate attributes.
const input_attrs = computed<any>(() => {
if (param.value === undefined || !input_type_values.includes(param.value.value.type)) {
if (param.value === undefined ||
!input_type_values.includes(param_type.value)
) {
return undefined
}
let type: string,
Expand All @@ -79,10 +88,10 @@
cssclass: string[] = ['form-control'],
checked: boolean = false,
disabled: boolean = editor_store.selected_subtree.is_subtree
switch (param.value.value.type) {
switch (param_type.value) {
case 'int':
step = 1.0
case 'float':

Check warning on line 94 in src/components/ParamInputs.vue

View workflow job for this annotation

GitHub Actions / build (18.x)

Expected a 'break' statement before 'case'

Check warning on line 94 in src/components/ParamInputs.vue

View workflow job for this annotation

GitHub Actions / build (20.x)

Expected a 'break' statement before 'case'

Check warning on line 94 in src/components/ParamInputs.vue

View workflow job for this annotation

GitHub Actions / build (22.x)

Expected a 'break' statement before 'case'

Check warning on line 94 in src/components/ParamInputs.vue

View workflow job for this annotation

GitHub Actions / build (23.x)

Expected a 'break' statement before 'case'
type = 'number'
value = param.value.value.value as number
break
Expand All @@ -93,7 +102,7 @@
break
case 'unset_optionref':
disabled = true
case 'string':

Check warning on line 105 in src/components/ParamInputs.vue

View workflow job for this annotation

GitHub Actions / build (18.x)

Expected a 'break' statement before 'case'

Check warning on line 105 in src/components/ParamInputs.vue

View workflow job for this annotation

GitHub Actions / build (20.x)

Expected a 'break' statement before 'case'

Check warning on line 105 in src/components/ParamInputs.vue

View workflow job for this annotation

GitHub Actions / build (22.x)

Expected a 'break' statement before 'case'

Check warning on line 105 in src/components/ParamInputs.vue

View workflow job for this annotation

GitHub Actions / build (23.x)

Expected a 'break' statement before 'case'
type = 'text'
value = param.value.value.value as string
break
Expand All @@ -111,24 +120,6 @@
}
})

// Below gives the attributes for data types handled by <JSONInput>
// no type_values check since this is also the fallback
const json_attrs = computed<any>(() => {
if (param.value === undefined) {
return undefined
}
switch (param.value.value.type) {
case 'list':
break
case 'dict':
case OrderedDict_Name:
break
default:
break
}
return {}
})

// Handles value changes for the <input> element
function onChange(event: Event) {
if (param.value === undefined) {
Expand Down Expand Up @@ -174,86 +165,83 @@
</div>

<TypeParam
v-else-if="param.value.type === 'type'"
v-else-if="param_type === 'type'"
:category="props.category"
:data_key="props.data_key"
/>

<MathOperatorParam
v-else-if="param.value.type === MathUnaryOperator_Name"
v-else-if="param_type === MathUnaryOperator_Name"
:category="props.category"
:data_key="props.data_key"
:op_type="'unary'"
/>
<MathOperandParam
v-else-if="param.value.type === MathUnaryOperandType_Name"
v-else-if="param_type === MathUnaryOperandType_Name"
:category="props.category"
:data_key="props.data_key"
:op_type="'unary'"
/>
<MathOperatorParam
v-else-if="param.value.type === MathBinaryOperator_Name"
v-else-if="param_type === MathBinaryOperator_Name"
:category="props.category"
:data_key="props.data_key"
:op_type="'binary'"
/>
<MathOperandParam
v-else-if="param.value.type === MathOperandType_Name"
v-else-if="param_type === MathOperandType_Name"
:category="props.category"
:data_key="props.data_key"
:op_type="'binary'"
/>

<FilePathParam
v-else-if="param.value.type === FilePath_Name"
v-else-if="param_type === FilePath_Name"
:category="props.category"
:data_key="props.data_key"
/>

<RosTypeParam
v-else-if="param.value.type === RosTopicType_Name"
v-else-if="param_type === RosTopicType_Name"
:category="props.category"
:data_key="props.data_key"
:type="'topic'"
/>
<RosNameParam
v-else-if="param.value.type === RosTopicName_Name"
v-else-if="param_type === RosTopicName_Name"
:category="props.category"
:data_key="props.data_key"
:type="'topic'"
/>

<RosTypeParam
v-else-if="param.value.type === RosServiceType_Name"
v-else-if="param_type === RosServiceType_Name"
:category="props.category"
:data_key="props.data_key"
:type="'service'"
/>
<RosNameParam
v-else-if="param.value.type === RosServiceName_Name"
v-else-if="param_type === RosServiceName_Name"
:category="props.category"
:data_key="props.data_key"
:type="'service'"
/>

<RosTypeParam
v-else-if="param.value.type === RosActionType_Name"
v-else-if="param_type === RosActionType_Name"
:category="props.category"
:data_key="props.data_key"
:type="'action'"
/>
<RosNameParam
v-else-if="param.value.type === RosActionName_Name"
v-else-if="param_type === RosActionName_Name"
:category="props.category"
:data_key="props.data_key"
:type="'action'"
/>

<div v-else class="form-group">
<label class="d-block">
{{ param.key }}
<JSONInput v-bind="json_attrs" :category="props.category" :data_key="props.data_key" />
</label>
<div v-else class="form-group position-relative">
<JSONInput :category="props.category" :data_key="props.data_key" />
</div>
</div>
<div v-else>Error loading param data</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/TreeNameStateDisplay.vue
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const tree_state = computed<TreeState>(() => {

const tree_state_styles = computed<any>(() => {
let bg_color_var = ''
let border_color_var = '--bs-body-color'
//let border_color_var = '--bs-body-color'
switch (tree_state.value) {
case TreeState.ERROR:
bg_color_var = '--bg-color-error'
Expand Down
34 changes: 27 additions & 7 deletions src/components/param_inputs/TypeParam.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ import { useEditNodeStore } from '@/stores/edit_node'
import { useEditorStore } from '@/stores/editor'
import { useMessasgeStore } from '@/stores/message'
import type { ParamData } from '@/types/types'
import { python_builtin_types } from '@/utils'
import { getTypeAndInfo, python_builtin_types } from '@/utils'
import Fuse from 'fuse.js'
import { computed, ref } from 'vue'

const props = defineProps<{
Expand All @@ -44,12 +45,23 @@ const editor_store = useEditorStore()
const edit_node_store = useEditNodeStore()
const messages_store = useMessasgeStore()

let messages_results = ref<string[]>([])
let search_results = ref<string[]>([])

const param = computed<ParamData | undefined>(() =>
edit_node_store.new_node_options.find((x) => x.key === props.data_key)
)

const search_fuse = computed<Fuse<string>>(() => {
if (param.value === undefined) {
return messages_store.messages_fuse
}
const info = getTypeAndInfo(param.value.value.type)[1]
if (info === 'builtin') {
return new Fuse<string>(python_builtin_types)
}
return messages_store.messages_fuse
})

const display_value = computed<string>(() => {
if (param.value === undefined) {
return ''
Expand All @@ -75,8 +87,8 @@ function onChange(event: Event) {
const target = event.target as HTMLInputElement
let new_type_name = target.value || ''
new_type_name = new_type_name.replace('__builtin__.', '').replace('builtins.', '')
const results = messages_store.messages_fuse.search(new_type_name)
messages_results.value = results.map((x) => x.item)
const results = search_fuse.value.search(new_type_name)
search_results.value = results.map((x) => x.item)

edit_node_store.updateParamValue(props.category, props.data_key, new_type_name)
}
Expand All @@ -86,6 +98,15 @@ function selectSearchResult(search_result: string) {
releaseDropdown()
}

function displaySearchResult(value: string): string {
// Show builtins prefix if appropriate
if (python_builtin_types.includes(value)) {
value = 'builtins.' + value
}
// Allow line breaks at dots
return value.replace(/\./g, '.\u200B')
}

function focusInput() {
edit_node_store.changeCopyMode(false)
hide_results.value = false
Expand Down Expand Up @@ -133,16 +154,15 @@ function releaseDropdown() {
@mouseleave="releaseDropdown"
>
<div
v-for="result in messages_results"
v-for="result in search_results"
:key="result"
class="list-group-item search-result"
tabindex="0"
@click="() => selectSearchResult(result)"
@keyup.enter="() => selectSearchResult(result)"
@keyup.esc="releaseDropdown"
>
<!--Insert a zero-width space after each dot to allow line breaks-->
{{ result.replace(/\./g, '.\u200B') }}
{{ displaySearchResult(result) }}
</div>
</div>
</div>
Expand Down
Loading
Loading