[ English | 中文 (简体, 中国) | русский | português (Brasil) | नेपाली | 한국어 (대한민국) | Indonesia | français | español | esperanto | English (United Kingdom) | Deutsch ]
Tutorial: Membuat Plugin Horizon¶
Mengapa saya harus mengemas kode saya sebagai plugin?¶
Kami sangat menyarankan Anda menulis dan memelihara kode Anda menggunakan arsitektur plugin kami. Plugin menurut definisi berarti kemampuan untuk terhubung. Secara praktis, plugin adalah cara untuk memperluas dan menambah fungsionalitas yang sudah ada. Anda dapat mengontrol kontennya dan berkembang pada tingkat yang tidak tergantung pada Horizon. Jika Anda menulis dan mengemas kode Anda sebagai plugin, itu akan terus berfungsi di rilis mendatang.
Menulis kode Anda sebagai plugin juga memodulasi kode Anda sehingga lebih mudah untuk menerjemahkan dan menguji. Ini juga membuatnya lebih mudah bagi para penyebar untuk menggunakan kode Anda yang memungkinkan pemberdayaan fitur secara selektif. Kami saat ini menggunakan pola ini secara internal untuk dasbor kami.
Membuat Plugin¶
Tutorial ini mengasumsikan Anda memiliki pemahaman dasar tentang Python, HTML, JavaScript. Pengetahuan tentang AngularJS adalah opsional tetapi disarankan jika Anda mencoba membuat plugin Angular.
Nama repositori Anda¶
Tak perlu dikatakan, penting untuk memilih nama repositori yang bermakna.
Selain itu, jika Anda berencana untuk mendukung terjemahan pada plugin dashboard Anda, disarankan untuk memilih nama seperti xxxx-dashboard
(atau xxxx-ui
. xxxx-horizon
). Skrip infra CI OpenStack menganggap repositori dengan sufiks ini sebagai proyek Django.
Jenis-jenis Plugin yang menambahkan konten¶
Struktur file untuk tipe plugin Anda akan berbeda tergantung pada kebutuhan Anda. Plugin Anda dapat dikategorikan ke dalam dua jenis:
Pengaya (plugin) yang membuat panel atau dasbor baru
Plugin yang mengubah alur kerja, tindakan, dll ... (hanya Angular)
Kami akan membahas dasar-dasar bekerja dengan panel untuk Python dan Angular. Jika Anda tertarik untuk membuat panel baru, ikuti langkah-langkah di bawah ini.
Catatan
Tutorial ini menunjukkan kepada Anda cara membuat panel baru. Jika Anda tertarik untuk membuat plugin dasbor baru, gunakan struktur file dari :ref: tutorials-dashboard.
Struktur File¶
Di bawah ini adalah kerangka tampilan plugin Anda.
myplugin
│
├── myplugin
│ ├── __init__.py
│ │
│ ├── enabled
│ │ └──_31000_myplugin.py
│ │
│ ├── api
│ │ ├──__init__.py
│ │ ├── my_rest_api.py
│ │ └── myservice.py
│ │
│ ├── content
│ │ ├──__init__.py
│ │ └── mypanel
│ │ ├── __init__.py
│ │ ├── panel.py
│ │ ├── tests.py
│ │ ├── urls.py
│ │ ├── views.py
│ │ └── templates
│ │ └── mypanel
│ │ └── index.html
│ │
│ └── static
│ | └── dashboard
│ | └── identity
│ | └── myplugin
│ | └── mypanel
│ | ├── mypanel.html
│ | ├── mypanel.js
│ | └── mypanel.scss
│ │
│ └── locale
│ └── <lang>
│ └── LC_MESSAGES
│ ├── django.po
│ └── djangojs.po
│
├── setup.py
├── setup.cfg
├── LICENSE
├── MANIFEST.in
├── README.rst
├── babel-django.cfg
└── babel-djangojs.cfg
Jika Anda membuat plugin Python, Anda dapat mengabaikan folder static
. Sebagian besar kelas yang Anda butuhkan disediakan dengan Python. Jika Anda ingin menambahkan logika front-end kustom, Anda harus memasukkan JavaScript tambahan di sini.
Plugin AngularJS adalah kumpulan file JavaScript atau sumber daya statis. Karena sepenuhnya berjalan di browser Anda, kami perlu menempatkan semua sumber daya statis kami di dalam folder static
. Ini memastikan bahwa kolektor statis Django mengambilnya dan mendistribusikannya ke browser dengan benar.
File Diaktifkan¶
Folder yang diaktifkan berisi file konfigurasi yang mendaftarkan plugin Anda dengan Horizon. File diawali dengan string alpha-numeric yang menentukan urutan pemuatan plugin Anda. Untuk informasi lebih lanjut tentang apa yang bisa Anda sertakan dalam file ini, lihat pengaturan pluggable di Referensi Pengaturan.
_31000_myplugin.py:
# The name of the panel to be added to HORIZON_CONFIG. Required.
PANEL = 'mypanel'
# The name of the dashboard the PANEL associated with. Required.
PANEL_DASHBOARD = 'identity'
# Python panel class of the PANEL to be added.
ADD_PANEL = 'myplugin.content.mypanel.panel.MyPanel'
# A list of applications to be prepended to INSTALLED_APPS
ADD_INSTALLED_APPS = ['myplugin']
# A list of AngularJS modules to be loaded when Angular bootstraps.
ADD_ANGULAR_MODULES = ['horizon.dashboard.identity.myplugin.mypanel']
# Automatically discover static resources in installed apps
AUTO_DISCOVER_STATIC_FILES = True
# A list of js files to be included in the compressed set of files
ADD_JS_FILES = []
# A list of scss files to be included in the compressed set of files
ADD_SCSS_FILES = ['dashboard/identity/myplugin/mypanel/mypanel.scss']
# A list of template-based views to be added to the header
ADD_HEADER_SECTIONS = ['myplugin.content.mypanel.views.HeaderView',]
Catatan
Saat ini, AUTO_DISCOVER_STATIC_FILES = True
hanya akan menemukan file JavaScript, bukan file SCSS.
my_rest_api.py¶
File ini kemungkinan akan diperlukan jika membuat plugin menggunakan Angular. Plugin Anda perlu berkomunikasi dengan layanan baru atau memerlukan interaksi baru dengan layanan yang sudah didukung oleh Horizon. Dalam contoh khusus ini, plugin akan menambah dukungan untuk layanan Identity yang sudah didukung, Keystone. File ini berfungsi untuk mendefinisikan antarmuka REST baru untuk sisi klien plugin untuk berkomunikasi dengan Horizon. Biasanya, antarmuka REST di sini membuat panggilan ke myservice.py
.
File ini tidak diperlukan dalam plugin murni berbasis Django, atau jika plugin berbasis Angular Anda mengandalkan dukungan CORS dalam layanan yang diinginkan. Untuk informasi lebih lanjut tentang CORS, lihat https://docs.openstack.org/oslo.middleware/latest/admin/cross-project-cors.html
myservice.py¶
File ini kemungkinan akan diperlukan jika membuat plugin yang didorong oleh Django atau Angular. File ini dimaksudkan untuk bertindak sebagai lokasi yang nyaman untuk berinteraksi dengan layanan baru yang didukung plugin ini. Sementara interaksi dengan layanan dapat ditangani di views.py
, mengisolasi logika adalah pola yang sudah ada di Horizon.
panel.py¶
Kami menetapkan panel tempat konten plugin kami berada. Saat ini merupakan keharusan bahkan untuk plugin Angular. Slug adalah pengidentifikasi unik panel dan sering digunakan sebagai bagian dari URL. Pastikan itu cocok dengan apa yang Anda miliki di file yang diaktifkan.
from django.utils.translation import gettext_lazy as _
import horizon
class MyPanel(horizon.Panel):
name = _("My Panel")
slug = "mypanel"
tests.py¶
Tulis beberapa tes untuk bagian Django dari plugin Anda dan letakkan di sini.
urls.py¶
Sekarang kami memiliki panel, kami perlu menyediakan URL agar pengguna dapat mengunjungi panel baru kami! URL ini umumnya akan mengarah ke view.
from django.urls import re_path
from myplugin.content.mypanel import views
urlpatterns = [
re_path(r'^$', views.IndexView.as_view(), name='index'),
]
views.py¶
Karena rendering dilakukan di sisi klien, semua kebutuhan tampilan kami adalah untuk merujuk beberapa halaman HTML. Jika Anda menulis plugin Python, view ini bisa jauh lebih kompleks. Lihat panduan topik untuk lebih jelasnya.
from django.views import generic
class IndexView(generic.TemplateView):
template_name = 'identity/mypanel/index.html'
index.html¶
Indeks HTML adalah tempat rendering terjadi. Dalam contoh ini, kami hanya menggunakan Django. Jika Anda tertarik menggunakan arahan Angular, baca bagian AngularJS di bawah ini
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "My plugin" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_domain_page_header.html" with title=_("My Panel") %}
{% endblock page_header %}
{% block main %}
Hello world!
{% endblock %}
Pada titik ini, Anda memiliki plugin yang sangat mendasar. Perhatikan bahwa templat baru diperlukan untuk memperpanjang base.html. Termasuk base.html penting karena sejumlah alasan. Ini adalah templat yang berisi semua sumber daya statis Anda beserta fungsi apa pun di luar panel Anda (hal-hal seperti navigasi, pemilihan konteks, dll ...). Pada saat ini, ini juga berlaku untuk plugin Angular.
MANIFEST.in¶
File ini bertanggung jawab untuk mendaftarkan jalur yang ingin Anda sertakan dalam tar Anda.
include setup.py
recursive-include myplugin *.js *.html *.scss
setup.py¶
import setuptools
setuptools.setup(
setup_requires=['pbr>=2.0.0'],
pbr=True)
setup.cfg¶
[metadata]
name = myplugin
summary = A panel plugin for OpenStack Dashboard
description_file =
README.rst
author = myname
author_email = myemail
home_page = __REPLACE_YOUR_PLGUIN_HOMEPAGE_URL__
classifier =
Environment :: OpenStack
Framework :: Django
Intended Audience :: Developers
Intended Audience :: System Administrators
License :: OSI Approved :: Apache Software License
Operating System :: POSIX :: Linux
Programming Language :: Python
Programming Language :: Python :: 3 :: Only
Programming Language :: Python :: 3
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
[files]
packages =
myplugin
AngularJS Plugin¶
Jika Anda tidak memiliki rencana untuk menambahkan AngularJS ke plugin Anda, Anda dapat melewati bagian ini. Dalam tutorial di bawah ini, kami akan menunjukkan kepada Anda bagaimana menyesuaikan panel Anda menggunakan Angular.
index.html¶
Indeks HTML adalah tempat rendering terjadi dan berfungsi sebagai titik masuk untuk Angular. Di sinilah kita mulai menyimpang dari plugin Python tradisional. Dalam contoh ini, kami menggunakan templat Django sebagai perekat pada templat Angular kami. Mengapa kita melalui templat Django untuk plugin Angular? Singkat cerita, base.html
berisi bagian navigasi yang masih kita butuhkan untuk setiap panel.
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "My panel" %}{% endblock %}
{% block page_header %}
<hz-page-header
header="{$ 'My panel' | translate $}"
description="{$ 'My custom panel!' | translate $}">
</hz-page-header>
{% endblock page_header %}
{% block main %}
<ng-include src="'{{ STATIC_URL }}dashboard/identity/myplugin/mypanel/mypanel.html'">
</ng-include>
{% endblock %}
Template ini mengandung kode Django dan AngularJS. Angular dilambangkan dengan {$..$}
sementara Django dilambangkan dengan {{..}}
dan {%..%}
. Template ini diproses dua kali, sekali oleh Django di sisi server dan sekali lagi oleh Angular di sisi klien. Ini berarti bahwa ekspresi dalam {{..}}
dan {%..%}
diganti dengan nilai pada saat mencapai templat Angular Anda.
Apa yang Anda pilih untuk dimasukkan dalam block main
sepenuhnya terserah Anda. Karena Anda membuat plugin Angular, kami sarankan Anda menyimpan semuanya di bagian Angular. Jangan campur kode Python di sini! Jika Anda menemukan diri Anda mengirimkan data Python, lakukan itu melalui layanan REST kami.
Ingatlah untuk selalu menggunakan STATIC_URL
saat merujuk sumber daya statis Anda. Ini memastikan bahwa perubahan pada jalur statis dalam pengaturan akan terus melayani sumber daya statis Anda dengan benar.
Catatan
Arahan Angular diawali dengan ng. Demikian pula, arahan Horizon diawali dengan hz. Anda dapat menganggapnya sebagai ruang nama (namespace).
mypanel.js¶
Pengontrol Anda adalah perekat antara model dan view. Dalam contoh ini, kita akan memberikan beberapa data palsu untuk ditampilkan (render). Untuk memuat data yang lebih kompleks, pertimbangkan untuk menggunakan layanan $http.
(function() {
'use strict';
angular
.module('horizon.dashboard.identity.myplugin.mypanel', [])
.controller('horizon.dashboard.identity.myPluginController',
myPluginController);
myPluginController.$inject = [ '$http' ];
function myPluginController($http) {
var ctrl = this;
ctrl.items = [
{ name: 'abc', id: 123 },
{ name: 'efg', id: 345 },
{ name: 'hij', id: 678 }
];
}
})();
Ini adalah contoh dasar di mana kami mengejek data. Untuk latihan, muat data Anda menggunakan layanan $http
.
mypanel.html¶
Ini adalah pandangan kami. Dalam contoh ini, kami mengulang daftar item yang disediakan oleh controller dan menampilkan nama dan id. Yang penting untuk dicatat adalah referensi ke controller kami menggunakan direktif ng-controller
.
<div ng-controller="horizon.dashboard.identity.myPluginController as ctrl">
<div>Loading data from your controller:</div>
<ul>
<li ng-repeat="item in ctrl.items">
<span class="c1">{$ item.name $}</span>
<span class="c2">{$ item.id $}</span>
</li>
</ul>
</div>
mypanel.scss¶
Anda dapat memilih untuk menyesuaikan panel Anda dengan memberikan scss Anda sendiri. Pastikan Anda memasukkannya ke dalam file yang diaktifkan melalui pengaturan ADD_SCSS_FILES
.
Dukungan Terjemahan¶
Instruksi umum tentang cara mengaktifkan dukungan terjemahan dijelaskan dalam Infrastructure User Manual 1.
Bagian ini menjelaskan topik khusus untuk plugin Horizon.
ADD_INSTALLED_APPS¶
Pastikan untuk memasukkan <modulename> `` (``myplugin
dalam contoh ini) dalam ADD_INSTALLED_APPS
dalam file enabled
terkait.
Jika Anda menyiapkan plugin baru, Anda akan menggunakan
<modulename> `` sebagai ``INSTALLED_APPS
dalam banyak kasus seperti yang disarankan dalam tutorial ini. Ini bagus dan tidak ada lagi yang bisa dilakukan.Jika karena alasan tertentu plugin Anda perlu mendaftarkan modul python lain ke
ADD_INSTALLED_APPS
, pastikan Anda menyertakan ``<modulename> `` tambahannya.
Ini berasal dari kombinasi dua alasan berikut.
Django mencari katalog pesan terjemahan dari setiap jalur yang ditentukan dalam
INSTALLED_APPS
[#] _.Skrip infra OpenStack mengasumsikan katalog pesan terjemahan ditempatkan di bawah
<modulename>/locale
(misalnyamyplugin/locale
).
myplugin/locale¶
File katalog pesan yang diterjemahkan (file PO) ditempatkan di bawah direktori ini.
babel-django.cfg, babel-djangojs.cfg¶
File ini digunakan untuk mengekstraksi pesan dengan pybabel
: babel-django.cfg
untuk kode python dan file templat, dan babel-djangojs.cfg
untuk file JavaScript.
Mereka diminta untuk mengaktifkan dukungan terjemahan oleh OpenStack CI infra. Jika tidak ada, pekerjaan terjemahan akan melewati pemrosesan untuk proyek Anda.
Menginstal Plugin Anda¶
Sekarang Anda memiliki plugin yang lengkap, sekarang saatnya untuk menginstal dan mengujinya. Petunjuk di bawah ini menganggap bahwa Anda memiliki plugin yang berfungsi.
plugin
adalah lokasi plugin Anda``horizon``adalah lokasi horizon
`` paket`` adalah nama lengkap dari plugin yang Anda paket
Jalankan "cd` plugin` & python setup.py sdist"
Jalankan "cp -rv enabled
horizon
/openstack_dashboard/local/"Jalankan "
horizon
/tools/with_venv.sh pip install dist/package
.tar.gz"Restart Apache atau server uji Django Anda
Catatan
Langkah 3 instal paket Anda ke lingkungan virtual Horizon. Anda dapat menginstal plugin Anda tanpa menggunakan with_venv.sh
dan pip
. Paket hanya akan diinstal di PYTHON_PATH
sistem sebagai gantinya.
Jika Anda dapat menekan pola URL di urls.py
di browser Anda, Anda telah berhasil menggunakan plugin Anda! Untuk plugin yang tidak memiliki URL, periksa apakah sumber daya statis Anda dimuat menggunakan inspektur browser.
Dengan asumsi Anda menerapkan my_rest_api.py
, Anda dapat menggunakan klien REST untuk menekan url secara langsung dan mengujinya. Seharusnya ada banyak klien REST yang tersedia di browser web Anda.
Perhatikan bahwa Anda mungkin perlu membangun kembali lingkungan virtual Anda jika plugin Anda tidak muncul dengan benar. Jika plugin Anda tidak muncul dengan benar, periksa folder .tox
Anda untuk memastikan konten plugin sesuai dengan yang Anda harapkan.
Catatan
Untuk menghapus instalan, gunakan pip uninstall
. Anda juga perlu menghapus file yang diaktifkan dari folder local/enabled
.