initial commit
This commit is contained in:
commit
d0caaeaa4a
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
*.pyc
|
||||||
|
*.swp
|
||||||
|
.idea
|
||||||
|
*.iml
|
||||||
|
build
|
||||||
|
dist
|
||||||
|
*.egg*
|
||||||
|
.DS_Store
|
26
customControl/__init__.py
Normal file
26
customControl/__init__.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
__author__ = "Marc Hannappel <sunpack@web.de>"
|
||||||
|
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
|
||||||
|
__copyright__ = "Copyright (C) 2014 The OctoPrint Project - Released under terms of the AGPLv3 License"
|
||||||
|
|
||||||
|
import octoprint.plugin
|
||||||
|
|
||||||
|
class CustomControlPlugin(octoprint.plugin.SettingsPlugin,
|
||||||
|
octoprint.plugin.TemplatePlugin,
|
||||||
|
octoprint.plugin.AssetPlugin):
|
||||||
|
def get_settings_defaults(self):
|
||||||
|
return dict();
|
||||||
|
|
||||||
|
def get_assets(self):
|
||||||
|
return {
|
||||||
|
"js": ["js/customControl.js"],
|
||||||
|
}
|
||||||
|
|
||||||
|
# If you want your plugin to be registered within OctoPrint under a different name than what you defined in setup.py
|
||||||
|
# ("OctoPrint-PluginSkeleton"), you may define that here. Same goes for the other metadata derived from setup.py that
|
||||||
|
# can be overwritten via __plugin_xyz__ control properties. See the documentation for that.
|
||||||
|
__plugin_name__ = "CustomControl"
|
||||||
|
__plugin_license__ = "AGPLv3"
|
||||||
|
__plugin_implementation__ = CustomControlPlugin()
|
228
customControl/static/js/customControl.js
Normal file
228
customControl/static/js/customControl.js
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
$(function () {
|
||||||
|
$.fn.isChildOf = function (element) {
|
||||||
|
return $(element).has(this).length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// from http://jsfiddle.net/KyleMit/X9tgY/
|
||||||
|
$.fn.contextMenu = function (settings) {
|
||||||
|
return this.each(function () {
|
||||||
|
// Open context menu
|
||||||
|
$(this).on("contextmenu", function (e) {
|
||||||
|
// return native menu if pressing control
|
||||||
|
if (e.ctrlKey) return;
|
||||||
|
|
||||||
|
$(settings.menuSelector)
|
||||||
|
.data("invokedOn", $(e.target))
|
||||||
|
.show()
|
||||||
|
.css({
|
||||||
|
position: "absolute",
|
||||||
|
left: getMenuPosition(e.clientX, 'width', 'scrollLeft'),
|
||||||
|
top: getMenuPosition(e.clientY, 'height', 'scrollTop'),
|
||||||
|
"z-index": 9999
|
||||||
|
}).off('click')
|
||||||
|
.on('click', function (e) {
|
||||||
|
if (e.target.tagName.toLowerCase() == "input")
|
||||||
|
return;
|
||||||
|
|
||||||
|
$(this).hide();
|
||||||
|
|
||||||
|
var $invokedOn = $(this).data("invokedOn");
|
||||||
|
var $selectedMenu = $(e.target);
|
||||||
|
|
||||||
|
settings.menuSelected.call(this, $invokedOn, $selectedMenu);
|
||||||
|
});
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
//make sure menu closes on any click
|
||||||
|
$(document).click(function () {
|
||||||
|
$(settings.menuSelector).hide();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function getMenuPosition(mouse, direction, scrollDir) {
|
||||||
|
var win = $(window)[direction](),
|
||||||
|
scroll = $(window)[scrollDir](),
|
||||||
|
menu = $(settings.menuSelector)[direction](),
|
||||||
|
position = mouse + scroll;
|
||||||
|
|
||||||
|
// opening menu would pass the side of the page
|
||||||
|
if (mouse + menu > win && menu < mouse)
|
||||||
|
position -= menu;
|
||||||
|
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.bindingHandlers.contextMenu = {
|
||||||
|
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
|
||||||
|
var val = ko.utils.unwrapObservable(valueAccessor());
|
||||||
|
|
||||||
|
$(element).contextMenu(val);
|
||||||
|
},
|
||||||
|
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
|
||||||
|
var val = ko.utils.unwrapObservable(valueAccessor());
|
||||||
|
|
||||||
|
$(element).contextMenu(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function CustomControlViewModel(parameters) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
self.loginState = parameters[0];
|
||||||
|
self.settingsViewModel = parameters[1];
|
||||||
|
self.controlViewModel = parameters[2];
|
||||||
|
|
||||||
|
self.controls = ko.observableArray([]);
|
||||||
|
|
||||||
|
self.controlsFromServer = [];
|
||||||
|
self.additionalControls = [];
|
||||||
|
|
||||||
|
self.staticID = 0;
|
||||||
|
|
||||||
|
self.onBeforeBinding = function () {
|
||||||
|
self.settings = self.settingsViewModel.settings;
|
||||||
|
self.rerenderControls();
|
||||||
|
};
|
||||||
|
|
||||||
|
self.onAllBound = function (allViewModels) {
|
||||||
|
var additionalControls = [];
|
||||||
|
_.each(allViewModels, function (viewModel) {
|
||||||
|
if (viewModel.hasOwnProperty("getAdditionalControls")) {
|
||||||
|
additionalControls = additionalControls.concat(viewModel.getAdditionalControls());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (additionalControls.length > 0) {
|
||||||
|
self.additionalControls = additionalControls;
|
||||||
|
self.rerenderControls();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.rerenderControls = function () {
|
||||||
|
self.staticID = 0;
|
||||||
|
|
||||||
|
var allControls = self.controlsFromServer.concat(self.additionalControls);
|
||||||
|
self.controls(self._processControls(allControls))
|
||||||
|
};
|
||||||
|
|
||||||
|
self._processControls = function (controls) {
|
||||||
|
for (var i = 0; i < controls.length; i++) {
|
||||||
|
controls[i] = self._processControl(controls[i]);
|
||||||
|
}
|
||||||
|
return controls;
|
||||||
|
};
|
||||||
|
|
||||||
|
self._processControl = function (control) {
|
||||||
|
if (control.hasOwnProperty("template") && control.hasOwnProperty("key") && control.hasOwnProperty("template_key") && !control.hasOwnProperty("output")) {
|
||||||
|
control.output = ko.observable("");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (control.hasOwnProperty("children")) {
|
||||||
|
if (control.processed)
|
||||||
|
control.children = ko.observableArray(self._processControls(control.children()));
|
||||||
|
else
|
||||||
|
control.children = ko.observableArray(self._processControls(control.children));
|
||||||
|
|
||||||
|
if (!control.hasOwnProperty("layout") || !(control.layout == "vertical" || control.layout == "horizontal")) {
|
||||||
|
control.layout = "vertical";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (control.hasOwnProperty("input")) {
|
||||||
|
for (var i = 0; i < control.input.length; i++) {
|
||||||
|
control.input[i].value = ko.observable(control.input[i].default);
|
||||||
|
if (!control.input[i].hasOwnProperty("slider")) {
|
||||||
|
control.input[i].slider = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var js;
|
||||||
|
if (control.hasOwnProperty("javascript")) {
|
||||||
|
js = control.javascript;
|
||||||
|
|
||||||
|
// if js is a function everything's fine already, but if it's a string we need to eval that first
|
||||||
|
if (!_.isFunction(js)) {
|
||||||
|
control.javascript = function (data) {
|
||||||
|
eval(js);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (control.hasOwnProperty("enabled")) {
|
||||||
|
js = control.enabled;
|
||||||
|
|
||||||
|
// if js is a function everything's fine already, but if it's a string we need to eval that first
|
||||||
|
if (!_.isFunction(js)) {
|
||||||
|
control.enabled = function (data) {
|
||||||
|
return eval(js);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
control.id = "settingsCustomControl_id" + self.staticID++;
|
||||||
|
control.processed = true;
|
||||||
|
return control;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.displayMode = function (customControl) {
|
||||||
|
if (customControl.hasOwnProperty("children")) {
|
||||||
|
return "settingsCustomControls_containerTemplate";
|
||||||
|
} else {
|
||||||
|
return "settingsCustomControls_controlTemplate";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.searchElement = function (list, id) {
|
||||||
|
for (var i = 0; i < list.length; i++)
|
||||||
|
{
|
||||||
|
if (list[i].id == id)
|
||||||
|
return list[i];
|
||||||
|
|
||||||
|
if (list[i].hasOwnProperty("children")) {
|
||||||
|
var element = self.searchElement(list[i].children(), id);
|
||||||
|
if (element != undefined)
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.controlContextMenu = function (invokedOn, selectedMenu)
|
||||||
|
{
|
||||||
|
if (selectedMenu.attr('cmd') == "createContainer") {
|
||||||
|
if (invokedOn.attr('id') == "base") {
|
||||||
|
// TODO: make a create dialog
|
||||||
|
self.controlsFromServer.push({ children: [], id: "settingsCustomControl_id" + self.staticID++ });
|
||||||
|
self.rerenderControls();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var parentElement = self.searchElement(self.controlsFromServer, invokedOn.attr('id'));
|
||||||
|
if (parentElement == undefined)
|
||||||
|
{
|
||||||
|
// TODO: make an Warning dialog
|
||||||
|
alert("Something went wrong while creating the new Element");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: make a create dialog
|
||||||
|
parentElement.children.push(self._processControl({ children: [], id: "settingsCustomControl_id" + self.staticID++ }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.editStyle = function (type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// view model class, parameters for constructor, container to bind to
|
||||||
|
OCTOPRINT_VIEWMODELS.push([
|
||||||
|
CustomControlViewModel,
|
||||||
|
["loginStateViewModel", "settingsViewModel", "controlViewModel"],
|
||||||
|
"#settings_plugin_customControl"
|
||||||
|
]);
|
||||||
|
});
|
11
customControl/templates/customControl.jinja2
Normal file
11
customControl/templates/customControl.jinja2
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title></title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
110
customControl/templates/customControl_settings.jinja2
Normal file
110
customControl/templates/customControl_settings.jinja2
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
<h4>{{ _('Control') }}</h4>
|
||||||
|
|
||||||
|
<div style="min-height:15px; margin: 0px 16px; border:1px solid #00e500" id="base" data-bind="contextMenu: { menuSelector: '#controlContextMenu', menuSelected: $root.controlContextMenu }, visible: loginState.isUser">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="clear: both; display: none;" id="customControls" data-bind="visible: loginState.isUser, template: { name: $root.displayMode, foreach: controls }"></div>
|
||||||
|
|
||||||
|
<ul id="controlContextMenu" class="dropdown-menu" role="menu" style="display:block;position:fixed !important;margin-bottom:5px;">
|
||||||
|
<li>
|
||||||
|
<a href="#" cmd="createContainer">Create Container</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul id="commandContextMenu" class="dropdown-menu" role="menu" style="display:block;position:fixed !important;margin-bottom:5px;">
|
||||||
|
<li><a href="#" cmd="editCommand">Edit Command</a></li>
|
||||||
|
<li><a href="#" cmd="deleteCommand">Delete Command</a></li>
|
||||||
|
<li class="divider"></li>
|
||||||
|
<li class="dropdown-submenu">
|
||||||
|
<a href="#">Style</a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li>
|
||||||
|
<a href="#" cmd="editStyle">Normal</a>
|
||||||
|
</li>
|
||||||
|
<li class="btn-primary">
|
||||||
|
<a href="#" cmd="editStyle">Primary</a>
|
||||||
|
</li>
|
||||||
|
<li class="btn-danger">
|
||||||
|
<a href="#" cmd="editStyle">Danger</a>
|
||||||
|
</li>
|
||||||
|
<li class="dropdown-submenu">
|
||||||
|
<a href="#">Custom</a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li><input type="text" placeholder="Background Color 1" cmd="editStyle"></input></li>
|
||||||
|
<li><input type="text" placeholder="Background Color 2" cmd="editStyle"></input></li>
|
||||||
|
<li><input type="text" placeholder="Foreground Color" cmd="editStyle"></input></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul id="containerContextMenu" class="dropdown-menu" role="menu" style="display:block;position:fixed !important;margin-bottom:5px;">
|
||||||
|
<li class="dropdown-submenu">
|
||||||
|
<a href="#">Create Command</a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li><a href="#" cmd="createContainer">Create Container</a></li>
|
||||||
|
<li><a href="#" cmd="createCommand">Command</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li class="divider"></li>
|
||||||
|
<li><a href="#" cmd="editCommand">Edit Container</a></li>
|
||||||
|
<li><a href="#" cmd="deleteCommand">Delete Container</a></li>
|
||||||
|
<li class="divider"></li>
|
||||||
|
<li class="dropdown-submenu">
|
||||||
|
<a href="#">Style</a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li><input type="text" placeholder="Background Color 1" cmd="editStyle"></input></li>
|
||||||
|
<li><input type="text" placeholder="Background Color 2" cmd="editStyle"></input></li>
|
||||||
|
<li><input type="text" placeholder="Foreground Color" cmd="editStyle"></input></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<!-- Templates for custom controls -->
|
||||||
|
<script type="text/html" id="settingsCustomControls_containerTemplate">
|
||||||
|
<div style="min-height:15px; margin: 8px 16px; padding: 8px 16px; border:1px dashed #000000" data-bind="contextMenu: { menuSelector: '#containerContextMenu', menuSelected: $root.controlContextMenu }, attr: { 'id': id }">
|
||||||
|
<!-- ko if: name -->
|
||||||
|
<h1 data-bind="text: name"></h1>
|
||||||
|
<!-- /ko -->
|
||||||
|
|
||||||
|
<!-- ko if: layout == 'vertical' -->
|
||||||
|
<div class="custom_section custom_section_vertical" data-bind="template: { name: $root.displayMode, foreach: children }"></div>
|
||||||
|
<!-- /ko -->
|
||||||
|
|
||||||
|
<!-- ko if: layout == 'horizontal' -->
|
||||||
|
<div class="custom_section custom_section_horizontal" data-bind="template: { name: $root.displayMode, foreach: children }"></div>
|
||||||
|
<!-- /ko -->
|
||||||
|
|
||||||
|
<!-- ko if: layout == 'horizontal_grid' -->
|
||||||
|
<div class="row-fluid custom_section custom_section_horizontal_grid">
|
||||||
|
<!-- ko foreach: children -->
|
||||||
|
<div data-bind="template: { name: $root.displayMode }, css: $root.rowCss($data)"></div>
|
||||||
|
<!-- /ko -->
|
||||||
|
</div>
|
||||||
|
<!-- /ko -->
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
<script type="text/html" id="settingsCustomControls_controlTemplate">
|
||||||
|
<form class="form-inline custom_control" style="min-height:15px; border:1px solid #000000" data-bind="contextMenu: { menuSelector: '#commandContextMenu', menuSelected: $root.controlContextMenu }, attr: { 'id': id }">
|
||||||
|
<!-- ko template: { name: 'customControls_controlTemplate_input', data: $data, if: $data.hasOwnProperty('input') } --><!-- /ko -->
|
||||||
|
<!-- ko template: { name: 'customControls_controlTemplate_command', data: $data, if: $data.hasOwnProperty('command') || $data.hasOwnProperty('commands') || $data.hasOwnProperty('script') || $data.hasOwnProperty('javascript') } --><!-- /ko -->
|
||||||
|
<!-- ko template: { name: 'customControls_controlTemplate_output', data: $data, if: $data.hasOwnProperty('output') } --><!-- /ko -->
|
||||||
|
</form>
|
||||||
|
</script>
|
||||||
|
<script type="text/html" id="customControls_controlTemplate_input">
|
||||||
|
<!-- ko foreach: input -->
|
||||||
|
<label data-bind="text: name"></label>
|
||||||
|
<!-- ko if: slider -->
|
||||||
|
<input type="number" style="width: 100px" data-bind="slider: {value: value, min: slider.min, max: slider.max, step: slider.step}">
|
||||||
|
<!-- /ko -->
|
||||||
|
<!-- ko ifnot: slider -->
|
||||||
|
<input type="text" class="input-small" data-bind="attr: {placeholder: name}, value: value">
|
||||||
|
<!-- /ko -->
|
||||||
|
<!-- /ko -->
|
||||||
|
</script>
|
||||||
|
<script type="text/html" id="customControls_controlTemplate_output">
|
||||||
|
<label data-bind="text: output"></label>
|
||||||
|
</script>
|
||||||
|
<script type="text/html" id="customControls_controlTemplate_command">
|
||||||
|
<button class="btn" data-bind="text: name, enable: $root.isCustomEnabled($data), click: function() { $root.clickCustom($data) }"></button>
|
||||||
|
</script>
|
||||||
|
<!-- End of templates for custom controls -->
|
2
requirements.txt
Normal file
2
requirements.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
OctoPrint
|
||||||
|
|
96
setup.py
Normal file
96
setup.py
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
import setuptools
|
||||||
|
|
||||||
|
########################################################################################################################
|
||||||
|
|
||||||
|
### Do not forget to adjust the following variables to your own plugin.
|
||||||
|
|
||||||
|
# The plugin's identifier, has to be unique
|
||||||
|
plugin_identifier = "customControl"
|
||||||
|
|
||||||
|
# The plugin's python package, should be "octoprint_<plugin identifier>", has to be unique
|
||||||
|
plugin_package = "octoprint_%s" % plugin_identifier
|
||||||
|
|
||||||
|
# The plugin's human readable name. Can be overwritten within OctoPrint's internal data via __plugin_name__ in the
|
||||||
|
# plugin module
|
||||||
|
plugin_name = "OctoPrint-CustomControlPlugin"
|
||||||
|
|
||||||
|
# The plugin's version. Can be overwritten within OctoPrint's internal data via __plugin_version__ in the plugin module
|
||||||
|
plugin_version = "0.1"
|
||||||
|
|
||||||
|
# The plugin's description. Can be overwritten within OctoPrint's internal data via __plugin_description__ in the plugin
|
||||||
|
# module
|
||||||
|
plugin_description = ""
|
||||||
|
|
||||||
|
# The plugin's author. Can be overwritten within OctoPrint's internal data via __plugin_author__ in the plugin module
|
||||||
|
plugin_author = "Marc Hannappel (Salandora)"
|
||||||
|
|
||||||
|
# The plugin's author's mail address.
|
||||||
|
plugin_author_email = "sunpack@web.de"
|
||||||
|
|
||||||
|
# The plugin's homepage URL. Can be overwritten within OctoPrint's internal data via __plugin_url__ in the plugin module
|
||||||
|
plugin_url = ""
|
||||||
|
|
||||||
|
# The plugin's license. Can be overwritten within OctoPrint's internal data via __plugin_license__ in the plugin module
|
||||||
|
plugin_license = "AGPLv3"
|
||||||
|
|
||||||
|
# Additional package data to install for this plugin. The subfolders "templates", "static" and "translations" will
|
||||||
|
# already be installed automatically if they exist.
|
||||||
|
plugin_additional_data = []
|
||||||
|
|
||||||
|
########################################################################################################################
|
||||||
|
|
||||||
|
def package_data_dirs(source, sub_folders):
|
||||||
|
import os
|
||||||
|
dirs = []
|
||||||
|
|
||||||
|
for d in sub_folders:
|
||||||
|
folder = os.path.join(source, d)
|
||||||
|
if not os.path.exists(folder):
|
||||||
|
continue
|
||||||
|
|
||||||
|
for dirname, _, files in os.walk(folder):
|
||||||
|
dirname = os.path.relpath(dirname, source)
|
||||||
|
for f in files:
|
||||||
|
dirs.append(os.path.join(dirname, f))
|
||||||
|
|
||||||
|
return dirs
|
||||||
|
|
||||||
|
|
||||||
|
def requirements(filename):
|
||||||
|
return filter(lambda line: line and not line.startswith("#"), map(lambda line: line.strip(), open(filename).read().split("\n")))
|
||||||
|
|
||||||
|
|
||||||
|
def params():
|
||||||
|
# Our metadata, as defined above
|
||||||
|
name = plugin_name
|
||||||
|
version = plugin_version
|
||||||
|
description = plugin_description
|
||||||
|
author = plugin_author
|
||||||
|
author_email = plugin_author_email
|
||||||
|
url = plugin_url
|
||||||
|
license = plugin_license
|
||||||
|
|
||||||
|
# we only have our plugin package to install
|
||||||
|
packages = [plugin_package]
|
||||||
|
|
||||||
|
# we might have additional data files in sub folders that need to be installed too
|
||||||
|
package_data = {plugin_package: package_data_dirs(plugin_package, ['static', 'templates', 'translations'] + plugin_additional_data)}
|
||||||
|
include_package_data = True
|
||||||
|
|
||||||
|
# If you have any package data that needs to be accessible on the file system, such as templates or static assets
|
||||||
|
# this plugin is not zip_safe.
|
||||||
|
zip_safe = False
|
||||||
|
|
||||||
|
# Read the requirements from our requirements.txt file
|
||||||
|
install_requires = requirements("requirements.txt")
|
||||||
|
|
||||||
|
# Hook the plugin into the "octoprint.plugin" entry point, mapping the plugin_identifier to the plugin_package.
|
||||||
|
# That way OctoPrint will be able to find the plugin and load it.
|
||||||
|
entry_points = {
|
||||||
|
"octoprint.plugin": ["%s = %s" % (plugin_identifier, plugin_package)]
|
||||||
|
}
|
||||||
|
|
||||||
|
return locals()
|
||||||
|
|
||||||
|
setuptools.setup(**params())
|
Loading…
Reference in New Issue
Block a user