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

rough out plugin-standalone logic #10672 #10678

Merged
merged 5 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
2 changes: 1 addition & 1 deletion arches/app/media/js/utils/create-vue-application.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Tooltip from 'primevue/tooltip';
import { createApp } from 'vue';
import { createGettext } from "vue3-gettext";

export default async function createVueApp(vueComponent){
export default async function createVueApplication(vueComponent){
chrabyrd marked this conversation as resolved.
Show resolved Hide resolved
/**
* This wrapper allows us to maintain a level of control inside arches-core
* over Vue apps. For instance this allows us to abstract i18n setup/config
Expand Down
15 changes: 15 additions & 0 deletions arches/app/media/js/views/plugin-standalone.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { defineAsyncComponent } from 'vue';
import createVueApplication from 'utils/create-vue-application';

const pluginData = require('views/plugin-data');

// workaround for webpack failures surrounding dynamic imports
const vuePluginPath = pluginData['component'].replace('src/', '').replace('.vue', '');
const AsyncComponent = defineAsyncComponent(() => import(`@/${vuePluginPath}.vue`));

const pluginMountingPoint = document.querySelector('#plugin-mounting-point');
pluginMountingPoint.setAttribute("id", pluginData['slug']);

createVueApplication(AsyncComponent).then(vueApp => {
vueApp.mount(`#${pluginData['slug']}`);
});
2 changes: 1 addition & 1 deletion arches/app/templates/base-manager.htm
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ <h1 class="brand-text" style="margin-top: 15px;">{{ app_name }}</h1>

{% for p in plugins %}
{% if p.config is not None %}
{% if p.config.show is not False %}
{% if p.config.show and not p.config.is_standalone %}
<!-- ko let: {uid: Math.random().toString()} -->
<li {% if main_script == "views/plugin" and plugin.pluginid == p.pluginid %} class="active-sub" {% endif %}>
{% if p.slug is not None %}
Expand Down
85 changes: 85 additions & 0 deletions arches/app/templates/views/plugin-standalone.htm
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<!--
ARCHES - a program developed to inventory and manage immovable cultural heritage.
Copyright (C) 2013 J. Paul Getty Trust and World Monuments Fund

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
{% load static %}
{% load webpack_static from webpack_loader %}


<!DOCTYPE html>
<!--[if IE 8]> <html lang="en" class="ie8"> <![endif]-->
<!--[if IE 9]> <html lang="en" class="ie9"> <![endif]-->
<!--[if !IE]><!--> <html lang="en"> <!--<![endif]-->

<head>
<title>
{% block title %} {{ app_settings.APP_NAME }} - {{ plugin.name }} {% endblock title %}
chrabyrd marked this conversation as resolved.
Show resolved Hide resolved
</title>

<!-- Meta -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">

<link rel="shortcut icon" href="{% webpack_static 'favicons/favicon.ico' %}" type="image/x-icon" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A nice to have would be to use the icon listed in the Plugin row as the favicon. But this can be a followup. And also depends on whether we add font awesome here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd caution against this for now. We'd need to remove support for using an .ico file and instead just drop a plain <i> tag in its place. Should be a good followup to allow users to upload a custom .ico defined in the Plugin db record.

<link rel="apple-touch-icon" href="{% webpack_static 'favicons/apple-touch-icon.png' %}" />
<link rel="apple-touch-icon" sizes="76x76" href="{% webpack_static 'favicons/apple-touch-icon-76x76.png' %}" />
<link rel="apple-touch-icon" sizes="120x120" href="{% webpack_static 'favicons/apple-touch-icon-120x120.png' %}" />
<link rel="apple-touch-icon" sizes="152x152" href="{% webpack_static 'favicons/apple-touch-icon-152x152.png' %}" />
<link rel="apple-touch-icon" sizes="180x180" href="{% webpack_static 'favicons/apple-touch-icon-180x180.png' %}" />

{% block css %}
<!-- POC rough out of PrimeVue theme switcher -->
chrabyrd marked this conversation as resolved.
Show resolved Hide resolved
<link rel="stylesheet" href="{% webpack_static 'node_modules/primevue/resources/themes/mdc-light-indigo/theme.css' %}" />
{% endblock css %}
</head>

<body>
{% block main_content %}
<div id="plugin-mounting-point"></div>
{% endblock main_content %}
</body>

{% block javascript %}
<script src="{% webpack_static 'node_modules/requirejs/require.js' %}"></script>

{% block pre_require_js %}
<div
id="pluginData"
style="display: none;"
pluginData='{{ plugin_json }}'
></div>
{% endblock pre_require_js %}

{% if main_script %}
<script src="{% webpack_static '' %}build/js/{{main_script}}.js"></script>
{% endif %}

{% if app_settings.GOOGLE_ANALYTICS_TRACKING_ID != None %}
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');

ga('create', '{{app_settings.GOOGLE_ANALYTICS_TRACKING_ID}}', 'auto');
ga('send', 'pageview');
</script>
{% endif %}
{% endblock javascript %}

</html>
14 changes: 13 additions & 1 deletion arches/app/views/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,25 @@ def get(self, request, pluginid=None, slug=None):
plugin = models.Plugin.objects.get(slug=slug)
else:
plugin = models.Plugin.objects.get(pk=pluginid)

if not request.user.has_perm("view_plugin", plugin):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a follow-up, we might want to expose this as a config option as well. If my vue app desires to handle login itself, currently, this will redirect you to the arches auth page unnecessarily.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed 👍

if slug is not None:
return redirect("/auth?next=/plugins/{}".format(slug))
if slug is not None:
return redirect("/auth?next=/plugins/{}".format(pluginid))
if request.GET.get("json", False):

if request.GET.get("json"):
return JSONResponse(plugin)

if plugin.config.get('is_standalone'):
chrabyrd marked this conversation as resolved.
Show resolved Hide resolved
context = self.get_context_data(
plugin=plugin,
plugin_json=JSONSerializer().serialize(plugin),
main_script="views/plugin-standalone",
)

return render(request, "views/plugin-standalone.htm", context)

resource_graphs = (
models.GraphModel.objects.exclude(pk=settings.SYSTEM_SETTINGS_RESOURCE_MODEL_ID)
.exclude(isresource=False)
Expand Down
6 changes: 4 additions & 2 deletions releases/7.6.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ Arches 7.6.0 Release Notes

### Major enhancements

An interface for contributing front-end features in Vue is now provided via the ``createVueApp()`` function. A minimal example is available in the [Arches Vue Integration Styleguide](https://github.com/archesproject/arches-docs/blob/master/docs/developing/vue/arches-vue-integration.md).
- An interface for contributing front-end features in Vue is now provided via the ``createVueApp()`` function. A minimal example is available in the [Arches Vue Integration Styleguide](https://github.com/archesproject/arches-docs/blob/master/docs/developing/vue/arches-vue-integration.md).

The ``createVueApp()`` function is experimental in 7.6. It currently registers all available ``PrimeVue`` services and directives, such as [toast (error messaging) plugins](https://primevue.org/toast/), [tooltip animations](https://primevue.org/tooltip/), and more. Over time, if some of these features do not see significant use in core Arches (or if registering them leads to a performance drag), they may be dropped from the ``createVueApp()`` wrapper. Implementers may always register any needed plugins/services in their own Vue applications. (Note: The vast majority of ``PrimeVue``'s functionality does not require these services or directives.)
- The ``createVueApp()`` function is experimental in 7.6. It currently registers all available ``PrimeVue`` services and directives, such as [toast (error messaging) plugins](https://primevue.org/toast/), [tooltip animations](https://primevue.org/tooltip/), and more. Over time, if some of these features do not see significant use in core Arches (or if registering them leads to a performance drag), they may be dropped from the ``createVueApp()`` wrapper. Implementers may always register any needed plugins/services in their own Vue applications. (Note: The vast majority of ``PrimeVue``'s functionality does not require these services or directives.)
chrabyrd marked this conversation as resolved.
Show resolved Hide resolved

- Plugins now support the configuration boolean `is_standalone`. Standalone plugins do not appear in the sidebar, and do not display the sidebar or application header.

### Performance Improvements

Expand Down