How can I display/reference external text in omnigraffle?


#1

Hi there!

I’m trying to work up an amalgamated network diagram of our environment.

One of the things I’m trying to do is to have the omnigraffle document display and continue to reference text documents which are updated externally from omnigraffle.
I have a disconnected mechanism which runs periodically and exports the current allocation/assignment of IPs into a markdown file per subnet.
These files are hierarchically adjacent to the OG document:

For explanation purposes, lets say:

  • The OG document’s filename is ‘diagram.graffle’
  • The OG document lives in a git repo ‘networkdiagram’
  • The subnets in question are 10.1.1/24, and 192.0.2/24.

networkdiagram/diagram.graffle
networkdiagram/10_1_1.md
networkdiagram/192_0_2.md

I would like to be able to display/view these markdown files in omnigraffle somehow when I’m looking at the network diagram, and have OG understand that it is displaying information that may be updated upstream and reflect any external changes automagically. When the OG document is saved I’m fine with it caching/containing a static/stale copy of that data, and ideally, when the OG document is opened, if there are changes to the md files, they would be consumed and the contents of whatever internal caches inside the OG document updated with the newer/canonical data… I don’t NEED to edit them from within omnigraffle. but it might be nice if that was a thing ¯_(ツ)_/¯

Have I explained the gist of what I’m trying to accomplish sufficiently?

if so:
How would I do this? :) :)
Is this a horrible idea for some reason that I’m not currently aware of?

Is there a better way to facilitate this general idea of enriching an OG document with data that is generated, owned, and managed elsewhere?


#2

You can use the Object Data fields in the Properties Inspector to associate metadata from your external text with the appropriate part of the diagram.graffle. That means that you’ll be able to see it when you hover over that item. You can use scripting to map the text to graphics either by graphic name or object IDs. The benefit of using the Object Data area is that you can have the text stored on the object and editable within OmniGraffle without the text being anywhere on the canvas. There is also Document Data in the Document inspector for storing information about the overall OmniGraffle file.

I would start simple, and rather than try to detect changes, just run the script to bring in the text from the file each time. If that starts to become slow, you could add a time/date stamp each time you run the script so that you’d know when it was last updated. You could also diff the text files and update only the changes.

While this is a good idea overall, you may have more early success in simpler diagrams. For example, if you have deeply nested groups, you have to iterate through all groups until there are no further groups to process those graphics. Tables have similar complexity which may present some scripting challenges. When I’m writing scripts, sometimes things as simple as locked objects and layers will get in my way, and I can either make my script more robust by accounting for all of those factors, or I can make my file simpler to keep my script shorter. OmniGraffle Pro supports AppleScript and OmniJS/JXA, so either of those languages can be used define Object Data. To see what you think of using Object Data, search stencils for Periodic Table. Drag out an element and choose Copy As either AppleScript or JavaScript, and you’ll see how the object data is defined. It’s a handy way to get a look at how the graphic information is stored for scripting. If you go for JavaScript, https://omni-automation.com is the best place to get started. If you go for AppleScript, open OmniGraffle’s scripting dictionary in Script Editor.

Your ideas sounds useful! It’s going to be easier to accomplish if you are already comfortable with writing scripts.

Thanks,
Lanette


#3

Hi Lanette,

I think our visions are slightly orthogonal.

I envision a layer, or a container, within which the content of an external file will be displayed.

IE: in one layer/canvas/whatever logical construct is appropriate there would be a diagram of what is where in the physical context of a server rack. (ala a visio rack diagram)

in another layer/canvas there would be a logical diagram of the interconnectedness of the various devices across the campus

and in additional layer(s?)/canvas(es?) there would be N containers, each container would display the content of an external file…

if the external file is updated while omnigraffle is not running, and then omnigraffle opens ‘diagram.graffle’ the content that has been updated would replace the content in the container inside layer inside the ‘diagram.graffle’ file.

Am I making sense?

am I crazy?

(granted, affirmative answers to those two questions are not mutually exclusive… :) but that’s a subject for a different conversation altogether )


#4

One approach might be to use an AppleScript snippet in the action of a shape, including an assignment of the contents of an external text file to

text of self

So, for example (full script below)

(note that the ~ can be expanded by code running in Script Editor, but not by code running in a shape action - there you will need to use a full file path)

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

-- readFile :: FilePath -> IO String
on readFile(strPath)
    set ca to current application
    set e to reference
    set {s, e} to (ca's NSString's ¬
        stringWithContentsOfFile:((ca's NSString's ¬
            stringWithString:strPath)'s ¬
            stringByStandardizingPath) ¬
            encoding:(ca's NSUTF8StringEncoding) |error|:(e))
    if e is missing value then
        s as string
    else
        (localizedDescription of e) as string
    end if
end readFile

on run {}
    -- readFile("~/Projects/notes2019-06-25.taskpaper") 
    set text of self to readFile("/Users/houthakker/Projects/notes2019-06-25.taskpaper")
end run

#5

oh, that’s an interesting approach!
Thank you @draft8!

If I understand correctly, the ‘action’ is fired when one clicks on the shape, right?
Do you know if there’s an ‘on graffle_document_opening’ hook that I might leverage?

this feels like it WOULD WORK, but still is a bit clunky, and contains a bit more voodoo than I’d reach for initially, but if there is NOT a better way, I’ll likely end up using something like this.

I’m just trying to find the most elegant / least error prone / simplest path… as the fewest moving parts is oft the best route to take IMHO… :)


#6

Yes, a script action requires a triggering click.

It might also be worth taking a look at LinkBack items

(see, in the OG7 manual under Using LinkBack to Embed Content from Another Application)