2
0
mirror of https://github.com/inventree/inventree-website.git synced 2025-04-28 05:26:44 +00:00

Merge pull request #110 from matmair/matmair/issue94

Add plugin repo
This commit is contained in:
Oliver 2023-01-29 13:00:49 +11:00 committed by GitHub
commit 2205999494
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 340 additions and 115 deletions

View File

@ -4,17 +4,41 @@ It is built on Jekyll and GitHub pages for backend / hosting, tailtwindcss for d
[![Netlify Status](https://api.netlify.com/api/v1/badges/f84340d0-bc2f-4f7f-ad4c-877c50b33a27/deploy-status)](https://app.netlify.com/sites/inventree-org-preview/deploys) [![Netlify Status](https://api.netlify.com/api/v1/badges/f84340d0-bc2f-4f7f-ad4c-877c50b33a27/deploy-status)](https://app.netlify.com/sites/inventree-org-preview/deploys)
## Architecture ## Adding a plugin to the list
The website consists of content, layouts and assets. Jekyll runs and builds out of these files static html files - that are then hosted on GitHub pages. Folders with an underscore prefixed are internal folders for Jekyll, folders without are rendered as subdirectories in the output. Any maintainer of a plugin can add their plugin to the list. The plugin will be listed on the website, we might provide a mechanism to discover plugins from within InvenTree in the future.
Content: To add a plugin the following steps are required:
- Fork the repository
- Create a new branch. We recommend `plugin/<plugin-name>` as the branch name.
- Create a new file in `_repo`. We recommend using the package name as the file name.
- Copy the content from `_repo/template.md` into the new file.
- Fill out the details. Please make sure to use the correct format for the fields.
- If this is your first contribution to the list, please add yourself to the `_publishers` folder.
- Use your GitHub username as the file name.
- Copy the content from `_publishers/_template.md` into the new file.
- Fill out the details. Please make sure to use the correct format for the fields.
- Commit your changes and create a pull request. We recommend using the title `[REPO] Add plugin <plugin-name>`.
Please note that the plugin list is moderated as we see fit and we reserve the right to reject plugins that do not meet basic quality standards. We will try to provide feedback in the pull request if that is the case.
As a maintainer of a plugin we count on you to keep the information up to date. If you want to update the information, please create a pull request.
The plugin list is just getting started as a static collection, we might enhance the features in the future. If we need more information or make significant changes to the list, we will ping the maintainers via their GitHub handle - so please keep your main GitHub handle up to date in your publisher file.
## Architecture and development
The website consists of content, layouts and assets. Jekyll runs and builds out of these files static html files - that are then hosted on GitHub pages.
### Folders and files
Folders with an underscore prefixed are internal folders for Jekyll, folders without are rendered as subdirectories in the output.
Structure:
`_data` contains data that is references on pages `_data` contains data that is references on pages
`_drafts` contains drafts for blog pages and news items `_drafts` contains drafts for blog pages and news items
`_news` contains news entries `_news` contains news entries
`_posts` contains blog entries `_posts` contains blog entries
`_publishers` contains authors/publishers `_publishers` contains authors/publishers of blog entries, news items and plugins
`_repo` will contain plugin repo entries `_repo` contains plugin repo entries
Layouts: Layouts:
`_includes` contains partials that can be used in layouts `_includes` contains partials that can be used in layouts
@ -27,9 +51,16 @@ The site configuration is saved in `config.yaml`, required gems in `Gemfile` and
The CSS stylesheet uses tailwindcss and is built with postcss on demand. NodeJs is needed for this. The main css file is located in `assets/index.css`. Rebuilds are handled by the workflows automatically. The CSS stylesheet uses tailwindcss and is built with postcss on demand. NodeJs is needed for this. The main css file is located in `assets/index.css`. Rebuilds are handled by the workflows automatically.
## Common commands ### Preview builds
Once a PR is created, a preview build is created on Netlify. The preview build is available at `https://<pr-number>-inventree-org-preview.netlify.app/`. The preview build is automatically updated when the PR is updated.
A bot will comment on the PR with the link to the preview build.
### Common commands for local development
Install packages for ruby and nodejs. Install packages for ruby and nodejs.
```
```bash
sudo apt-get install rubygems ruby-dev nodejs npm sudo apt-get install rubygems ruby-dev nodejs npm
npm install npm install
sudo gem install bundler sudo gem install bundler
@ -37,16 +68,13 @@ bundle install
``` ```
Build site locally Build site locally
```
```bash
bundle exec jekyll build bundle exec jekyll build
``` ```
Run debug server Run debug server that automatically updates. This does not recompile the tailwindcss stylesheet. If you change something in the css file, you neet to build the site fully with the command above.
```
```bash
bundle exec jekyll serve --incremental bundle exec jekyll serve --incremental
``` ```
Regenerate file structure
```
tree -I '_site|.git|.jekyll-cache|node_modules' --dirsfirst
```

View File

@ -13,10 +13,6 @@ deploy-link:
internal: deploy.md internal: deploy.md
blog-link: blog-link:
internal: blog.html internal: blog.html
plugin-link:
internal: plugins.html
contribute-link:
internal: contribute.md
# Hosting parameters # Hosting parameters
baseurl: "" baseurl: ""
@ -33,8 +29,7 @@ collections:
permalink: "/:title" permalink: "/:title"
repo: repo:
output: true output: true
custom_permalink_placeholders: ["publisher"] permalink: ":doc_author/:title"
#permalink: "/:publisher/:title"
news: news:
output: true output: true
permalink: /news/:year/:month/:day/:title permalink: /news/:year/:month/:day/:title

View File

@ -8,6 +8,8 @@
site: doc-link site: doc-link
- name: News - name: News
internal: news.html internal: news.html
- name: Plugin List
internal: plugins.html
- title: Ecosystem - title: Ecosystem
link: link:

View File

@ -0,0 +1,19 @@
<section class="cm-gray-2 body-font">
<div class="section-container">
<div class="flex flex-col text-center w-full mb-5">
<h1 class="text-2xl font-medium title-font mb-4 cm-gray-1 tracking-widest">Plugin List</h1>
<p>
Explore plugins provided by the community.
<a class="text-secondary inline-flex items-center" href="{% link plugins.html %}" alt="learn more">Learn More <img class="w-4 h-4 ml-2" alt="Arrow pointing right" src="{{ '/assets/learn.svg' | relative_url }}" /></a>
</p>
</div>
<div class="flex flex-wrap -m-4">
{% assign filtered_repo = site.repo | sort: 'last-modified-date' | reverse %}
{% for plugin in filtered_repo limit:2 %}
<div class="space-4 p-2 md:w-1/2">
{% include plugin_card.html plugin=plugin %}
</div>
{% endfor %}
</div>
</div>
</section>

View File

@ -1,20 +1,20 @@
<a href="{{ plugin.url | relative_url }}" class="no-underline" aria-label="open plugin details">
<div class="row g-0 border rounded overflow-hidden flex-md-row mb-4 shadow-sm h-md-250 position-relative"> <div class="row g-0 border rounded overflow-hidden flex-md-row mb-4 shadow-sm h-md-250 position-relative">
<div class="col p-4 d-flex flex-column position-static"> <div class="col p-4 d-flex flex-column position-static">
<div class="d-inline-block"> <div class="d-inline-block leading-loose">
{% for cat in plugin.categories %} {% for cat in plugin.categories %}
<span class="badge bg-yellow-500">{{ cat }}</span> <span class="plugin_cat">{{ cat }}</span>
{% endfor %} {% endfor %}
{% for tag in plugin.tags %} {% for tag in plugin.tags %}
<span class="badge bg-blue-400">{{ tag }}</span> <span class="plugin_tag">{{ tag }}</span>
{% endfor %} {% endfor %}
</div> </div>
<h3 class="mb-0">{{ plugin.name }}</h3> <h3 class="my-0">{{ plugin.name }}</h3>
<div class="mb-1 text-muted"> <div class="mb-1 text-muted">
{% if plugin.published_on %}{{ plugin.published_on | date_to_string }} - {% endif %} {% if plugin.published_on %}{{ plugin.published_on | date_to_string }} - {% endif %}
{% include partial/publisher_ref.html pub=plugin.publisher %} {% include partial/publisher_ref.html pub=plugin.author %}
</div> </div>
<p class="mb-auto">{{ plugin.excerpt | mardownify | remove: '<p>' | remove: '</p>' }}</p> <p class="my-0">{{ plugin.excerpt | mardownify | remove: '<p>' | remove: '</p>' }}</p>
<a href="{{ plugin.url | relative_url }}" class="stretched-link" aria-label="open plugin details"></a>
</div> </div>
</div> </div>
</a>

View File

@ -0,0 +1,53 @@
---
layout: default
---
<div class="pt-3 pb-1 section-container">
<h1 class="header-text title-font mb-4 cm-gray-1">{{page.title}}</h1>
<span class="content">
{% assign all_items = "" | split: "/" %}
{% for col_item in site[page.collection] %}
{% for item in col_item[page.reference] %}
{% assign preprocessed = item | strip %}
{% unless preprocessed == "" %}
{% assign all_items = all_items | push: preprocessed %}
{% endunless %}
{% endfor %}
{% endfor %}
{% assign all_items = all_items | uniq | sort %}
<p>The full list of plugins is available on the main <a href="{% link plugins.html %}">plugin list</a> page.</p><br>
<p class="mb-0 italic">Click on a name to jump to the plugins that are marked with it.</p>
<i class="fa fa-tag"></i>
{% for item in all_items %}
{% unless tag == "" %}
<a class="label" href="{{ page.permalink | prepend: site.baseurl }}#{{ item | slugify }}">
<span class="badge">{{ item }}</span>
</a>
{% endunless %}
{% endfor %}
</span>
<br><br>
{% for item in all_items %}
{% unless item == "" %}
<div id="{{ item | slugify }}" class="anchor"></div>
<h2 class="text-lg sm:text-xl cm-gray-1 font-medium title-font mb-2">{{ item }}</h2>
<div class="flex flex-wrap">
{% for plugin in site[page.collection] %}
{% assign col_items = "" | split: "/" %}
{% for item in plugin[page.reference] %}
{% assign lower_item = item %}
{% assign col_items = col_items | push: lower_item %}
{% endfor %}
{% if col_items contains item %}
<div class="space-4 p-2 md:w-1/2">{% include plugin_card.html plugin=plugin %}</div>
{% endif %}
{% endfor %}
</div>
{% endunless %}
{% endfor %}
</div></div>

View File

@ -4,48 +4,86 @@ notitle: true
fullwith: true fullwith: true
--- ---
<h2>{{ page.name }} <h2>{{ page.name }}
<span class="sm:ml-2 text-sm">{% include partial/publisher_ref.html pub=page.publisher %}</span> <span class="sm:ml-2 text-sm">{% include partial/publisher_ref.html pub=page.author %}</span>
<span class="sm:ml-2 text-sm">last modified: {{ page.last-modified-date | date_to_string }}</span>
</h2> </h2>
<div class="md:flex md:flex-row flex-wrap"> <div class="flex-wrap md:flex md:flex-nowrap">
<div class="w-full md:w-3/4"> <div class="w-full md:w-auto md:mr-4">
{{ content }} {{ content }}
</div> </div>
<div class="w-full md:w-1/4"> <div class="w-full md:w-1/4">
<h2 class="block sm:hidden">Link section</h2> <h2 class="block sm:hidden">Detail section</h2>
<div> <div>
<p class="mb-0">License:
<div> {% if page.open_source %}<i class="fa-brands fa-osi"></i>{% else %}<i class="fa-solid fa-lock"></i>{% endif %}
<h4 class="fst-italic">Github</h4> {{ page.license }}<br>
<p>{{ page.github | remove: "https://github.com/" }}</p> <div class="flex flex-wrap">
<a href="{{ page.github }}" class="stretched-link" aria-label="open github repo"></a> Status:
<div>{% if page.stable %}<i class="fa-regular fa-circle-check"></i>Stable{% else %}<i class="fa-solid fa-triangle-exclamation"></i> Unstable{% endif %}</div>
<div>{% if page.maintained %}<i class="fa-regular fa-circle-check"></i>Maintained{% else %}<i class="fa-solid fa-circle-exclamation"></i> Unmaintained{% endif %}</div>
</div> </div>
{% if page.pypi and page.package_name %}Package on PyPI:<pre class="my-0">{{ page.package_name }}</pre>{% endif %}
</p>
<a href="{{ page.website }}" class="no-underline" aria-label="open website">
<div>
<h4 class="plugin_links">Website <i class="fa-solid fa-arrow-up-right-from-square" title="External link"></i></h4>
<p class="font-normal">{{ page.website }}</p>
</div>
</a>
{% if page.issue_tracker %}
<a href="{{ page.issue_tracker }}" class="no-underline" aria-label="open the issue tracker">
<div>
<h4 class="plugin_links">Issue Tracker <i class="fa-solid fa-arrow-up-right-from-square" title="External link"></i></h4>
</div>
</a>
{% endif %}
{% if page.github %}
<a href="{{ page.github }}" class="no-underline" aria-label="open source on GitHub">
<div>
<h4 class="plugin_links">Sourcecode on GitHub <i class="fa-solid fa-arrow-up-right-from-square" title="External link"></i></h4>
<p class="font-normal">{{ page.github | remove: "https://github.com/" }}</p>
</div>
</a>
{% endif %}
{% if page.gitlab %}
<a href="{{ page.gitlab }}" class="no-underline" aria-label="open source on Gitlab">
<div>
<h4 class="plugin_links">Sourcecode on Gitlab <i class="fa-solid fa-arrow-up-right-from-square" title="External link"></i></h4>
<p class="font-normal">{{ page.gitlab | remove: "https://gitlab.com/" }}</p>
</div>
</a>
{% endif %}
{% if page.source %}
<a href="{{ page.source }}" class="no-underline" aria-label="open source on SCM">
<div>
<h4 class="plugin_links">Sourcecode on SCM <i class="fa-solid fa-arrow-up-right-from-square" title="External link"></i></h4>
<p class="font-normal">{{ page.source }}</p>
</div>
</a>
{% endif %}
<div> <div>
<h4 class="fst-italic">Categories</h4> <h4 class="plugin_links">Categories</h4>
<ol class="list-unstyled"> <div>
{% for categorie in page.categories %} {% for categorie in page.categories %}
<li><a href="/categories/#{{ categorie | slugify }}"><span class="badge bg-yellow-500">{{ categorie }}</span></a></li> <a href="{% link categories.html %}#{{ categorie | slugify }}"><span class="plugin_cat">{{ categorie }}</span></a>
{% endfor %} {% endfor %}
</ol> </div>
</div> </div>
<div> <div>
<h4 class="fst-italic">Tags</h4> <h4 class="plugin_links">Tags</h4>
<ol class="list-unstyled"> <div>
{% for tag in page.tags %} {% for tag in page.tags %}
<li><a href="/tags/#{{ tag | slugify }}"><span class="badge bg-blue-400">{{ tag }}</span></a></li> <a href="{% link tags.html %}#{{ tag | slugify }}"><span class="plugin_tag">{{ tag }}</span></a>
{% endfor %} {% endfor %}
</ol> </div>
</div> </div>
<div>
<h4 class="fst-italic">Website</h4>
<p>{{ page.website }}</p>
<a href="{{ page.website }}" class="stretched-link" aria-label="open website"></a>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,11 +0,0 @@
---
layout: content
---
<article>
{{ content }}
{% if page.plugin %}
<hr>
<p>Find out more about this plugin on the plugin site</p>
{% include plugin_card.html plugin=page.plugin %}
{% endif %}
</article>

View File

@ -0,0 +1,9 @@
module Jekyll
module Drops
class UrlDrop < Drop
def doc_author
@obj.data['author']
end
end
end
end

View File

@ -0,0 +1,22 @@
# see https://stackoverflow.com/a/36769049/17860466
Jekyll::Hooks.register :posts, :pre_render do |post|
# get the current post last modified time
modification_time = File.mtime( post.path )
# inject modification_time in post's datas.
post.data['last-modified-date'] = modification_time
end
Jekyll::Hooks.register :repo, :pre_render do |repo|
# get the current post last modified time
modification_time = File.mtime( repo.path )
# inject modification_time in post's datas.
repo.data['last-modified-date'] = modification_time
end

7
_publishers/_template.md Normal file
View File

@ -0,0 +1,7 @@
---
short_name: octocat # GitHub username - must be the same as the filename
name: The Octocat # The name/alias/whatever you want to be displayed
github: octocat # Your GitHub username - if you switch to a new account, please update this
website: https://github.blog/ # Your website, twitter, reddit - optional
---
A cool tagline # A tagline or motivation, optional - please keep it under 200 words

21
_repo/_template.md Normal file
View File

@ -0,0 +1,21 @@
---
name: inventree-brother-plugin # Name of the plugin (should be either NAME, TITLE or SLUG)
author: schrodingersgat # Maintainer must be the same as the publisher reference
license: MIT # License, we prefer open source
open_source: true # Is this project licensed with an OSI-approved license - aka 'open source'
stable: true # Is this project stable? Should users deploy this in their instace?
maintained: true # Is this project maintained?
pypi: true # Is availanle via PyPi
package_name: inventree-brother-plugin # Name of the package on the index, required if pypi true
github: https://github.com/inventree/inventree-brother-plugin # Ĺink to repo in GitHub, one of github, gitlab or source is required
gitlab: https://gitlab.com/inventree/inventree-brother-plugin # Ĺink to repo in Gitlab, one of github, gitlab or source is required
source: https://example.com/inventree/inventree-brother-plugin # Link to source, one of github, gitlab or source is required
issue_tracker: https://github.com/inventree/inventree-brother-plugin/issues # Link to Issue tracker, optional
website: https://inventree.org # Website, full path with protocol, optional
categories: # Mixins/integrations that are used, optional
- Label
tags: # Freetext tags - treat them like kewords, optional
- Brother
- Printer
---
Description text for the plugin goes here. Markdown is supported. You could just reuse the README.md file from your repo.

View File

@ -0,0 +1,38 @@
---
name: InvenTree Apprise
author: matmair
license: MIT
open_source: true
stable: true
maintained: true
pypi: true
package_name: inventree-apprise
github: https://github.com/matmair/inventree-apprise
issue_tracker: https://github.com/matmair/inventree-apprise/issues
website: https://mjmair.com
categories:
- Notifications
tags:
- Apprise
- 3rd party integration
- Discord
- IFTTT
- Matrix
- Microsoft Teams
- Slack
- Twilio
-
---
Send notifications from InvenTree via Apprise
## Setup
1. Install this plugin in the webinterface with the packagename `inventree-apprise`
1. Enable the plugin in the plugin settings. You need to be signed in as a superuser for this.
**The server will restart if you enable the plugin**
1. Add all endpoints you want to use in the plugin settings. You can use the [Apprise URL Syntax](https://github.com/caronc/apprise#supported-notifications).
## License
This project is licensed as MIT. Copy and do what you want - maybe tag your new plugin so others can find it. The more the merrier.

View File

@ -1,41 +0,0 @@
---
name: ShopifyIntegrationPlugin org
author: matmair
website: https://mjmair.com
github: https://github.com/matmair/ShopifyIntegrationPlugin
categories:
- Integration
- Webhook
tags:
- Shopify
- Orders
---
A simple Integration into Shopify.
Let your orders from Shopify be created in autopilot, update your Inventory-Levels from InvenTree and vice-versa.
## Installation
1. Navigate to your InvenTree directory and cd into `src/InvenTree/plugins` and execute `git submodule add https://github.com/matmair/ShopifyIntegrationPlugin` there. Enable plugins in the general plugin settings and reload InvenTree.
2. Add a private app to your Shopify store (please register as a dev and use a development store. This is a PoC)
3. Go to the InvenTree settings and fill in the settings for the ShopifyIntegrationPlugin from your new private app.
4. Check out the new navigation tab.
## Caveat
Your instance must be reachable for webhooks from Shopify so use ngrok or something like that to expose your instance with HTTPS.
## State of the code
This code is bad. It is neither optimized nor is it CI/Cd ready or covered in any way.
I use this Plugin as a PoC to show what will be possible with the new system.
## Contribute
The whole plugin system is currently not even in the dev branch.
Feel free to submit issues or just send me a mail to dev AT mjmair.com
## No open source?
Currently I have defined no license so forking is a bad idea copyright-wise. This code should not be used as basis for anything - I will define a license once the plugin system gets released.

View File

@ -59,6 +59,12 @@ layout: empty
visibility: hidden; visibility: hidden;
} }
.content a {
color:#111827;
font-weight:500;
text-decoration:underline;
}
.color-link { .color-link {
@apply text-secondary @apply text-secondary
} }
@ -79,6 +85,14 @@ layout: empty
@apply list-none @apply list-none
} }
.plugin_cat {
@apply badge bg-yellow-500 whitespace-nowrap
}
.plugin_tag {
@apply badge bg-blue-400 whitespace-nowrap
}
.max-w-p90 { .max-w-p90 {
max-width: 90% max-width: 90%
} }
@ -87,4 +101,15 @@ layout: empty
display: block; display: block;
text-align: center; text-align: center;
} }
.plugin_links {
@apply mb-0 italic
}
.anchor {
display: block;
position: relative;
top: -4.5rem;
visibility: hidden;
}
} }

7
categories.html Normal file
View File

@ -0,0 +1,7 @@
---
layout: collection/collection_refpage
title: Plugins by Category
collection: repo
permalink: /plugins/categories/
reference: categories
---

View File

@ -11,12 +11,9 @@ You can read more about the plugin architecture, including information on develo
Add *native printing capabilities* for your network connected printers to the webinterface and apps. There are plugins for: Add *native printing capabilities* for your network connected printers to the webinterface and apps. There are plugins for:
- [Brother QL](https://pypi.org/project/inventree-brother-plugin/) - [Brother QL](https://pypi.org/project/inventree-brother-plugin/)
- [Zebra](https://github.com/SergeoLacruz/inventree-zebra-plugin) - [Zebra](https://github.com/SergeoLacruz/inventree-zebra-plugin)
- [Cups](https://github.com/wolflu05/inventree-cups-plugin)
### Plugin repo ### Plugin repo
{% include partial/alert.html You can find all tagged plugins on [PyPi](https://pypi.org/search/?q=inventree-plugin) and [GitHub](https://github.com/topics/inventreeplugins).
style='info'
title='Coming soon' We also offer a [plugin repo](../../plugins.html) with a community driven list of plugins. We encourage you to add your own plugins.
desc="We are working on a full plugin repo - keep up to date on the blog or directly in your InvenTree dashboard with news."
%}

View File

@ -22,3 +22,4 @@ main_page: True
{% include block/cta.html cta=site.data.ctas.end %} {% include block/cta.html cta=site.data.ctas.end %}
{% include block/plugins.html %}

View File

@ -1,14 +1,22 @@
--- ---
layout: default layout: default
title: Plugins title: Plugin List
permalink: /plugins permalink: /plugins
--- ---
<div class="pt-3 pb-1 section-container"> <div class="pt-3 pb-1 section-container">
<h1 class="header-text title-font mb-4 cm-gray-1">InvenTree Plugin Repository</h1> <h1 class="header-text title-font mb-4 cm-gray-1">InvenTree Plugin List</h1>
<p class="content">
InvenTree is a modular application and can be extended with plugins. This list is a collection of plugins that have been developed by the community.
Beeing on this list does not mean that the plugin is officially supported by the InvenTree core team. We also do not check for security, privacy or performance issues or compatibility with the latest InvenTree version.
<br><br>
You can also browse for plugins by <a href="{% link tags.html %}">tags</a> or <a href="{% link categories.html %}">categories</a>
</p>
<div class="flex flex-wrap">
{% for plugin in site.repo %} {% for plugin in site.repo %}
<div class="space-4 p-2 md:w-1/2">
{% include plugin_card.html plugin=plugin %} {% include plugin_card.html plugin=plugin %}
</div>
{% endfor %} {% endfor %}
</div> </div>
</div>

7
tags.html Normal file
View File

@ -0,0 +1,7 @@
---
layout: collection/collection_refpage
title: Plugins by Tags
collection: repo
permalink: /plugins/tags/
reference: tags
---

View File

@ -12,5 +12,5 @@ buttons:
link: http://example.com link: http://example.com
- text: lorem ipsum - text: lorem ipsum
link: link:
internal: plugins.html site: plugn-link
--- ---