Skip to content

Commit

Permalink
improve plus button on workflow node (#4413)
Browse files Browse the repository at this point in the history
Co-authored-by: Cole Blanchard <[email protected]>
  • Loading branch information
blanchco and Cole Blanchard authored Aug 9, 2024
1 parent a544c56 commit 662c9b4
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 65 deletions.
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
<template>
<Button
v-bind="$attrs"
type="button"
size="small"
@click="showMenu"
icon="pi pi-plus"
aria-haspopup="true"
aria-controls="overlay_menu"
severity="secondary"
/>
<Menu
ref="menu"
id="overlay_menu"
:model="menuItems"
:popup="true"
@focus="emit('menu-focus')"
@blur="emit('menu-blur')"
/>
<aside>
<Button
v-bind="$attrs"
type="button"
size="small"
@click="showMenu"
icon="pi pi-plus"
aria-haspopup="true"
aria-controls="overlay_menu"
severity="secondary"
/>
<Menu
ref="menu"
id="overlay_menu"
:model="menuItems"
:popup="true"
@focus="emit('menu-focus')"
@blur="emit('menu-blur')"
/>
</aside>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { ref, computed } from 'vue';
import Menu from 'primevue/menu';
import Button from 'primevue/button';
import { OperatorMenuItem } from '@/services/workflow';
Expand All @@ -32,9 +34,7 @@ const emit = defineEmits(['menu-focus', 'menu-blur', 'menu-selection']);
const isMenuShowing = ref<boolean>(false);
const menu = ref();
const menuItems = ref();
onMounted(() => {
const menuItems = computed(() => {
const options: Array<{}> = [];
props.nodeMenu.forEach((node) =>
options.push({
Expand All @@ -44,7 +44,7 @@ onMounted(() => {
}
})
);
menuItems.value = [{ items: options }];
return [{ items: options }];
});
function showMenu(event) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,18 @@
:id="output.id"
:key="output.id"
:class="{ 'port-connected': output.status === WorkflowPortStatus.CONNECTED }"
@mouseenter="emit('port-mouseover', $event)"
@mouseleave="emit('port-mouseleave')"
@mouseenter="
($event) => {
menuFocusId = output.id;
emit('port-mouseover', $event);
}
"
@mouseleave="
() => {
menuFocusId = null;
emit('port-mouseleave');
}
"
@click.stop="emit('port-selected', output, WorkflowDirection.FROM_OUTPUT)"
@focus="() => {}"
@focusout="() => {}"
Expand All @@ -29,6 +39,24 @@
/>
</div>
</section>
<Transition>
<tera-operator-menu
v-show="menuOptions.length && menuFocusId === output.id"
:nodeMenu="menuOptions"
:style="{
height: '2rem',
position: 'absolute',
right: '-4rem',
bottom: '0px'
}"
@click.stop
@mousedown.stop
@mouseup.stop
@menu-focus="menuFocusId = output.id"
@menu-blur="menuFocusId = null"
@menu-selection="(operatorType) => emit('menu-selection', operatorType)"
/>
</Transition>
<!--TODO: We will see how to integrate port actions into this button later-->
<!-- <Button
size="small"
Expand All @@ -41,16 +69,31 @@
</template>

<script setup lang="ts">
import { PropType, computed } from 'vue';
import { PropType, computed, ref } from 'vue';
import { WorkflowPortStatus, WorkflowDirection, WorkflowOutput } from '@/types/workflow';
import Button from 'primevue/button';
import { OperatorMenuItem } from '@/services/workflow';
import TeraOperatorMenu from './tera-operator-menu.vue';
const emit = defineEmits(['port-mouseover', 'port-selected', 'port-mouseover', 'port-mouseleave', 'remove-edges']);
const menuFocusId = ref<string | null>(null);
const emit = defineEmits([
'port-mouseover',
'port-selected',
'port-mouseover',
'port-mouseleave',
'remove-edges',
'menu-selection'
]);
const props = defineProps({
outputs: {
type: Array as PropType<WorkflowOutput<any>[]>,
default: () => []
},
menuOptions: {
type: Array as PropType<OperatorMenuItem[]>,
default: () => []
}
});
Expand Down Expand Up @@ -81,6 +124,15 @@ li > *:not(:first-child) {
margin-right: calc(var(--port-base-size) * 2);
}
li:hover:before {
content: '';
position: absolute;
width: 6.5rem;
height: 4rem;
bottom: -0.75rem;
right: -8rem;
}
.port-container {
text-align: right;
}
Expand All @@ -107,4 +159,15 @@ li > *:not(:first-child) {
top: -0.35rem;
left: -0.35rem;
}
/** These v-* classes are used for animations for the <Transition /> element */
.v-enter-active,
.v-leave-active {
transition: opacity 0.5s ease;
}
.v-enter-from,
.v-leave-to {
opacity: 0;
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -35,25 +35,14 @@
</section>
<tera-operator-outputs
:outputs="node.outputs"
:menu-options="menuOptions"
@menu-selection="onSelection"
@port-mouseover="(event) => mouseoverPort(event, PortType.Output)"
@port-mouseleave="mouseleavePort"
@port-selected="(input: WorkflowPort, direction: WorkflowDirection) => emit('port-selected', input, direction)"
@remove-edges="(portId: string) => emit('remove-edges', portId)"
/>
</main>
<tera-operator-menu
v-if="isMenuFocused && menuOptions.length"
:nodeMenu="menuOptions"
:style="{
top: '-30px',
left: `${operatorPosition.width + 20}px`
}"
@menu-focus="showOutputButton(PortType.Output)"
@menu-blur="hideOutputButton"
@menu-selection="(operatorType) => onSelection(operatorType)"
@focus="showOutputButton(PortType.Output)"
@blur="hideOutputButton"
/>
</template>

<script setup lang="ts">
Expand All @@ -69,7 +58,6 @@ import TeraOperatorHeader from '@/components/operator/tera-operator-header.vue';
import TeraOperatorInputs from '@/components/operator/tera-operator-inputs.vue';
import TeraOperatorOutputs from '@/components/operator/tera-operator-outputs.vue';
import TeraOperatorAnnotation from '@/components/operator/tera-operator-annotation.vue';
import TeraOperatorMenu from '@/components/operator/tera-operator-menu.vue';
import { OperatorMenuItem } from '@/services/workflow';
const props = defineProps<{
Expand All @@ -95,12 +83,8 @@ enum PortType {
}
const operator = ref<HTMLElement>();
const operatorPosition = ref();
const interactionStatus = ref(0); // States will be added to it thorugh bitmasking
const annotationRef = ref<typeof TeraOperatorAnnotation | null>(null);
const isMenuFocused = ref<boolean>(false);
const menuButtonTimeoutId = ref<NodeJS.Timeout | null>(null);
const menuOptions = ref<OperatorMenuItem[] | []>([]);
let resizeObserver: ResizeObserver | null = null;
Expand All @@ -113,25 +97,7 @@ function openInNewWindow() {
floatingWindow.open(url);
}
function hideMenuButton() {
isMenuFocused.value = false;
}
function showOutputButton(portType: PortType) {
if (menuButtonTimeoutId.value) {
clearTimeout(menuButtonTimeoutId.value);
}
if (portType) {
isMenuFocused.value = true;
}
}
function hideOutputButton() {
menuButtonTimeoutId.value = setTimeout(hideMenuButton, 1000);
}
function mouseoverPort(event: MouseEvent, portType: PortType) {
showOutputButton(portType);
const el = event.target as HTMLElement;
const portElement = (el.querySelector('.port') as HTMLElement) ?? el;
const nodePosition: Position = { x: props.node.x, y: props.node.y };
Expand All @@ -145,7 +111,6 @@ function mouseoverPort(event: MouseEvent, portType: PortType) {
}
function mouseleavePort() {
menuButtonTimeoutId.value = setTimeout(hideMenuButton, 1000);
emit('port-mouseleave');
}
Expand All @@ -162,7 +127,6 @@ onMounted(() => {
if (operator.value) {
resizeObserver = new ResizeObserver(resizeHandler);
resizeObserver.observe(operator.value);
operatorPosition.value = operator.value.getBoundingClientRect();
}
});
Expand Down

0 comments on commit 662c9b4

Please sign in to comment.