Skip to content

Commit

Permalink
Airflow 2.X support
Browse files Browse the repository at this point in the history
  • Loading branch information
ohadmata committed Mar 14, 2021
1 parent 2c7db2b commit c998820
Show file tree
Hide file tree
Showing 11 changed files with 205 additions and 31 deletions.
11 changes: 3 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,10 @@ With this plugin you will be able to delete, duplicate & edit you dags.

### System Requirements

* Airflow 1.10.x
* Not tested for Airflow 2.x
* Airflow >= 1.10.2
* Python 3.7+

### Manual Installation
1. Copy 'simple_dag_editor' folder into your plugins directory
2. Restart airflow instance
3. Open Admin - Simple DAG editor

### Package Installation
### Installation
1. Install the plugin (pip install simple-dag-editor)
2. Restart airflow instance
3. Open Admin - Simple DAG editor
Expand Down
8 changes: 6 additions & 2 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
# simple-dag-editor changelog

## 0.0.6
## 0.1.0
2021-03-14

- Airflow 2.X support
- Vertical separator removed from the editor

## 0.1.0
2021-03-06

### Added
- initial version

151 changes: 151 additions & 0 deletions simple_dag_editor/app_builder_view.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
from flask_appbuilder import BaseView, expose
from airflow.version import version
from flask import jsonify, request
from airflow import configuration
from simple_dag_editor.commons import ROUTE, MENU_CATEGORY, MENU_LABEL, JS_FILES
from simple_dag_editor.utils import Storage, TreeUtils

__all__ = ['appbuilder_view']

# AppBuilder (Airflow >= 2.0)

try:
from airflow.www import auth
from airflow.security import permissions

PERMISSIONS = [
(permissions.ACTION_CAN_READ, permissions.RESOURCE_WEBSITE),
]

class AppBuilderDagEditorView(BaseView):
airflow_major_version = int(version.split('.')[0])
route_base = ROUTE
base_permissions = ['can_list', 'can_create', 'menu_acccess']

@expose('/')
@auth.has_access(PERMISSIONS)
def list(self):
return self._render('index')

@expose('/files', methods=['GET'])
@auth.has_access(PERMISSIONS)
def root_ls(self):
node = request.args.get('id')
path = node if node != '#' else configuration.conf.get('core', 'dags_folder')

return jsonify(
TreeUtils.ls_to_tree_node(Storage.ls(path))
)

@expose("/read", methods=["GET"])
@auth.has_access(PERMISSIONS)
def read_file(self):
path = request.args.get('path')
return jsonify({
'status': 'ok',
'data': Storage.read(path)
})

@expose("/delete", methods=["POST"])
@auth.has_access(PERMISSIONS)
def delete_file(self):
path = request.json.get('path')
Storage.delete(path)
return jsonify({
'status': 'ok'
})

@expose("/save", methods=["POST"])
@auth.has_access(PERMISSIONS)
def save_file(self):
path = request.json.get('path')
data = request.json.get('data')
Storage.write(path, data)
return jsonify({
'status': 'ok'
})

def _render(self, template, *args, **kargs):
return self.render_template(
template + '_appbuilder.html',
airflow_major_version=self.airflow_major_version,
js_files=JS_FILES,
*args,
**kargs
)


except (ImportError, ModuleNotFoundError):
from airflow_code_editor.auth import has_access
from airflow.www_rbac.decorators import has_dag_access

# AppBuilder (Airflow >= 1.10 < 2.0 and rbac = True)

class AppBuilderDagEditorView(BaseView):
airflow_major_version = int(version.split('.')[0])
route_base = ROUTE
base_permissions = ['can_list']

@expose('/')
@has_dag_access(can_dag_edit=True)
@has_access
def list(self):
return self._render('index')

@expose('/files', methods=['GET'])
@has_dag_access(can_dag_edit=True)
def root_ls(self):
node = request.args.get('id')
path = node if node != '#' else configuration.conf.get('core', 'dags_folder')

return jsonify(
TreeUtils.ls_to_tree_node(Storage.ls(path))
)

@expose("/read", methods=["GET"])
@has_dag_access(can_dag_edit=True)
@has_access
def read_file(self):
path = request.args.get('path')
return jsonify({
'status': 'ok',
'data': Storage.read(path)
})

@expose("/delete", methods=["POST"])
@has_dag_access(can_dag_edit=True)
@has_access
def delete_file(self):
path = request.json.get('path')
Storage.delete(path)
return jsonify({
'status': 'ok'
})

@expose("/save", methods=["POST"])
@has_dag_access(can_dag_edit=True)
@has_access
def save_file(self):
path = request.json.get('path')
data = request.json.get('data')
Storage.write(path, data)
return jsonify({
'status': 'ok'
})

def _render(self, template, *args, **kargs):
return self.render_template(
template + '_appbuilder.html',
airflow_major_version=self.airflow_major_version,
js_files=JS_FILES,
*args,
**kargs
)


appbuilder_dag_editor_view = AppBuilderDagEditorView()
appbuilder_view = {
'category': MENU_CATEGORY,
'name': MENU_LABEL,
'view': appbuilder_dag_editor_view,
}
8 changes: 7 additions & 1 deletion simple_dag_editor/commons.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,17 @@
'MENU_LABEL',
'ROUTE',
'STATIC',
'JS_FILES'
]

PLUGIN_NAME = 'dag_editor'
MENU_CATEGORY = 'Admin'
MENU_LABEL = 'Simple DAG editor'
ROUTE = '/' + PLUGIN_NAME
STATIC = '/static/' + PLUGIN_NAME

JS_FILES = [
'js/ace.min.js',
'js/jstree.min.js',
'js/mode-python.min.js',
'js/sweetalert2.all.min.js'
]
2 changes: 2 additions & 0 deletions simple_dag_editor/flask_admin_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

__all__ = ["admin_view"]

# AppBuilder (Airflow < 2.0)

try:
from flask_admin import BaseView, expose
AIRFLOW_MAJOR_VERSION = int(version.split('.')[0])
Expand Down
23 changes: 10 additions & 13 deletions simple_dag_editor/simple_dag_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@
# limitations under the License
#
__author__ = 'Ohad Mata <ohadmata@gmail.com>'
__version__ = '0.0.6'
__version__ = '0.1.0'

from flask import Blueprint
from airflow.plugins_manager import AirflowPlugin
from airflow import configuration
from simple_dag_editor.commons import STATIC
from simple_dag_editor.flask_admin_view import admin_view
from simple_dag_editor.app_builder_view import appbuilder_view

__all__ = ['SimpleDagEditor']

Expand All @@ -34,22 +35,18 @@
)


class DagEditorPlugin(AirflowPlugin):
class SimpleDagEditor(AirflowPlugin):
name = 'simple_dag_editor'
operators = []
hooks = []
executors = []
menu_links = []

if configuration.getboolean('dag_editor', 'DISABLED', fallback=False):
name = 'simple_dag_editor'
operators = []
flask_blueprints = []
hooks = []
executors = []
admin_views = []
menu_links = []
appbuilder_views = []
else:
name = 'simple_dag_editor'
operators = []
flask_blueprints = [simple_dag_editor_blueprint]
hooks = []
executors = []
admin_views = [admin_view] if admin_view is not None else []
menu_links = []
appbuilder_views = []
appbuilder_views = [appbuilder_view]
7 changes: 6 additions & 1 deletion simple_dag_editor/static/css/style.css
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
.editor_container{
padding-top: 15px;
padding-bottom: 0;
}

.code-panel{
padding: 0 !important;
}

.explorer-panel{
height:760px;
height:660px;
overflow: auto;
}

Expand Down
16 changes: 16 additions & 0 deletions simple_dag_editor/templates/index_appbuilder.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

{% extends 'appbuilder/general/model/list.html' %}

{% block head_css %}
{{ super() }}
{% include "index_head.html" %}
{% endblock %}

{% block content %}
{% include "index_body.html" %}
{% endblock %}

{% block tail %}
{{ super() }}
{% include "index_tail.html" %}
{% endblock %}
8 changes: 2 additions & 6 deletions simple_dag_editor/templates/index_body.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

<div class="container">
<div class="container editor_container">
<div class="row">

<div class="col-md-3"> <!--Explorer panel-->
Expand Down Expand Up @@ -32,10 +32,6 @@
<style type="text/css">
#editor {
width: 100%;
height: 705px;
height: 605px;
}
</style>




1 change: 1 addition & 0 deletions simple_dag_editor/templates/index_tail.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
$(".btn").attr("disabled", true);

editor.session.setMode("ace/mode/python");
editor.setShowPrintMargin(false);
editor.setOptions({
fontSize: "14px"
});
Expand Down
1 change: 1 addition & 0 deletions simple_dag_editor/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
from typing import List, Dict


class Storage:

@classmethod
Expand Down

0 comments on commit c998820

Please sign in to comment.