InvenTree icon indicating copy to clipboard operation
InvenTree copied to clipboard

[FR] 3D Model Viewer

Open RedEchidnaUK opened this issue 1 year ago • 34 comments

Please verify that this feature request has NOT been suggested before.

  • [x] I checked and didn't find a similar feature request

Problem statement

It would be really nice to be able to view 3D models that are attached to parts.

Suggested solution

Option 1

Under attachments you could click the more actions and if the attachment was a supported 3D file you could choose the option to view it in a 3D viewer. Once in the viewer you could then take a 'capture' of the current view and set it as the part image.

Option 2

In the main part view you could upload a 3D model instead of a static image. You could then click on the image to open a 3D model viewer, rotate/manipulate the model to your liking and then 'capture' the current view and set it as the part image.

Describe alternatives you've considered

Not having a 3D viewer :)

Examples of other systems

I have found the Online3DViewer project that should aid in developing a solution. Although I'm not a frontend developer (or even a professional developer) it didn't look too difficult to implement (easy to say I know) in a webpage. They even give their whole site as part of the source files.

If I had time I might even look at adding it myself, but currently I have too many unfinished projects and I don't want to commit to another one. I don't think this would be a high priority feature, but it would be nice to have.

Do you want to develop this?

  • [ ] I want to develop this.

RedEchidnaUK avatar Jan 02 '25 19:01 RedEchidnaUK

This would be an ideal candidate to be developed as a plugin. @RedEchidnaUK would this be something you would be interested in developing?

SchrodingersGat avatar Jan 02 '25 20:01 SchrodingersGat

@SchrodingersGat I’m going to reluctantly say no to developing a plugin. Sadly, I really don’t have time at the moment due to other projects I’m committed to. Of course if that changes, I’ll be sure to let you know.

RedEchidnaUK avatar Jan 02 '25 21:01 RedEchidnaUK

@SchrodingersGat It would be really cool, if we would extend the plugin system to provide custom previewers for various file types. E.g. this would be helpful for your wirewiz plugin too, or an inline pdf previewer, ...

wolflu05 avatar Jan 02 '25 22:01 wolflu05

Having done a bit more searching I see there is already a FR for preview for attachment files that I missed in my previous search. Would it make more sense that this request is part of that FR?

RedEchidnaUK avatar Jan 03 '25 12:01 RedEchidnaUK

I do not think that would cover it, that will probably be addressed by making thumbnails available

matmair avatar Jan 03 '25 16:01 matmair

Just to update this, I’ve had a bit of free time and I’ve had a bit of a play about and I think I might be able to create a plugin to preview certain 3D CAD files.

I’ve no idea how long it will take me as I’m not very familiar with React and Typescript etc. and a 3D viewer is probably quite an ambitious thing to start with… I have also found out that the viewer I linked above is so poorly documented it’s almost impossible to work with for a newcomer. However, I still have a plan and a very basic proof of concept working, so there is still hope!

One question I do have, which version of React does Inventree use? It looks like React 18.3.1 from looking at the frontend package.json and the plugin creator seems to specify 18.3.18 in its package.json. However, I somehow ended up with React 19 when I used the creator? This could be (probably is) something I’ve inadvertently done.

RedEchidnaUK avatar Feb 17 '25 20:02 RedEchidnaUK

@RedEchidnaUK good point regarding react version - the plugin creator should be pinned to use the same version! I'll look into this, likely a bug with the creator itself.

https://github.com/inventree/plugin-creator/issues/26

SchrodingersGat avatar Feb 18 '25 00:02 SchrodingersGat

I’m getting close to having something working, but I have a question I’m hoping you can help with.

At some point I’m going to want to get a list of the attachments of the part and send them to my React component. This seems simple enough, but if I want my React component to send data back, such as a new image for the part, how would I go about it?

I thought I would just use the API directly, but from what I’ve read the user would have to sign in again to get an access token, which doesn’t seem great from a UX point. I’m probably looking at the problem wrong, and apologies if it seems simple, but I’m really not used to working with web based apps. If I’ve missed some documentation, feel free to point me at it. Thanks.

RedEchidnaUK avatar Feb 23 '25 15:02 RedEchidnaUK

@RedEchidnaUK great question! The front-end plugins get passed a lot of context data - including the currently active API object which is already authenticated against the server.

You can use this API object to make requests to the server without any other auth interactions with the user.

Check out how the inventree-order-history plugin achieves this, for example:

https://github.com/inventree/inventree-order-history/blob/2f8287254283cd87a7e5fb45c91c5954b3405f4a/frontend/src/OrderHistoryPanel.tsx#L223

    const historyQuery = useQuery(
        {
            queryKey: [
                'order-history',
                startDate,
                endDate,
                period,
                orderType,
                context.id,
                context.model,
            ],
            refetchOnMount: false,
            refetchOnWindowFocus: false,
            queryFn: async () => {
                return context.api?.get(`/${ORDER_HISTORY_URL}`, {
                    params: queryParams,
                }).then((response: any) => {
                    return response.data;
                }).catch(() => {
                    return [];
                }) ?? [];
            }
        },
        queryClient
    )

SchrodingersGat avatar Feb 24 '25 05:02 SchrodingersGat

@SchrodingersGat thank you for the detailed answer. I had looked at a few plugins, but had completely missed that nugget of information. That should give me everything I need. Thanks for the help.

RedEchidnaUK avatar Feb 24 '25 06:02 RedEchidnaUK

If you find any details that would be good to include in the docs please submit a PR to the documentation :)

SchrodingersGat avatar Feb 24 '25 06:02 SchrodingersGat

What I think would be nice, from a documentation point of view, is a walkthrough of developing a simple plugin. Using the generator, create a panel plugin example, get information via the api, display the information, push data/a file back, how to enable support for light/dark mode etc.

I fully appreciate as developers this might not be the best use of your time, especially as I know you’re working really hard to get to 1.0.0. and documentation is the least fun part. Perhaps if I ever get to a point where I can do all of those things and no one has beaten me to it, I’ll give it a go and do a PR.

RedEchidnaUK avatar Feb 24 '25 16:02 RedEchidnaUK

@RedEchidnaUK a "plugin development guide" has been on my wishlist for some time. But, only so many hours in the day! If you do find some time to add something to this effect, it would be greatly appreciated!

SchrodingersGat avatar Feb 25 '25 02:02 SchrodingersGat

Getting ever closer to a beta release as I now have a basic, but functional, 3D viewer with controls and a panel with an API call working. I just need to marry the two together when I get time (@SchrodingersGat I know what you mean about only so many hours in the day!) One thing I’m not sure on, is how to get the base url of the site to combine with the returned attachment url. Unless I’m wrong, the API doesn’t seem to provide it. Any hints on where I’ve missed it would be much appreciated.

Edit: Sorry, I think you can ignore this question, it’s in the context RTFM! (I’m sure it wasn’t there earlier…)

RedEchidnaUK avatar Mar 02 '25 20:03 RedEchidnaUK

Hopefully this will be the last question for a while (no promises 😄 ), and again apologies if it's stated somewhere and I've missed it.

It looks like you can get the base url from context, e.g.

console.log("BaseUrl: ",context.globalSettings.getSetting("INVENTREE_BASE_URL"));

However, I've noticed you can also get the host from context, e.g.

console.log("Host: ",context.host);

I'm guessing these are two different things? If they are, when would you use one over the other?

Thanks.

RedEchidnaUK avatar Mar 03 '25 19:03 RedEchidnaUK

They are subtly different but I think for most purposes they should be the same.

  • INVENTREE_BASE_URL is the server's view of what it's URL is
  • 'host' is the client's address to connect to the host

Nominally they should be the same

SchrodingersGat avatar Mar 05 '25 03:03 SchrodingersGat

Thanks @SchrodingersGat

RedEchidnaUK avatar Mar 05 '25 07:03 RedEchidnaUK

@SchrodingersGat At the chance of out staying my welcome...

How would I get all of the attachments for a part from the Python backend? I can successfully do it via the API on the frontend, but it feels like that might not be the correct way on the backend. I've tried reading about mixins etc. as well as looking at the documentation and source code, but I'm not that experienced with Python (or at least not in the context Inventree uses it) and I'm probably more confused than when I started... Any pointers, once again, gratefully received.

RedEchidnaUK avatar Mar 07 '25 20:03 RedEchidnaUK

I'll assume that you have the part instance available (i.e. the single part that the user is viewing).

so in python (server side) you can simply call:

attachments = part.attachments

This is because the Part Model inherits from the InvenTreeAttachmentMixin class which provides the attachments property

SchrodingersGat avatar Mar 10 '25 10:03 SchrodingersGat

Once again, thanks @SchrodingersGat That is a lot easier than I was expecting. I’ll try and give it a go tonight!

RedEchidnaUK avatar Mar 10 '25 13:03 RedEchidnaUK

I've finally had time to get it to a point that is good enough for a beta release! https://github.com/RedEchidnaUK/inventree-3d-viewer

Known issues

  • It only supports STL and GLB files (the core engine is capable of supporting many more formats)
  • It has to be built and installed via the plugins docker folder (that's how I've been working with it and I'm not yet up to speed on the other install methods)
  • I have witnessed it causing the Inventree browser tab to slow to a crawl and become unusable until the tab is refreshed (even when not on the part/plugin panel). I've only seen it happen in the Ubuntu VM I develop in, so it could be an issue with the VM and its virtual graphics card. If anyone else sees this behaviour please let me know. I've no idea where to begin to fix it, but at least I will know it's not just a one off.

RedEchidnaUK avatar Mar 15 '25 14:03 RedEchidnaUK

This looks pretty interesting. Thank you for creating such a plugin. I wonder if me may create a new frontend feature that is specific for attachment preview so that we don't have to add lots of panels for each type. That way we may could add a click on an attachment row in the existing panel, that opens a modal with a preview provided by a plugin. This could then be implemented for pdfs, images, kicad files (I think there was a js rendering engine developed as OSS a while ago), wirewiz, ... I think I already explained that idea in an issue before.

wolflu05 avatar Mar 15 '25 20:03 wolflu05

@RedEchidnaUK that looks awesome! Very nice work indeed. When you are ready for "release" we can add it to the inventree website for visibility.

that's how I've been working with it and I'm not yet up to speed on the other install methods

Releasing to pypi is pretty straight forward with the plugin creator. Happy to help walk you through that process if you like!

I have witnessed it causing the Inventree browser tab to slow to a crawl and become unusable until the tab is refreshed (even when not on the part/plugin panel)

I would be interested to see if this is due to rendering (on the frontend) or if it takes a long time to process the plugin panel request (backend).

SchrodingersGat avatar Mar 15 '25 22:03 SchrodingersGat

This looks pretty interesting. Thank you for creating such a plugin. I wonder if me may create a new frontend feature that is specific for attachment preview so that we don't have to add lots of panels for each type. That way we may could add a click on an attachment row in the existing panel, that opens a modal with a preview provided by a plugin. This could then be implemented for pdfs, images, kicad files (I think there was a js rendering engine developed as OSS a while ago), wirewiz, ... I think I already explained that idea in an issue before.

I agree that this concept would be best served as a "preview" panel pop-out from the "attachments" page. Rather than a separate main panel. @wolflu05 do you want to look into developing a new frontend UI feature type if you have time?

It would be reasonably easy to migrate the functionality of this plugin to the preview pane once available.

SchrodingersGat avatar Mar 15 '25 22:03 SchrodingersGat

Unfortunately, I won’t have time to develop this in the next months and its not my priority. I'd be happy if someone else has the time to develop this new frontend UI feature integration.

wolflu05 avatar Mar 16 '25 07:03 wolflu05

@wolflu05 and @SchrodingersGat thank you for the support and encouragement.

I agree, it would be awesome to have it as part of a 'preview' system directly in the attachment panel as that would open up so many file preview options. Sadly at this stage, it's probably beyond my knowledge to make those sorts of changes to Inventree.

@SchrodingersGat Thank you for the offer of assistance for PyPi once I get to release.

The thing that's holding me back making an official release at the moment is this slowdown issue. My gut is telling me it is a frontend issue and I only really see it from within my VM. If I browse the VM hosted instance from an external browser it almost works 100%. Inventree doesn't seem to suffer with slowdowns, but the 3D model drops frames when you start rotating/zooming... but then that only happens when you open another part, the first load is fine... very odd.

RedEchidnaUK avatar Mar 16 '25 13:03 RedEchidnaUK

You may want to test if you only experience this error in dev mode or also in a react production build.

wolflu05 avatar Mar 16 '25 16:03 wolflu05

@wolflu05 Sorry, I probably should have been clearer. I’m doing the development work in a VM, but Inventree is running as a production Docker environment, so it is a production build. I do need to see if I get the same issue running just as a React build outside of Inventree.

RedEchidnaUK avatar Mar 16 '25 17:03 RedEchidnaUK

So your not using the react dev server for your plugin panel at all? You're always build a react prod bundle and then see the changes after manually reloading the page?

@SchrodingersGat Is that not implemented in the plugin template? (React HMR directly inside the plugin panel) That was the first thing I setup on my plugins (haven't used the plugin creator yet).

wolflu05 avatar Mar 16 '25 17:03 wolflu05

@wolflu05 Correct. It’s not a very efficient way to work and I really should get the dev environment up and running properly. Most of the panel work was actually done outside of Inventree and then simple ported over to a plugin panel. As all the React code needs are the attachment urls from Inventree, which I do via the context.

RedEchidnaUK avatar Mar 16 '25 17:03 RedEchidnaUK