Fix regression where tooltip node descriptions in the graph stopped showing (#3639)
* Fix tooltips * Convert DefinitionIdentifier to string in JavaScript * Code review --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
parent
c60ddcf875
commit
c13647aef4
|
|
@ -2,7 +2,6 @@ use super::utility_types::{DocumentDetails, MouseCursorIcon, OpenDocument};
|
||||||
use crate::messages::app_window::app_window_message_handler::AppWindowPlatform;
|
use crate::messages::app_window::app_window_message_handler::AppWindowPlatform;
|
||||||
use crate::messages::input_mapper::utility_types::misc::ActionShortcut;
|
use crate::messages::input_mapper::utility_types::misc::ActionShortcut;
|
||||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier;
|
|
||||||
use crate::messages::portfolio::document::node_graph::utility_types::{
|
use crate::messages::portfolio::document::node_graph::utility_types::{
|
||||||
BoxSelection, ContextMenuInformation, FrontendClickTargets, FrontendGraphInput, FrontendGraphOutput, FrontendNode, FrontendNodeType, NodeGraphErrorDiagnostic, Transform,
|
BoxSelection, ContextMenuInformation, FrontendClickTargets, FrontendGraphInput, FrontendGraphOutput, FrontendNode, FrontendNodeType, NodeGraphErrorDiagnostic, Transform,
|
||||||
};
|
};
|
||||||
|
|
@ -61,7 +60,7 @@ pub enum FrontendMessage {
|
||||||
// Send prefix: Send global, static data to the frontend that is never updated
|
// Send prefix: Send global, static data to the frontend that is never updated
|
||||||
SendUIMetadata {
|
SendUIMetadata {
|
||||||
#[serde(rename = "nodeDescriptions")]
|
#[serde(rename = "nodeDescriptions")]
|
||||||
node_descriptions: Vec<(DefinitionIdentifier, String)>,
|
node_descriptions: Vec<(String, String)>,
|
||||||
#[serde(rename = "nodeTypes")]
|
#[serde(rename = "nodeTypes")]
|
||||||
node_types: Vec<FrontendNodeType>,
|
node_types: Vec<FrontendNodeType>,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -80,29 +80,23 @@ impl DefinitionIdentifier {
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn serialized(&self) -> String {
|
||||||
|
match self {
|
||||||
|
DefinitionIdentifier::ProtoNode(id) => format!("PROTONODE:{}", id.as_str()),
|
||||||
|
DefinitionIdentifier::Network(data) => format!("NETWORK:{}", data),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Value> for DefinitionIdentifier {
|
impl From<Value> for DefinitionIdentifier {
|
||||||
fn from(value: Value) -> Self {
|
fn from(value: Value) -> Self {
|
||||||
match value {
|
let s = value.as_str().expect("DefinitionIdentifier value must be a string");
|
||||||
Value::Object(mut map) => {
|
|
||||||
let ty = map.remove("type").unwrap().as_str().unwrap().to_owned();
|
|
||||||
|
|
||||||
match ty.as_ref() {
|
match s.split_once(':') {
|
||||||
"Network" => {
|
Some(("PROTONODE", data)) => DefinitionIdentifier::ProtoNode(ProtoNodeIdentifier::with_owned_string(data.to_string())),
|
||||||
let data = map.remove("data").unwrap().as_str().unwrap().to_owned();
|
Some(("NETWORK", data)) => DefinitionIdentifier::Network(data.to_string()),
|
||||||
DefinitionIdentifier::Network(data)
|
other => panic!("Unknown `DefinitionIdentifier` type. Found `{other:?}`."),
|
||||||
}
|
|
||||||
"ProtoNode" => {
|
|
||||||
let value = map.remove("data").unwrap();
|
|
||||||
let proto: ProtoNodeIdentifier = serde_json::from_value(value).unwrap();
|
|
||||||
DefinitionIdentifier::ProtoNode(proto)
|
|
||||||
}
|
|
||||||
_ => panic!("Unknown `DefinitionIdentifier` type: {:?}", ty),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => panic!("Expected a JSON object to convert to `DefinitionIdentifier`"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2621,7 +2615,7 @@ pub fn collect_node_types() -> Vec<FrontendNodeType> {
|
||||||
name = identifier.implementation_name_from_identifier()
|
name = identifier.implementation_name_from_identifier()
|
||||||
}
|
}
|
||||||
FrontendNodeType {
|
FrontendNodeType {
|
||||||
identifier: identifier.clone(),
|
identifier: identifier.serialized(),
|
||||||
name,
|
name,
|
||||||
category: definition.category.to_string(),
|
category: definition.category.to_string(),
|
||||||
input_types,
|
input_types,
|
||||||
|
|
@ -2630,10 +2624,15 @@ pub fn collect_node_types() -> Vec<FrontendNodeType> {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn collect_node_descriptions() -> Vec<(DefinitionIdentifier, String)> {
|
pub fn collect_node_descriptions() -> Vec<(String, String)> {
|
||||||
DOCUMENT_NODE_TYPES
|
DOCUMENT_NODE_TYPES
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(identifier, definition)| (identifier.clone(), if definition.description != "TODO" { definition.description.to_string() } else { String::new() }))
|
.map(|(identifier, definition)| {
|
||||||
|
(
|
||||||
|
identifier.serialized(),
|
||||||
|
if definition.description != "TODO" { definition.description.to_string() } else { String::new() },
|
||||||
|
)
|
||||||
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2599,7 +2599,7 @@ impl NodeGraphMessageHandler {
|
||||||
.node_metadata(&node_id, breadcrumb_network_path)
|
.node_metadata(&node_id, breadcrumb_network_path)
|
||||||
.is_some_and(|node_metadata| node_metadata.persistent_metadata.is_layer()),
|
.is_some_and(|node_metadata| node_metadata.persistent_metadata.is_layer()),
|
||||||
can_be_layer: network_interface.is_eligible_to_be_layer(&node_id, breadcrumb_network_path),
|
can_be_layer: network_interface.is_eligible_to_be_layer(&node_id, breadcrumb_network_path),
|
||||||
reference: network_interface.reference(&node_id, breadcrumb_network_path),
|
reference: network_interface.reference(&node_id, breadcrumb_network_path).map(|reference| reference.serialized()),
|
||||||
display_name: network_interface.display_name(&node_id, breadcrumb_network_path),
|
display_name: network_interface.display_name(&node_id, breadcrumb_network_path),
|
||||||
implementation_name: network_interface.implementation_name(&node_id, breadcrumb_network_path),
|
implementation_name: network_interface.implementation_name(&node_id, breadcrumb_network_path),
|
||||||
primary_input,
|
primary_input,
|
||||||
|
|
@ -2715,16 +2715,12 @@ impl NodeGraphMessageHandler {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let Some(reference) = network_interface.reference(&node_id, &[]) else {
|
|
||||||
log::error!("Could not get reference for layer {node_id} in update_layer_panel");
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
let clippable = layer.can_be_clipped(network_interface.document_metadata());
|
let clippable = layer.can_be_clipped(network_interface.document_metadata());
|
||||||
|
|
||||||
let data = LayerPanelEntry {
|
let data = LayerPanelEntry {
|
||||||
id: node_id,
|
id: node_id,
|
||||||
reference,
|
implementation_name: network_interface.implementation_name(&node_id, &[]),
|
||||||
|
icon_name: network_interface.is_artboard(&node_id, &[]).then(|| "Artboard".to_string()),
|
||||||
alias: network_interface.display_name(&node_id, &[]),
|
alias: network_interface.display_name(&node_id, &[]),
|
||||||
in_selected_network: selection_network_path.is_empty(),
|
in_selected_network: selection_network_path.is_empty(),
|
||||||
children_allowed,
|
children_allowed,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
use super::document_node_definitions::DefinitionIdentifier;
|
|
||||||
use glam::{DVec2, IVec2};
|
use glam::{DVec2, IVec2};
|
||||||
use graph_craft::document::NodeId;
|
use graph_craft::document::NodeId;
|
||||||
use graph_craft::document::value::TaggedValue;
|
use graph_craft::document::value::TaggedValue;
|
||||||
|
|
@ -79,7 +78,7 @@ pub struct FrontendNode {
|
||||||
pub is_layer: bool,
|
pub is_layer: bool,
|
||||||
#[serde(rename = "canBeLayer")]
|
#[serde(rename = "canBeLayer")]
|
||||||
pub can_be_layer: bool,
|
pub can_be_layer: bool,
|
||||||
pub reference: Option<DefinitionIdentifier>,
|
pub reference: Option<String>,
|
||||||
#[serde(rename = "displayName")]
|
#[serde(rename = "displayName")]
|
||||||
pub display_name: String,
|
pub display_name: String,
|
||||||
#[serde(rename = "implementationName")]
|
#[serde(rename = "implementationName")]
|
||||||
|
|
@ -104,7 +103,7 @@ pub struct FrontendNode {
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
pub struct FrontendNodeType {
|
pub struct FrontendNodeType {
|
||||||
pub identifier: DefinitionIdentifier,
|
pub identifier: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub category: String,
|
pub category: String,
|
||||||
#[serde(rename = "inputTypes")]
|
#[serde(rename = "inputTypes")]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
use super::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
|
use super::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
|
||||||
use super::network_interface::NodeNetworkInterface;
|
use super::network_interface::NodeNetworkInterface;
|
||||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier;
|
|
||||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||||
use glam::DVec2;
|
use glam::DVec2;
|
||||||
use graph_craft::document::{NodeId, NodeNetwork};
|
use graph_craft::document::{NodeId, NodeNetwork};
|
||||||
|
|
@ -35,7 +34,10 @@ impl serde::Serialize for JsRawBuffer {
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, specta::Type)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, specta::Type)]
|
||||||
pub struct LayerPanelEntry {
|
pub struct LayerPanelEntry {
|
||||||
pub id: NodeId,
|
pub id: NodeId,
|
||||||
pub reference: DefinitionIdentifier,
|
#[serde(rename = "implementationName")]
|
||||||
|
pub implementation_name: String,
|
||||||
|
#[serde(rename = "iconName")]
|
||||||
|
pub icon_name: Option<String>,
|
||||||
pub alias: String,
|
pub alias: String,
|
||||||
#[serde(rename = "inSelectedNetwork")]
|
#[serde(rename = "inSelectedNetwork")]
|
||||||
pub in_selected_network: bool,
|
pub in_selected_network: bool,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher, getContext, onMount } from "svelte";
|
import { createEventDispatcher, getContext, onMount } from "svelte";
|
||||||
|
|
||||||
import type { DefinitionIdentifier, FrontendNodeType } from "@graphite/messages";
|
import type { FrontendNodeType } from "@graphite/messages";
|
||||||
import type { NodeGraphState } from "@graphite/state-providers/node-graph";
|
import type { NodeGraphState } from "@graphite/state-providers/node-graph";
|
||||||
|
|
||||||
import LayoutCol from "@graphite/components/layout/LayoutCol.svelte";
|
import LayoutCol from "@graphite/components/layout/LayoutCol.svelte";
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
import TextInput from "@graphite/components/widgets/inputs/TextInput.svelte";
|
import TextInput from "@graphite/components/widgets/inputs/TextInput.svelte";
|
||||||
import TextLabel from "@graphite/components/widgets/labels/TextLabel.svelte";
|
import TextLabel from "@graphite/components/widgets/labels/TextLabel.svelte";
|
||||||
|
|
||||||
const dispatch = createEventDispatcher<{ selectNodeType: DefinitionIdentifier }>();
|
const dispatch = createEventDispatcher<{ selectNodeType: string }>();
|
||||||
const nodeGraph = getContext<NodeGraphState>("nodeGraph");
|
const nodeGraph = getContext<NodeGraphState>("nodeGraph");
|
||||||
|
|
||||||
// Content
|
// Content
|
||||||
|
|
@ -125,7 +125,7 @@
|
||||||
{disabled}
|
{disabled}
|
||||||
label={nodeType.name}
|
label={nodeType.name}
|
||||||
tooltipLabel={nodeType.name}
|
tooltipLabel={nodeType.name}
|
||||||
tooltipDescription={$nodeGraph.nodeDescriptions.get(nodeType.identifier)}
|
tooltipDescription={nodeType.identifier ? $nodeGraph.nodeDescriptions.get(nodeType.identifier) : undefined}
|
||||||
action={() => dispatch("selectNodeType", nodeType.identifier)}
|
action={() => dispatch("selectNodeType", nodeType.identifier)}
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
|
||||||
|
|
@ -644,15 +644,15 @@
|
||||||
{@html $nodeGraph.thumbnails.get(listing.entry.id)}
|
{@html $nodeGraph.thumbnails.get(listing.entry.id)}
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{#if listing.entry.reference.type === "Network" && listing.entry.reference.data === "Artboard"}
|
{#if listing.entry.iconName}
|
||||||
<IconLabel icon="Artboard" class="layer-type-icon" tooltipLabel="Artboard" />
|
<IconLabel icon={listing.entry.iconName} class="layer-type-icon" tooltipLabel="Artboard" />
|
||||||
{/if}
|
{/if}
|
||||||
<LayoutRow class="layer-name" on:dblclick={() => onEditLayerName(listing)}>
|
<LayoutRow class="layer-name" on:dblclick={() => onEditLayerName(listing)}>
|
||||||
<input
|
<input
|
||||||
data-text-input
|
data-text-input
|
||||||
type="text"
|
type="text"
|
||||||
value={listing.entry.alias}
|
value={listing.entry.alias}
|
||||||
placeholder={listing.entry.reference.data}
|
placeholder={listing.entry.implementationName}
|
||||||
disabled={!listing.editingName}
|
disabled={!listing.editingName}
|
||||||
on:blur={() => onEditLayerNameDeselect(listing)}
|
on:blur={() => onEditLayerNameDeselect(listing)}
|
||||||
on:keydown={(e) => e.key === "Escape" && onEditLayerNameDeselect(listing)}
|
on:keydown={(e) => e.key === "Escape" && onEditLayerNameDeselect(listing)}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
import { fade } from "svelte/transition";
|
import { fade } from "svelte/transition";
|
||||||
|
|
||||||
import type { Editor } from "@graphite/editor";
|
import type { Editor } from "@graphite/editor";
|
||||||
import type { DefinitionIdentifier, FrontendGraphInput, FrontendGraphOutput, FrontendNode } from "@graphite/messages";
|
import type { FrontendGraphInput, FrontendGraphOutput, FrontendNode } from "@graphite/messages";
|
||||||
import type { NodeGraphState } from "@graphite/state-providers/node-graph";
|
import type { NodeGraphState } from "@graphite/state-providers/node-graph";
|
||||||
|
|
||||||
import NodeCatalog from "@graphite/components/floating-menus/NodeCatalog.svelte";
|
import NodeCatalog from "@graphite/components/floating-menus/NodeCatalog.svelte";
|
||||||
|
|
@ -100,7 +100,7 @@
|
||||||
return sparse;
|
return sparse;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createNode(identifier: DefinitionIdentifier) {
|
function createNode(identifier: string) {
|
||||||
if ($nodeGraph.contextMenuInformation === undefined) return;
|
if ($nodeGraph.contextMenuInformation === undefined) return;
|
||||||
|
|
||||||
editor.handle.createNode(identifier, $nodeGraph.contextMenuInformation.contextMenuCoordinates.x, $nodeGraph.contextMenuInformation.contextMenuCoordinates.y);
|
editor.handle.createNode(identifier, $nodeGraph.contextMenuInformation.contextMenuCoordinates.x, $nodeGraph.contextMenuInformation.contextMenuCoordinates.y);
|
||||||
|
|
@ -481,7 +481,7 @@
|
||||||
{@const layerAreaWidth = $nodeGraph.layerWidths.get(node.id) || 8}
|
{@const layerAreaWidth = $nodeGraph.layerWidths.get(node.id) || 8}
|
||||||
{@const layerChainWidth = $nodeGraph.chainWidths.get(node.id) || 0}
|
{@const layerChainWidth = $nodeGraph.chainWidths.get(node.id) || 0}
|
||||||
{@const hasLeftInputWire = $nodeGraph.hasLeftInputWire.get(node.id) || false}
|
{@const hasLeftInputWire = $nodeGraph.hasLeftInputWire.get(node.id) || false}
|
||||||
{@const description = (node.reference && $nodeGraph.nodeDescriptions.get(node.reference)) || undefined}
|
{@const description = node.reference ? $nodeGraph.nodeDescriptions.get(node.reference) : undefined}
|
||||||
<div
|
<div
|
||||||
class="layer"
|
class="layer"
|
||||||
class:selected={$nodeGraph.selected.includes(node.id)}
|
class:selected={$nodeGraph.selected.includes(node.id)}
|
||||||
|
|
@ -634,7 +634,7 @@
|
||||||
.map(([_, node], nodeIndex) => ({ node, nodeIndex })) as { node, nodeIndex } (nodeIndex)}
|
.map(([_, node], nodeIndex) => ({ node, nodeIndex })) as { node, nodeIndex } (nodeIndex)}
|
||||||
{@const exposedInputsOutputs = zipWithUndefined(node.exposedInputs, node.exposedOutputs)}
|
{@const exposedInputsOutputs = zipWithUndefined(node.exposedInputs, node.exposedOutputs)}
|
||||||
{@const clipPathId = String(Math.random()).substring(2)}
|
{@const clipPathId = String(Math.random()).substring(2)}
|
||||||
{@const description = (node.reference && $nodeGraph.nodeDescriptions.get(node.reference)) || undefined}
|
{@const description = node.reference ? $nodeGraph.nodeDescriptions.get(node.reference) : undefined}
|
||||||
<div
|
<div
|
||||||
class="node"
|
class="node"
|
||||||
class:selected={$nodeGraph.selected.includes(node.id)}
|
class:selected={$nodeGraph.selected.includes(node.id)}
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ export class UpdateNodeGraphTransform extends JsMessage {
|
||||||
|
|
||||||
export class SendUIMetadata extends JsMessage {
|
export class SendUIMetadata extends JsMessage {
|
||||||
@Transform(({ obj }) => new Map(obj.nodeDescriptions))
|
@Transform(({ obj }) => new Map(obj.nodeDescriptions))
|
||||||
readonly nodeDescriptions!: Map<DefinitionIdentifier, string>;
|
readonly nodeDescriptions!: Map<string, string>;
|
||||||
|
|
||||||
readonly nodeTypes!: FrontendNodeType[];
|
readonly nodeTypes!: FrontendNodeType[];
|
||||||
}
|
}
|
||||||
|
|
@ -220,7 +220,7 @@ export class FrontendNode {
|
||||||
|
|
||||||
readonly canBeLayer!: boolean;
|
readonly canBeLayer!: boolean;
|
||||||
|
|
||||||
readonly reference!: DefinitionIdentifier | undefined;
|
readonly reference!: string | undefined;
|
||||||
|
|
||||||
readonly displayName!: string;
|
readonly displayName!: string;
|
||||||
|
|
||||||
|
|
@ -251,7 +251,7 @@ export class FrontendNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FrontendNodeType {
|
export class FrontendNodeType {
|
||||||
readonly identifier!: DefinitionIdentifier;
|
readonly identifier!: string;
|
||||||
|
|
||||||
readonly name!: string;
|
readonly name!: string;
|
||||||
|
|
||||||
|
|
@ -834,7 +834,9 @@ export class UpdateDocumentLayerDetails extends JsMessage {
|
||||||
export class LayerPanelEntry {
|
export class LayerPanelEntry {
|
||||||
id!: bigint;
|
id!: bigint;
|
||||||
|
|
||||||
reference!: DefinitionIdentifier;
|
implementationName!: string;
|
||||||
|
|
||||||
|
iconName!: IconName | undefined;
|
||||||
|
|
||||||
alias!: string;
|
alias!: string;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ import {
|
||||||
type FrontendNode,
|
type FrontendNode,
|
||||||
type FrontendNodeType,
|
type FrontendNodeType,
|
||||||
type WirePath,
|
type WirePath,
|
||||||
type DefinitionIdentifier,
|
|
||||||
ClearAllNodeGraphWires,
|
ClearAllNodeGraphWires,
|
||||||
SendUIMetadata,
|
SendUIMetadata,
|
||||||
UpdateBox,
|
UpdateBox,
|
||||||
|
|
@ -45,7 +44,7 @@ export function createNodeGraphState(editor: Editor) {
|
||||||
/// The index is the exposed input index. The exports have a first key value of u32::MAX.
|
/// The index is the exposed input index. The exports have a first key value of u32::MAX.
|
||||||
wires: new Map<bigint, Map<number, WirePath>>(),
|
wires: new Map<bigint, Map<number, WirePath>>(),
|
||||||
wirePathInProgress: undefined as WirePath | undefined,
|
wirePathInProgress: undefined as WirePath | undefined,
|
||||||
nodeDescriptions: new Map<DefinitionIdentifier, string>(),
|
nodeDescriptions: new Map<string, string>(),
|
||||||
nodeTypes: [] as FrontendNodeType[],
|
nodeTypes: [] as FrontendNodeType[],
|
||||||
thumbnails: new Map<bigint, string>(),
|
thumbnails: new Map<bigint, string>(),
|
||||||
selected: [] as bigint[],
|
selected: [] as bigint[],
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue