diff --git a/jans-cli-tui/cli_tui/cli_style.py b/jans-cli-tui/cli_tui/cli_style.py
index 2daa3d1e190..33b33815b8e 100755
--- a/jans-cli-tui/cli_tui/cli_style.py
+++ b/jans-cli-tui/cli_tui/cli_style.py
@@ -1,4 +1,5 @@
from prompt_toolkit.styles import Style
+from types import SimpleNamespace
style = Style.from_dict(
{
@@ -76,6 +77,7 @@
"plugin-widget":"green",
"plugin-container":"",
"plugin-container.text":"green",
+ "plugin-black-bg": "bg: black",
## edit_client_dialog
"outh-client-navbar":"#2600ff",
@@ -130,9 +132,32 @@
"date-picker-time":"bg:#bab1b1",
"dialog-titled-widget":"bg:#ffffff fg:green",
+ ####tab
+ "tab-nav-background": "fg:#b0e0e6 bg:#a9a9a9",
+ "tab-unselected": "fg:#b0e0e6 bg:#a9a9a9 underline",
+ "tab-selected": "fg:#000080 bg:#d3d3d3",
+
+ ##scim
+ "scim-widget": "bg:black fg:white",
+
}
)
+
+def get_color_for_style(style_name:str)->SimpleNamespace:
+ ret_val = SimpleNamespace()
+ ret_val.fg = '#000000'
+ ret_val.bg = '#ffffff'
+
+ for pstyle in style.class_names_and_attrs:
+ if pstyle[0].__contains__(style_name):
+ if pstyle[1].color:
+ ret_val.fg = '#'+pstyle[1].color
+ if pstyle[1].bgcolor:
+ ret_val.bg = '#'+pstyle[1].bgcolor
+
+ return ret_val
+
## jans nav bar
main_navbar_bgcolor = "DimGray"
outh_navbar_bgcolor = "#ADD8E6"
diff --git a/jans-cli-tui/cli_tui/jans_cli_tui.py b/jans-cli-tui/cli_tui/jans_cli_tui.py
index 0c6a7e5d6c7..7b6874f976e 100755
--- a/jans-cli-tui/cli_tui/jans_cli_tui.py
+++ b/jans-cli-tui/cli_tui/jans_cli_tui.py
@@ -115,6 +115,7 @@ def __init__(self):
self.styles = dict(style.style_rules)
self._plugins = []
self._load_plugins()
+ self.available_plugins = []
self.cli_object_ok = False
self.pbar_text = ""
self.progressing_text = ""
@@ -217,9 +218,15 @@ def _load_plugins(self) -> None:
self._plugins.append(plugin_object)
def init_plugins(self) -> None:
+ """Initilizse plugins
+ """
for plugin in self._plugins:
if hasattr(plugin, 'init_plugin'):
+ if getattr(plugin, 'server_side_plugin', False) and plugin.pid not in self.available_plugins:
+ continue
+ self.logger.debug('Initializing plugin {}'.format(plugin.pid))
plugin.init_plugin()
+
self.plugins_initialised = True
def plugin_enabled(self, pid: str) -> bool:
@@ -317,27 +324,31 @@ async def coroutine():
self.stop_progressing()
self.cli_object_ok = True
- if not self.plugins_initialised:
- self.init_plugins()
- self.runtime_plugins()
+ self.check_available_plugins()
asyncio.ensure_future(coroutine())
else:
self.cli_object_ok = True
- if not self.plugins_initialised:
- self.init_plugins()
- self.runtime_plugins()
+ self.check_available_plugins()
- def runtime_plugins(self) -> None:
+ def check_available_plugins(self) -> None:
"""Disables plugins when cli object is ready"""
if self.cli_object_ok:
- response = self.cli_requests({'operation_id': 'is-license-active'})
- if response.status_code == 404:
- self.disable_plugin('config_api')
+ response = self.cli_requests({'operation_id': 'get-plugins'})
+ if response.ok:
+ plugins = response.json()
+ for plugin in plugins:
+ self.available_plugins.append(plugin['name'])
+
+ for pp in self._plugins:
+ if getattr(pp, 'server_side_plugin', False) and pp.pid not in self.available_plugins:
+ self.disable_plugin(pp.pid)
+
+ self.init_plugins()
def disable_plugin(self, pid) -> None:
@@ -355,9 +366,6 @@ async def check_jans_cli_ini(self) -> None:
else :
self.create_cli()
- if self.cli_object_ok and not self.plugins_initialised:
- self.init_plugins()
-
def jans_creds_dialog(self, *params: Any) -> None:
body=HSplit([
@@ -387,6 +395,7 @@ def set_keybindings(self) -> None:
self.bindings.add('tab')(self.focus_next)
self.bindings.add('s-tab')(self.focus_previous)
self.bindings.add('c-c')(do_exit)
+ self.bindings.add('c-q')(do_exit)
self.bindings.add('f1')(self.help)
self.bindings.add('escape')(self.escape)
self.bindings.add('s-up')(self.up)
@@ -569,6 +578,7 @@ def getTitledText(
focusable: Optional[bool] = None,
width: AnyDimension = None,
style: AnyFormattedText = '',
+ widget_style: AnyFormattedText = '',
scrollbar: Optional[bool] = False,
line_numbers: Optional[bool] = False,
lexer: PygmentsLexer = None,
@@ -583,7 +593,7 @@ def getTitledText(
height=height,
width=width,
read_only=read_only,
- style=self.styles['textarea-readonly'] if read_only else self.styles['textarea'],
+ style=widget_style or (self.styles['textarea-readonly'] if read_only else self.styles['textarea']),
accept_handler=accept_handler,
focusable=not read_only if focusable is None else focusable,
scrollbar=scrollbar,
@@ -598,7 +608,7 @@ def getTitledText(
ta.window.jans_name = name
ta.window.jans_help = jans_help
- v = VSplit([Window(FormattedTextControl(title), width=len(title)+1, style=style, height=height), ta], padding=1)
+ v = VSplit([Window(FormattedTextControl(title), width=len(title)+1, style=style, height=height), ta])
v.me = ta
return v
@@ -611,6 +621,7 @@ def getTitledCheckBoxList(
current_values: Optional[list] = [],
jans_help: AnyFormattedText= "",
style: AnyFormattedText= "",
+ widget_style: AnyFormattedText = '',
) -> AnyContainer:
title += ': '
@@ -620,9 +631,8 @@ def getTitledCheckBoxList(
cbl.current_values = current_values
cbl.window.jans_name = name
cbl.window.jans_help = jans_help
- #li, cd, width = self.handle_long_string(title, values, cbl)
- v = VSplit([Window(FormattedTextControl(title), width=len(title)+1, style=style,), cbl], padding=1)
+ v = VSplit([Window(FormattedTextControl(title), width=len(title)+1, style=style,), cbl], style=widget_style)
v.me = cbl
return v
@@ -636,10 +646,15 @@ def getTitledCheckBox(
on_selection_changed: Callable= None,
jans_help: AnyFormattedText= "",
style: AnyFormattedText= "",
+ widget_style: AnyFormattedText = '',
) -> AnyContainer:
title += ': '
cb = Checkbox(text)
+ if widget_style:
+ cb.default_style = widget_style
+ cb.checked_style = widget_style
+ cb.selected_style = widget_style
cb.checked = checked
cb.window.jans_name = name
cb.window.jans_help = jans_help
@@ -652,9 +667,7 @@ def custom_handler():
if on_selection_changed:
cb._handle_enter = custom_handler
- #li, cd, width = self.handle_long_string(title, text, cb)
-
- v = VSplit([Window(FormattedTextControl(title), width=len(title)+1, style=style,), cb], padding=1)
+ v = VSplit([Window(FormattedTextControl(title), width=len(title)+1, style=style,), cb], style=widget_style)
v.me = cb
@@ -669,6 +682,7 @@ def getTitledRadioButton(
on_selection_changed: Callable= None,
jans_help: AnyFormattedText= "",
style: AnyFormattedText= "",
+ widget_style: AnyFormattedText = '',
) -> AnyContainer:
title += ': '
@@ -689,7 +703,7 @@ def custom_handler():
if on_selection_changed:
rl._handle_enter = custom_handler
- v = VSplit([Window(FormattedTextControl(title), width=len(title)+1, style=style,), rl], padding=1)
+ v = VSplit([Window(FormattedTextControl(title), width=len(title)+1, style=style,), rl])
v.me = rl
@@ -715,9 +729,9 @@ def getTitledWidget(
def getButton(
self,
- text: AnyFormattedText,
- name: AnyFormattedText,
- jans_help: AnyFormattedText,
+ text: AnyFormattedText,
+ name: AnyFormattedText,
+ jans_help: AnyFormattedText,
handler: Callable= None,
) -> Button:
@@ -845,15 +859,14 @@ def show_message(
self.layout.focus(dialog)
self.invalidate()
- def show_again(self) -> None:
- self.show_message(_("Again"), _("Nasted Dialogs"),)
def get_confirm_dialog(
- self,
- message: AnyFormattedText
+ self,
+ message: AnyFormattedText,
+ confirm_handler: Optional[Callable]=None
) -> Dialog:
body = VSplit([Label(message)], align=HorizontalAlign.CENTER)
- buttons = [Button(_("No")), Button(_("Yes"))]
+ buttons = [Button(_("No")), Button(_("Yes"), handler=confirm_handler)]
dialog = JansGDialog(self, title=_("Confirmation"), body=body, buttons=buttons)
return dialog
diff --git a/jans-cli-tui/cli_tui/plugins/010_auth_server/edit_client_dialog.py b/jans-cli-tui/cli_tui/plugins/010_auth_server/edit_client_dialog.py
index 402dd3fb459..0f9468dac20 100755
--- a/jans-cli-tui/cli_tui/plugins/010_auth_server/edit_client_dialog.py
+++ b/jans-cli-tui/cli_tui/plugins/010_auth_server/edit_client_dialog.py
@@ -10,13 +10,17 @@
Button,
Label,
TextArea,
- Dialog
+ Dialog,
+ CheckboxList
)
+from prompt_toolkit.layout import Window
+
from prompt_toolkit.lexers import PygmentsLexer, DynamicLexer
from prompt_toolkit.application.current import get_app
from asyncio import Future, ensure_future
from utils.static import DialogResult, cli_style
from utils.multi_lang import _
+from utils.utils import common_data
from wui_components.jans_dialog_with_nav import JansDialogWithNav
from wui_components.jans_side_nav_bar import JansSideNavBar
from wui_components.jans_cli_dialog import JansGDialog
@@ -24,17 +28,22 @@
from wui_components.jans_date_picker import DateSelectWidget
from utils.utils import DialogUtils
from wui_components.jans_vetrical_nav import JansVerticalNav
+from wui_components.jans_label_container import JansLabelContainer
+
from view_uma_dialog import ViewUMADialog
import threading
from prompt_toolkit.buffer import Buffer
from prompt_toolkit.formatted_text import AnyFormattedText
from typing import Optional, Sequence
from typing import Callable
+from prompt_toolkit.eventloop import get_event_loop
+import asyncio
import json
ERROR_GETTING_CLIENTS = _("Error getting clients")
ATTRIBUTE_SCHEMA_PATH = '#/components/schemas/ClientAttributes'
+URL_SUFFIX_FORMATTER = 'inum:{}'
class EditClientDialog(JansGDialog, DialogUtils):
"""The Main Client Dialog that contain every thing related to The Client
@@ -62,14 +71,23 @@ def __init__(
delete_uma_resource (method, optional): handler invoked when deleting UMA-resources
"""
super().__init__(parent, title, buttons)
+
self.save_handler = save_handler
self.delete_uma_resource=delete_uma_resource
self.data = data
- self.title=title
- self.myparent.logger.debug('self.data in init: '+str(self.data))
+ self.title = title
+ self.nav_dialog_width = int(self.myparent.dialog_width*1.1)
self.prepare_tabs()
self.create_window()
+
+ def get_scope_by_inum(self, inum:str) -> dict:
+
+ for scope in common_data.scopes:
+ if scope['inum'] == inum or scope['dn'] == inum:
+ return scope
+ return {}
+
def save(self) -> None:
"""method to invoked when saving the dialog (Save button is pressed)
"""
@@ -78,7 +96,6 @@ def save(self) -> None:
self.data['disabled'] = not self.data['disabled']
for list_key in (
'redirectUris',
- 'scopes',
'postLogoutRedirectUris',
'contacts',
'authorizedOrigins',
@@ -89,11 +106,11 @@ def save(self) -> None:
if self.data[list_key]:
self.data[list_key] = self.data[list_key].splitlines()
+ self.data['scopes'] = [item[0] for item in self.client_scopes.entries]
+
if 'accessTokenAsJwt' in self.data:
self.data['accessTokenAsJwt'] = self.data['accessTokenAsJwt'] == 'jwt'
- self.myparent.logger.debug('self.data: '+str(self.data))
-
if 'rptAsJwt' in self.data:
self.data['rptAsJwt'] = self.data['rptAsJwt'] == 'jwt'
@@ -131,7 +148,7 @@ def save(self) -> None:
cfr = self.check_required_fields()
- self.myparent.logger.debug('CFR: '+str(cfr))
+
if not cfr:
return
@@ -139,11 +156,9 @@ def save(self) -> None:
if ditem in self.data and self.data[ditem] is None:
self.data.pop(ditem)
- close_me = True
if self.save_handler:
- close_me = self.save_handler(self)
- if close_me:
- self.future.set_result(DialogResult.ACCEPT)
+ self.save_handler(self)
+
def cancel(self) -> None:
"""method to invoked when canceling changes in the dialog (Cancel button is pressed)
@@ -168,18 +183,29 @@ def create_window(self) -> None:
(self.cancel, _("Cancel"))
],
height=self.myparent.dialog_height,
- width=self.myparent.dialog_width,
+ width=self.nav_dialog_width,
)
+
+ def fill_client_scopes(self):
+ self.client_scopes.entries = []
+ for scope_dn in self.data.get('scopes', []):
+ scope = self.get_scope_by_inum(scope_dn)
+ if scope:
+ label = scope.get('displayName') or scope.get('inum') or scope_dn
+ self.client_scopes.add_label(scope_dn, label)
+
def prepare_tabs(self) -> None:
"""Prepare the tabs for Edil Client Dialogs
"""
schema = self.myparent.cli_object.get_schema_from_reference('', '#/components/schemas/Client')
+
self.tabs = OrderedDict()
- self.tabs['Basic'] = HSplit([
+
+ basic_tab_widgets = [
self.myparent.getTitledText(
_("Client_ID"),
name='inum',
@@ -286,19 +312,33 @@ def prepare_tabs(self) -> None:
jans_help=self.myparent.get_help_from_schema(
self.myparent.cli_object.get_schema_from_reference('', ATTRIBUTE_SCHEMA_PATH),
'redirectUrisRegex'),
- style=cli_style.check_box),
+ style=cli_style.check_box)
+ ]
+
+ add_scope_button = VSplit([Window(), self.myparent.getButton(
+ text=_("Add Scope"),
+ name='oauth:logging:save',
+ jans_help=_("Add Scopes"),
+ handler=self.add_scopes)
+ ])
- self.myparent.getTitledText(_("Scopes"),
- name='scopes',
- value='\n'.join(self.data.get('scopes', [])),
- height=3,
- jans_help=self.myparent.get_help_from_schema(schema, 'scopes'),
- style=cli_style.check_box),
- ],width=D(),
- style=cli_style.tabs
+ self.client_scopes = JansLabelContainer(
+ title=_('Scopes'),
+ width=self.nav_dialog_width - 26,
+ on_display=self.myparent.data_display_dialog,
+ on_delete=self.delete_scope,
+ buttonbox=add_scope_button
)
+ self.fill_client_scopes()
+
+ basic_tab_widgets.append(self.client_scopes)
+
+
+ self.tabs['Basic'] = HSplit(basic_tab_widgets, width=D(), style=cli_style.tabs)
+
+
self.tabs['Tokens'] = HSplit([
self.myparent.getTitledRadioButton(
_("Access Token Type"),
@@ -620,7 +660,7 @@ def allow_spontaneous_changed(cb):
style=cli_style.check_box)
- self.tabs['Advanced Client Properties'] = HSplit([
+ self.tabs['Advanced Client Prop.'] = HSplit([
self.myparent.getTitledCheckBox(
_("Default Prompt login"),
@@ -780,16 +820,63 @@ def allow_spontaneous_changed(cb):
self.left_nav = list(self.tabs.keys())[0]
+
+ def scope_exists(self, scope_dn:str) -> bool:
+ for item_id, item_label in self.client_scopes.entries:
+ if item_id == scope_dn:
+ return True
+ return False
+
+
+ def add_scopes(self) -> None:
+
+ def add_selected_claims(dialog):
+ if 'scopes' not in self.data:
+ self.data['scopes'] = []
+
+ self.data['scopes'] += dialog.body.current_values
+ self.fill_client_scopes()
+
+ scopes_list = []
+
+ for scope in common_data.scopes:
+ if not self.scope_exists(scope['dn']):
+ scopes_list.append((scope['dn'], scope.get('displayName', '') or scope['inum']))
+
+ scopes_list.sort(key=lambda x: x[1])
+
+ check_box_list = CheckboxList(values=scopes_list)
+
+ buttons = [Button(_("Cancel")), Button(_("OK"), handler=add_selected_claims)]
+ dialog = JansGDialog(self.myparent, title=_("Select Scopes to add"), body=check_box_list, buttons=buttons)
+ self.myparent.show_jans_dialog(dialog)
+
+
+
+ def delete_scope(self, scope: list) -> None:
+
+
+ def do_delete_scope(dialog):
+ self.data['scopes'].remove(scope[0])
+ self.fill_client_scopes()
+
+ dialog = self.myparent.get_confirm_dialog(
+ message=_("Are you sure want to delete Scope:\n {} ?".format(scope[1])),
+ confirm_handler=do_delete_scope
+ )
+
+ self.myparent.show_jans_dialog(dialog)
+
+
def show_client_scopes(self) -> None:
- client_scopes = self.data.get('scopes')
- self.myparent.logger.debug('client_scopes: '+str(client_scopes))
+ client_scopes = self.data.get('scopes')#[0]
data = []
for i in client_scopes :
try :
inum = i.split(',')[0][5:]
rsponse = self.myparent.cli_object.process_command_by_id(
operation_id='get-oauth-scopes-by-inum',
- url_suffix='inum:{}'.format(inum),
+ url_suffix=URL_SUFFIX_FORMATTER.format(inum),
endpoint_args="",
data_fn=None,
data={}
@@ -804,9 +891,7 @@ def show_client_scopes(self) -> None:
pass
if rsponse.json().get('scopeType','') == 'spontaneous':
data.append(rsponse.json())
-
- self.myparent.logger.debug('datadata: '+str(data))
if not data :
data = "No Scope of type: Spontaneous"
@@ -862,7 +947,6 @@ def oauth_update_uma_resources (
if pattern:
endpoint_args +=',pattern:'+pattern
- self.myparent.logger.debug('DATA endpoint_args: '+str(endpoint_args))
try :
rsponse = self.myparent.cli_object.process_command_by_id(
operation_id='get-oauth-uma-resources-by-clientid',
@@ -897,7 +981,7 @@ def oauth_update_uma_resources (
try :
scope_response = self.myparent.cli_object.process_command_by_id(
operation_id='get-oauth-scopes-by-inum',
- url_suffix='inum:{}'.format(inum),
+ url_suffix=URL_SUFFIX_FORMATTER.format(inum),
endpoint_args='',
data_fn=None,
data={}
@@ -930,7 +1014,6 @@ def oauth_update_uma_resources (
on_enter=self.view_uma_resources,
on_display=self.myparent.data_display_dialog,
on_delete=self.delete_uma_resource,
- # selection_changed=self.data_selection_changed,
selectes=0,
headerColor='class:outh-client-navbar-headcolor',
entriesColor='class:outh-client-navbar-entriescolor',
diff --git a/jans-cli-tui/cli_tui/plugins/010_auth_server/main.py b/jans-cli-tui/cli_tui/plugins/010_auth_server/main.py
index f5fba51eba2..841ac78d10f 100755
--- a/jans-cli-tui/cli_tui/plugins/010_auth_server/main.py
+++ b/jans-cli-tui/cli_tui/plugins/010_auth_server/main.py
@@ -23,6 +23,8 @@
from prompt_toolkit.lexers import PygmentsLexer, DynamicLexer
from utils.static import DialogResult, cli_style, common_strings
from utils.utils import DialogUtils
+from utils.utils import common_data
+
from wui_components.jans_nav_bar import JansNavBar
from wui_components.jans_vetrical_nav import JansVerticalNav
from wui_components.jans_drop_down import DropDownWidget
@@ -66,9 +68,12 @@ def init_plugin(self) -> None:
self.app.create_background_task(self.get_appconfiguration())
self.schema = self.app.cli_object.get_schema_from_reference('', '#/components/schemas/AppConfiguration')
+ if not hasattr(common_data, 'scopes'):
+ self.app.create_background_task(self.retrieve_sopes())
+
async def get_appconfiguration(self) -> None:
'Coroutine for getting application configuration.'
-
+
cli_args = {'operation_id': 'get-properties'}
response = await self.app.loop.run_in_executor(self.app.executor, self.app.cli_requests, cli_args)
@@ -79,6 +84,16 @@ async def get_appconfiguration(self) -> None:
self.app_configuration = response.json()
self.oauth_logging()
+
+ async def retrieve_sopes(self) -> None:
+ """asyncio corotune for retreiving scopes
+ """
+ self.app.logger.debug("retreiving scopes")
+ cli_args = {'operation_id': 'get-oauth-scopes', 'endpoint_args': 'limit:200,startIndex:0'}
+ response = await self.app.loop.run_in_executor(self.app.executor, self.app.cli_requests, cli_args)
+ common_data.scopes = response.json()['entries']
+ self.app.logger.debug("scopes retreived")
+
def process(self):
"""No pre-processing for this plugin.
"""
@@ -119,7 +134,7 @@ def oauth_prepare_containers(self) -> None:
self.app.getButton(text=_("Get Clients"), name='oauth:clients:get', jans_help=_("Retreive first {} OpenID Connect clients").format(self.app.entries_per_page), handler=self.oauth_update_clients),
self.app.getTitledText(_("Search"), name='oauth:clients:search', jans_help=_(common_strings.enter_to_search), accept_handler=self.search_clients,style='class:outh_containers_clients.text'),
self.app.getButton(text=_("Add Client"), name='oauth:clients:add', jans_help=_("To add a new client press this button"), handler=self.add_client),
-
+
],
padding=3,
width=D(),
@@ -140,15 +155,22 @@ def oauth_prepare_containers(self) -> None:
self.oauth_containers['properties'] = HSplit([
VSplit([
- self.app.getTitledText(
- _("Search"),
- name='oauth:properties:search',
- jans_help=_(common_strings.enter_to_search),
- accept_handler=self.search_properties,
- style='class:outh_containers_scopes.text')
+ self.app.getTitledText(
+ _("Search"),
+ name='oauth:properties:search',
+ jans_help=_(common_strings.enter_to_search),
+ accept_handler=self.search_properties,
+ style='class:outh_containers_scopes.text'
+ ),
+ self.app.getButton(
+ _("Add Property"),
+ name='oauth:properties:add',
+ jans_help=_("Press this button to add a missing preperty"),
+ handler=self.add_property
+ ),
],
- padding=3,
- width=D(),
+ padding=3,
+ width=D(),
),
DynamicContainer(lambda: self.oauth_data_container['properties'])
],style='class:outh_containers_scopes')
@@ -239,7 +261,7 @@ async def coroutine():
headers=['Client ID', 'Client Name', 'Grant Types', 'Subject Type'],
preferred_size= [0,0,30,0],
data=data,
- on_enter=self.edit_client_dialog,
+ on_enter=self.edit_client,
on_display=self.app.data_display_dialog,
on_delete=self.delete_client,
get_help=(self.get_help,'Client'),
@@ -274,6 +296,47 @@ async def coroutine():
asyncio.ensure_future(coroutine())
+
+ def get_scopes(self, client_data) -> None:
+
+ async def coroutine():
+ cli_args = {'operation_id': 'get-oauth-scopes', 'endpoint_args':'limit:200,startIndex:0'}
+ self.app.start_progressing(_("Retreiving client Scopes..."))
+ response = await get_event_loop().run_in_executor(self.app.executor, self.app.cli_requests, cli_args)
+ self.app.stop_progressing()
+
+ if response.status_code not in (200, 201):
+ self.app.show_message(_("Error getting client Scopes"), str(response.text),tobefocused=self.oauth_containers['clients'])
+ return
+
+ try:
+ result = response.json()
+ except Exception:
+ self.app.show_message(_("Error getting client Scopes"), str(response.text),tobefocused=self.oauth_containers['clients'])
+ return
+
+ data_display_name =[]
+ data_base_dn =[]
+
+ for d in result.get('entries', []):
+ data_display_name.append(d.get('displayName',d.get('baseDn')))
+ data_base_dn.append(d.get('baseDn'))
+
+
+
+ for client_num in range(len(client_data)):
+
+ for scope_dn_num in range(len(client_data[client_num]['scopes'])):
+ if client_data[client_num]['scopes'][scope_dn_num] in data_base_dn:
+
+ index = data_base_dn.index(client_data[client_num]['scopes'][scope_dn_num])
+
+ client_data[client_num]['scopes'][scope_dn_num] = [data_display_name[index],data_base_dn[index].replace(',ou=scopes,o=jans','')]
+
+
+ asyncio.ensure_future(coroutine())
+ return client_data
+
def delete_client(self, **kwargs: Any) -> None:
"""This method for the deletion of the clients data
@@ -396,6 +459,50 @@ async def coroutine():
asyncio.ensure_future(coroutine())
+
+ def add_property(self):
+ missing_properties = []
+
+ for prop in self.schema['properties']:
+ if prop not in self.app_configuration:
+ missing_properties.append(prop)
+ missing_properties.sort()
+ missing_properties_data = [ [prop] for prop in missing_properties ]
+
+ def add_property(**params: Any) -> None:
+ self.add_property_dialog.future.set_result('add_property')
+ prop_name = params['passed'][0]
+ prop_val = ''
+ prop_type = self.schema['properties'][prop_name]['type']
+
+ if prop_type == 'string':
+ prop_val = ''
+ elif prop_type == 'array':
+ prop_val = []
+
+ passed = [prop_name, prop_val]
+
+ self.view_property(passed=passed, op_type='add')
+
+ properties = JansVerticalNav(
+ myparent=self.app,
+ headers=['Property Name'],
+ preferred_size=[0],
+ data=missing_properties_data,
+ on_enter=add_property,
+ get_help=(self.get_help,'AppConfiguration'),
+ selectes=0,
+ headerColor=cli_style.navbar_headcolor,
+ entriesColor=cli_style.navbar_entriescolor,
+ all_data=missing_properties
+ )
+
+ body = HSplit([properties])
+ buttons = [Button(_("Cancel"))]
+ self.add_property_dialog = JansGDialog(self.app, title=_("Select Property"), body=body, buttons=buttons)
+ self.app.show_jans_dialog(self.add_property_dialog)
+
+
def oauth_update_properties(
self,
start_index: Optional[int]= 0,
@@ -415,29 +522,16 @@ def oauth_update_properties(
# ------------------------------------------------------------------------------- #
# ----------------------------------- Search ------------------------------------ #
# ------------------------------------------------------------------------------- #
- porp_schema = self.app.cli_object.get_schema_from_reference('', '#/components/schemas/AppConfiguration')
data =[]
if pattern:
for k in self.app_configuration:
if pattern.lower() in k.lower():
- if k in porp_schema.get('properties', {}):
- data.append(
- [
- k,
- self.app_configuration[k],
- ]
- )
+ data.append([k, self.app_configuration[k]])
else:
for d in self.app_configuration:
- if d in porp_schema.get('properties', {}):
- data.append(
- [
- d,
- self.app_configuration[d],
- ]
- )
+ data.append([d, self.app_configuration[d]])
# ------------------------------------------------------------------------------- #
# --------------------------------- View Data ----------------------------------- #
@@ -445,9 +539,10 @@ def oauth_update_properties(
if data:
+ data.sort()
buttons = []
- if len(data)/20 >=1:
+ if len(data) > 20:
if start_index!=0:
handler_partial = partial(self.oauth_update_properties, start_index-1, pattern)
@@ -485,7 +580,7 @@ def oauth_update_properties(
if tofocus:
self.app.layout.focus(properties)
else:
- self.app.show_message(_("Oops"), _(common_strings.no_matching_result),tobefocused = self.oauth_containers['properties'])
+ self.app.show_message(_("Oops"), _(common_strings.no_matching_result), tobefocused= self.oauth_containers['properties'])
def properties_display_dialog(self, **params: Any) -> None:
"""Display the properties as Text
@@ -515,7 +610,7 @@ def view_property(self, **params: Any) -> None:
title = _("Edit property")
- dialog = ViewProperty(app=self.app, parent=self, title=title, data=selected_line_data)
+ dialog = ViewProperty(app=self.app, parent=self, title=title, data=selected_line_data, op_type=params.get('op_type', 'replace'))
self.app.show_jans_dialog(dialog)
@@ -547,6 +642,7 @@ def oauth_update_keys(self) -> None:
[
d['name'],
exps,
+ d['kid']
]
)
@@ -554,9 +650,9 @@ def oauth_update_keys(self) -> None:
keys = JansVerticalNav(
myparent=self.app,
- headers=['Name', 'Expiration'],
+ headers=['Name', 'Expiration','Kid'],
data=data,
- preferred_size=[0,0],
+ preferred_size=[0,0,0],
on_display=self.app.data_display_dialog,
selectes=0,
headerColor=cli_style.navbar_headcolor,
@@ -588,19 +684,26 @@ async def coroutine():
def edit_scope_dialog(self, **params: Any) -> None:
"""This Method show the scopes dialog for edit
"""
- selected_line_data = params['data']
+ selected_line_data = params['data']
dialog = EditScopeDialog(self.app, title=_("Edit Scopes"), data=selected_line_data, save_handler=self.save_scope)
self.app.show_jans_dialog(dialog)
- def edit_client_dialog(self, **params: Any) -> None:
+ def edit_client(self, **params: Any) -> None:
"""This Method show the scopes dialog for edit
"""
- selected_line_data = params['data']
- title = _("Edit user Data (Clients)")
+ selected_line_data = params['data']
+ title = _("Edit Clients")
+
+ self.edit_client_dialog = EditClientDialog(
+ parent=self.app,
+ title=title,
+ data=selected_line_data,
+ save_handler=self.save_client,
+ delete_uma_resource=self.delete_uma_resource
+ )
- self.EditClientDialog = EditClientDialog(self.app, title=title, data=selected_line_data, save_handler=self.save_client, delete_uma_resource=self.delete_uma_resource)
- self.app.show_jans_dialog(self.EditClientDialog)
+ self.app.show_jans_dialog(self.edit_client_dialog)
def save_client(self, dialog: Dialog) -> None:
"""This method to save the client data to server
@@ -612,21 +715,22 @@ def save_client(self, dialog: Dialog) -> None:
_type_: bool value to check the status code response
"""
+ async def coroutine():
+ self.app.start_progressing(_("Saving clinet ..."))
+ operation_id='put-oauth-openid-client' if dialog.data.get('inum') else 'post-oauth-openid-client'
+ cli_args = {'operation_id': operation_id, 'data': dialog.data}
+ response = await self.app.loop.run_in_executor(self.app.executor, self.app.cli_requests, cli_args)
+
+ dialog.future.set_result(DialogResult.ACCEPT)
+ self.app.stop_progressing()
+
+ if response.status_code in (200, 201):
+ self.oauth_update_clients()
+ else:
+ self.app.show_message(_("Error!"), _("An error ocurred while saving client:\n") + str(response.text), tobefocused=self.app.center_frame)
- response = self.app.cli_object.process_command_by_id(
- operation_id='put-oauth-openid-client' if dialog.data.get('inum') else 'post-oauth-openid-client',
- url_suffix='',
- endpoint_args='',
- data_fn='',
- data=dialog.data
- )
-
- self.app.stop_progressing()
- if response.status_code in (200, 201):
- self.oauth_update_clients()
- return None
+ asyncio.ensure_future(coroutine())
- self.app.show_message(_("Error!"), _("An error ocurred while saving client:\n") + str(response.text))
def save_scope(self, dialog: Dialog) -> None:
"""This method to save the client data to server
@@ -652,7 +756,7 @@ async def coroutine():
asyncio.ensure_future(coroutine())
- def search_scope(self, tbuffer:Buffer,) -> None:
+ def search_scope(self, tbuffer:Buffer) -> None:
"""This method handel the search for Scopes
Args:
@@ -661,7 +765,7 @@ def search_scope(self, tbuffer:Buffer,) -> None:
self.oauth_get_scopes(pattern=tbuffer.text)
- def search_clients(self, tbuffer:Buffer,) -> None:
+ def search_clients(self, tbuffer:Buffer) -> None:
"""This method handel the search for Clients
Args:
@@ -743,7 +847,7 @@ async def coroutine():
try:
self.app.layout.focus(focused_before)
except Exception:
- self.app.layout.focus(self.EditClientDialog)
+ self.app.layout.focus(self.edit_client_dialog)
if result.lower() == 'yes':
result = self.app.cli_object.process_command_by_id(
@@ -753,7 +857,7 @@ async def coroutine():
data_fn=None,
data={}
)
- self.EditClientDialog.oauth_get_uma_resources()
+ self.edit_client_dialog.oauth_get_uma_resources()
return result
diff --git a/jans-cli-tui/cli_tui/plugins/010_auth_server/view_property.py b/jans-cli-tui/cli_tui/plugins/010_auth_server/view_property.py
index 67ee4d7f09f..29731b1cf95 100644
--- a/jans-cli-tui/cli_tui/plugins/010_auth_server/view_property.py
+++ b/jans-cli-tui/cli_tui/plugins/010_auth_server/view_property.py
@@ -1,33 +1,32 @@
+import json
import asyncio
+from functools import partial
+from typing import Optional, Sequence
+
+from prompt_toolkit.application import Application
from prompt_toolkit.layout.dimension import D
from prompt_toolkit.formatted_text import AnyFormattedText
+from prompt_toolkit.layout.containers import HSplit
+from prompt_toolkit.widgets import Button, Dialog
+
from cli import config_cli
-from prompt_toolkit.layout.containers import (
- HSplit,
- DynamicContainer,
-)
-from prompt_toolkit.widgets import (
- Button,
- RadioList,
- Dialog,
- )
from utils.static import DialogResult, cli_style
from utils.utils import DialogUtils
from wui_components.jans_cli_dialog import JansGDialog
-from typing import Optional, Sequence
+from wui_components.jans_tab import JansTab
+
from utils.multi_lang import _
-import cli_style
class ViewProperty(JansGDialog, DialogUtils):
"""The Main UMA-resources Dialog to view UMA Resource Details
"""
def __init__(
self,
- app,
+ app: Application,
parent,
data:tuple,
- title: AnyFormattedText= "",
- buttons: Optional[Sequence[Button]]= []
+ title: AnyFormattedText='',
+ op_type: Optional[str]='replace'
)-> None:
"""init for `ViewProperty`, inherits from two diffrent classes `JansGDialog` and `DialogUtils`
@@ -39,20 +38,19 @@ def __init__(
parent (widget): This is the parent widget for the dialog
data (tuple): selected line data
title (AnyFormattedText, optional): The Main dialog title. Defaults to "".
- button_functions (list, optional): Dialog main buttons with their handlers. Defaults to [].
"""
- super().__init__(app, title, buttons)
- self.property, self.value = data[0],data[1]
+ super().__init__(app)
+ self.property_name, self.value = data[0], data[1]
self.app = app
self.myparent = parent
+ self.op_type = op_type
self.value_content = HSplit([],width=D())
- self.tabs = {}
- self.selected_tab = 'tab0'
- self.schema = self.app.cli_object.get_schema_from_reference('', '#/components/schemas/AppConfiguration')
-
+ self.tab_widget = None
+ self.widgets = []
+ self.buttons = [Button(text=_("Cancel"), handler=self.cancel), Button(text=_("Save"), handler=self.save)]
self.prepare_properties()
self.create_window()
-
+
def cancel(self) -> None:
"""method to invoked when canceling changes in the dialog (Cancel button is pressed)
"""
@@ -63,328 +61,188 @@ def save(self) -> None:
"""method to invoked when saving the dialog (Save button is pressed)
"""
- data_dict = {}
- list_data =[]
-
- if type(self.value) in [str,bool,int] :
- for wid in self.value_content.children:
- prop_type = self.get_item_data(wid)
- data = prop_type['value']
+ if len(self.widgets) == 1:
+ item_data = self.get_item_data(self.widgets[0])
+ data = item_data['value']
- elif (type(self.value)==list and (type(self.value[0]) not in [dict,list])):
-
- for wid in self.value_content.children:
- prop_type = self.get_item_data(wid)
-
- if self.get_type(prop_type['key']) != 'checkboxlist':
- data = prop_type['value'].split('\n')
- else:
- data = prop_type['value']
-
- elif type(self.value) == dict :
- for wid in self.value_content.children:
- for k in wid.children :
- prop_type = self.get_item_data(k)
- data_dict[prop_type['key']]=prop_type['value']
- data = data_dict
-
- elif type(self.value) == list and type(self.value[0]) == dict:
- for tab in self.tabs:
- data_dict = {}
- for k in self.tabs[tab].children :
- prop_type = self.get_item_data(k.children[0])
- data_dict[prop_type['key']]=prop_type['value']
- list_data.append(data_dict)
- data = list_data
- else :
- self.app.logger.debug("self.value: "+str(self.value))
- self.app.logger.debug("type self.value: "+str(type(self.value)))
+ elif self.tab_widget:
data = []
-
- # ------------------------------------------------------------#
- # --------------------- Patch to server ----------------------#
- # ------------------------------------------------------------#
- if data :
-
- cli_args = {'operation_id': 'patch-properties', 'data': [ {'op':'replace', 'path': self.property, 'value': data } ]}
-
- async def coroutine():
- self.app.start_progressing()
- response = await self.app.loop.run_in_executor(self.app.executor, self.app.cli_requests, cli_args)
- self.app.stop_progressing()
- self.myparent.app_configuration = response
- self.future.set_result(DialogResult.ACCEPT)
- self.myparent.oauth_update_properties(start_index=self.myparent.oauth_update_properties_start_index)
- asyncio.ensure_future(coroutine())
-
- def get_type(self,prop):
- """This Method get a property and get its type from schema to return the widget type to implement
-
- Args:
- prop (str): The property name
-
- Returns:
- str: the widget type to implement
- """
- try :
- proper = self.schema.get('properties', {})[prop]
-
- if proper['type'] == 'string':
- prop_type= 'TitledText'
-
- elif proper['type'] == 'integer':
- prop_type= 'int-TitledText'
-
- elif proper['type'] == 'boolean':
- prop_type= 'TitledCheckBox'
-
- elif proper['type'] == 'object':
- prop_type= 'dict'
-
- elif proper['type'] == 'array':
- if 'enum' in proper or ('enum' in proper['items']):
- prop_type= 'checkboxlist'
+ tabn = []
+ for tab in self.tab_widget.tabs:
+ tabn.append(tab[0])
+ if self.tab_widget.tab_content_type == 'object':
+ tab_data = self.make_data_from_dialog({tab[0]: tab[1]})
else:
- if type(self.value[0]) == dict:
- prop_type= 'list-dict'
- elif type(self.value[0]) == list:
- prop_type= 'list-list'
- else:
- prop_type= 'long-TitledText'
- except Exception:
- prop_type = None
-
- return prop_type
-
- def get_listValues(self,prop,type=None):
- """This method get list values for properties own Enum values
+ tab_data_tmp = self.make_data_from_dialog({tab[0]: tab[1]})
+ tab_data = tab_data_tmp[self.property_name]
+ data.append(tab_data)
+ else:
+ data = {}
+ for widget in self.widgets:
+ item_data = self.get_item_data(widget)
+ data[item_data['key']] = item_data['value']
+
+ cli_args = {'operation_id': 'patch-properties', 'data': [ {'op':self.op_type, 'path': self.property_name, 'value': data } ]}
+
+ async def coroutine():
+ self.app.start_progressing()
+ response = await self.app.loop.run_in_executor(self.app.executor, self.app.cli_requests, cli_args)
+ self.app.stop_progressing()
+ self.myparent.app_configuration = response
+ self.future.set_result(DialogResult.ACCEPT)
+ self.myparent.oauth_update_properties(start_index=self.myparent.oauth_update_properties_start_index)
+ asyncio.ensure_future(coroutine())
+
+
+ def get_widgets(
+ self,
+ properties:dict,
+ values: dict=None,
+ styles: dict=None
+ ) -> list:
+ """Returns list of widgets for properties
Args:
- prop (str): The property name
- type (_type_, optional): If the Items in Property properties had a nasted Enum. Defaults to None.
+ properties (dict): properties to get widget
+ values (dict): values of properties
+ styes (dict): styles for widgets
+ """
- Returns:
- list: List of the properties enum to choose from
+ if not values:
+ values = {self.property_name: self.value}
+ if not styles:
+ styles = {'widget_style':'', 'string': cli_style.edit_text, 'boolean': cli_style.check_box}
+
+ widgets = []
+ for item_name in properties:
+ item = properties[item_name]
+ if item['type'] in ('integer', 'string'):
+ widgets.append(
+ self.app.getTitledText(
+ item_name,
+ name=item_name,
+ value=str(values.get(item_name,'')),
+ text_type=item['type'],
+ style=styles['string'],
+ widget_style=styles['widget_style']
+ )
+ )
+
+ elif item['type'] == 'boolean':
+ widgets.append(
+ self.app.getTitledCheckBox(
+ item_name,
+ name=item_name,
+ checked=values.get(item_name, False),
+ style=styles['boolean'],
+ widget_style=styles['widget_style']
+ )
+ )
+
+ elif item['type'] == 'array' and item['items'].get('enum'):
+ widgets.append(
+ self.app.getTitledCheckBoxList(
+ item_name,
+ name=item_name,
+ values=item['items']['enum'],
+ current_values=values.get(item_name, []),
+ style=styles['boolean'],
+ widget_style=styles['widget_style']
+ )
+ )
+
+ elif item['type'] == 'array' and item['items'].get('type') in ('string', 'integer'):
+ titled_text = self.app.getTitledText(
+ item_name,
+ name=item_name,
+ height=4,
+ text_type = item['items']['type'],
+ value='\n'.join(values.get(item_name, [])),
+ style=styles['string'],
+ widget_style=styles['widget_style']
+ )
+ titled_text.jans_list_type = True
+ widgets.append(titled_text)
+
+ return widgets
+
+
+ def add_tab_element(
+ self,
+ properties:dict,
+ values: dict
+ ) -> None:
+ """Adds element to tab widget
+ Args:
+ properties (dict): properties of element to add
+ values (dict): values of properties
"""
- try :
- if type !='nasted':
- list_values= self.schema.get('properties', {})[prop]['items']['enum']
- else:
- list_values= self.schema.get('properties', {})[prop]['items']['items']['enum']
- except Exception:
- list_values = []
+ tab_name = '#{}'.format(len(self.tab_widget.tabs)+1)
+ tab_widgets = self.get_widgets(properties, values=values, styles={'widget_style': cli_style.tab_selected, 'string': cli_style.tab_selected, 'boolean': cli_style.tab_selected})
+ self.tab_widget.add_tab(tab_name, HSplit(tab_widgets, style=cli_style.tab_selected))
+ if not values:
+ self.tab_widget.set_tab(tab_name)
- return list_values
+ def delete_tab_element(self) -> None:
+ """Deletes currenlt oelemnt form tab widget
+ """
+ cur_tab = self.tab_widget.cur_tab
+ cur_tab_name = self.tab_widget.tabs[cur_tab][0]
+ self.tab_widget.remove_tab(cur_tab_name)
def prepare_properties(self):
"""This method build the main value_content to edit the properties
"""
- tab_temp = 'tab{}'
- prop_type = self.get_type(self.property)
-
- if prop_type == 'TitledText':
- self.value_content= HSplit([self.app.getTitledText(
- self.property,
- name=self.property,
- value=self.value,
- style=cli_style.edit_text
- ),
- ],width=D())
-
- elif prop_type == 'int-TitledText':
- self.value_content= HSplit([self.app.getTitledText(
- self.property,
- name=self.property,
- value=self.value,
- text_type='integer',
- style=cli_style.edit_text
- ),
- ],width=D())
-
- elif prop_type == 'long-TitledText':
- self.value_content= HSplit([self.app.getTitledText(
- self.property,
- name=self.property,
- height=3,
- value='\n'.join(self.value),
- style=cli_style.edit_text
- ),
- ],width=D())
-
- elif prop_type == 'list-list':
- self.value_content= HSplit([
- self.app.getTitledCheckBoxList(
- self.property,
- name=self.property,
- values=self.get_listValues(self.property,'nasted'),
- style='class:outh-client-checkboxlist'),
- ],width=D())
-
- elif prop_type == 'checkboxlist':
- self.value_content= HSplit([
- self.app.getTitledCheckBoxList(
- self.property,
- name=self.property,
- values=self.get_listValues(self.property),
- style='class:outh-client-checkboxlist'),
- ],width=D())
-
- elif prop_type == 'list-dict':
- tab_num = len(self.value)
- tabs = []
- for i in range(tab_num) :
- tabs.append((tab_temp.format(i), tab_temp.format(i)))
-
-
- for tab in self.value:
- tab_list=[]
- for item in tab:
- if type(tab[item]) == str:
- tab_list.append(HSplit([self.app.getTitledText(
- item ,
- name=item,
- value=tab[item],
- style=cli_style.edit_text
- ),
- ],width=D()))
-
- if type(tab[item]) == int :
- tab_list.append(HSplit([self.app.getTitledText(
- item ,
- name=item,
- value=tab[item],
- text_type='integer',
- style=cli_style.edit_text
- ),
- ],width=D()))
-
- elif type(tab[item]) == list:
- tab_list.append(HSplit([self.app.getTitledText(
- item,
- name=item,
- height=3,
- value='\n'.join(tab[item]),
- style=cli_style.edit_text
- ),
- ],width=D()))
-
- elif type(tab[item]) == bool:
- tab_list.append(HSplit([
- self.app.getTitledCheckBox(
- item,
- name=item,
- checked= tab[item],
- style=cli_style.checkbox),
- ],width=D()))
-
- self.tabs[tab_temp.format(self.value.index(tab))] = HSplit(tab_list,width=D())
-
- self.value_content=HSplit([
- self.app.getTitledRadioButton(
- _("Tab Num"),
- name='tabNum',
- current_value=self.selected_tab,
- values=tabs,
- on_selection_changed=self.tab_selection_changed,
- style='class:outh-scope-radiobutton'),
-
- DynamicContainer(lambda: self.tabs[self.selected_tab]),
-
- ],width=D())
-
- elif prop_type == 'TitledCheckBox':
- self.value_content= HSplit([
- self.app.getTitledCheckBox(
- self.property,
- name=self.property,
- checked= self.value,
- style=cli_style.checkbox),
- ],width=D())
-
- elif prop_type == 'dict':
- dict_list=[]
- for item in self.value:
- if type(self.value[item]) == str:
- dict_list.append(HSplit([self.app.getTitledText(
- item ,
- name=item,
- value=self.value[item],
- style=cli_style.edit_text
- ),
- ],width=D()))
-
- elif type(self.value[item]) == int :
- dict_list.append(HSplit([self.app.getTitledText(
- item ,
- name=item,
- value=self.value[item],
- text_type='integer',
- style=cli_style.edit_text
- ),
- ],width=D()))
-
- elif type(self.value[item]) == list:
- dict_list.append(HSplit([self.app.getTitledText(
- item,
- name=item,
- height=3,
- value='\n'.join(self.value[item]),
- style=cli_style.edit_text
- ),
- ],width=D()))
-
- elif type(self.value[item]) == bool:
- dict_list.append(HSplit([
- self.app.getTitledCheckBox(
- item,
- name=item,
- checked= self.value[item],
- style=cli_style.checkbox),
- ],width=D()))
-
- else :
- dict_list.append(HSplit([self.app.getTitledText(
- item,
- name=item,
- value="No Items Here",
- style=cli_style.edit_text,
- read_only=True,
- ),
- ],width=D()))
- self.value_content= HSplit(dict_list,width=D())
-
- def create_window(self):
-
- self.dialog = Dialog(title=self.property,
- body=
- HSplit([
- self.value_content,
- ], padding=1,width=100,style='class:outh-uma-tabs'
- ),
- buttons=[
- Button(
- text=_("Cancel"),
- handler=self.cancel,
- ) ,
- Button(
- text=_("Save"),
- handler=self.save,
- ) , ],
+ properties = self.myparent.schema['properties'][self.property_name]
+
+ if properties['type'] in ('string', 'integer', 'boolean'):
+ self.widgets = self.get_widgets({self.property_name: properties})
+
+ elif properties['type'] == 'array':
+ if properties['items'].get('type') in ('string', 'integer', 'boolean'):
+ self.widgets = self.get_widgets({self.property_name: properties})
+
+ elif properties['items'].get('type') == 'array':
+ self.tab_widget = JansTab(self)
+ self.tab_widget.tab_content_type = 'array'
+ item_property = {self.property_name: properties['items']}
+ for entry_value in self.value:
+ self.add_tab_element(item_property, {self.property_name: entry_value})
+
+ self.value_content = self.tab_widget
+ add_entry_partial = partial(self.add_tab_element, item_property, {})
+ self.buttons.append(Button(_("Add"), handler=add_entry_partial))
+ self.buttons.append(Button(_("Delete"), handler=self.delete_tab_element))
+
+ elif properties.get('properties'):
+ self.tab_widget = JansTab(self)
+ self.tab_widget.tab_content_type = 'object'
+ for entry_value in self.value:
+ self.add_tab_element(properties['properties'], entry_value)
+ self.value_content = self.tab_widget
+ add_entry_partial = partial(self.add_tab_element, properties['properties'], {})
+ self.buttons.append(Button(_("Add"), handler=add_entry_partial))
+ self.buttons.append(Button(_("Delete"), handler=self.delete_tab_element))
+
+ elif properties['type'] == 'object':
+ self.widgets = self.get_widgets(properties['properties'], values=self.value)
+
+ if not self.tab_widget:
+ self.value_content = HSplit(self.widgets, width=D())
+
+ def create_window(self) -> None:
+ """Creates dialog window
+ """
+
+ self.dialog = Dialog(
+ title=self.property_name,
+ body= HSplit([self.value_content], padding=1,width=100,style='class:outh-uma-tabs'),
+ buttons=self.buttons,
with_background=False,
)
- def tab_selection_changed(
- self,
- cb: RadioList,
- ) -> None:
- """This method for properties that implemented in multi tab
-
- Args:
- cb (RadioList): the New Value from the nasted tab
- """
- self.selected_tab = cb.current_value
def __pt_container__(self)-> Dialog:
"""The container for the dialog itself
diff --git a/jans-cli-tui/cli_tui/plugins/020_fido/main.py b/jans-cli-tui/cli_tui/plugins/020_fido/main.py
index 46721cef41e..d3617a775a7 100755
--- a/jans-cli-tui/cli_tui/plugins/020_fido/main.py
+++ b/jans-cli-tui/cli_tui/plugins/020_fido/main.py
@@ -12,6 +12,8 @@
from wui_components.jans_cli_dialog import JansGDialog
from utils.multi_lang import _
from utils.utils import DialogUtils
+from utils.static import cli_style
+
class Plugin(DialogUtils):
"""This is a general class for plugins
@@ -26,8 +28,9 @@ def __init__(
app (Generic): The main Application class
"""
self.app = app
- self.pid = 'fido'
+ self.pid = 'fido2'
self.name = '[F]IDO'
+ self.server_side_plugin = True
self.page_entered = False
self.data = {}
self.prepare_navbar()
@@ -93,12 +96,12 @@ def create_widgets(self):
self.schema = self.app.cli_object.get_schema_from_reference('Fido2', '#/components/schemas/AppConfiguration')
self.tabs['configuration'] = HSplit([
- self.app.getTitledText(_("Issuer"), name='issuer', value=self.data.get('issuer',''), jans_help=self.app.get_help_from_schema(self.schema, 'issuer'), style='class:outh-scope-text'),
- self.app.getTitledText(_("Base Endpoint"), name='baseEndpoint', value=self.data.get('baseEndpoint',''), jans_help=self.app.get_help_from_schema(self.schema, 'baseEndpoint'), style='class:outh-scope-text'),
- self.app.getTitledText(_("Clean Service Interval"), name='cleanServiceInterval', value=self.data.get('cleanServiceInterval',''), jans_help=self.app.get_help_from_schema(self.schema, 'cleanServiceInterval'), style='class:outh-scope-text', text_type='integer'),
- self.app.getTitledText(_("Clean Service Batch ChunkSize"), name='cleanServiceBatchChunkSize', value=self.data.get('cleanServiceBatchChunkSize',''), jans_help=self.app.get_help_from_schema(self.schema, 'cleanServiceBatchChunkSize'), style='class:outh-scope-text', text_type='integer'),
- self.app.getTitledCheckBox(_("Use Local Cache"), name='useLocalCache', checked=self.data.get('useLocalCache'), jans_help=self.app.get_help_from_schema(self.schema, 'useLocalCache'), style='class:outh-client-checkbox'),
- self.app.getTitledCheckBox(_("Disable Jdk Logger"), name='disableJdkLogger', checked=self.data.get('disableJdkLogger'), jans_help=self.app.get_help_from_schema(self.schema, 'disableJdkLogger'), style='class:outh-client-checkbox'),
+ self.app.getTitledText(_("Issuer"), name='issuer', value=self.data.get('issuer',''), jans_help=self.app.get_help_from_schema(self.schema, 'issuer'), style='class:outh-scope-text',widget_style=cli_style.scim_widget),
+ self.app.getTitledText(_("Base Endpoint"), name='baseEndpoint', value=self.data.get('baseEndpoint',''), jans_help=self.app.get_help_from_schema(self.schema, 'baseEndpoint'), style='class:outh-scope-text',widget_style=cli_style.scim_widget),
+ self.app.getTitledText(_("Clean Service Interval"), name='cleanServiceInterval', value=self.data.get('cleanServiceInterval',''), jans_help=self.app.get_help_from_schema(self.schema, 'cleanServiceInterval'), style='class:outh-scope-text', text_type='integer',widget_style=cli_style.scim_widget),
+ self.app.getTitledText(_("Clean Service Batch ChunkSize"), name='cleanServiceBatchChunkSize', value=self.data.get('cleanServiceBatchChunkSize',''), jans_help=self.app.get_help_from_schema(self.schema, 'cleanServiceBatchChunkSize'), style='class:outh-scope-text', text_type='integer',widget_style=cli_style.scim_widget),
+ self.app.getTitledCheckBox(_("Use Local Cache"), name='useLocalCache', checked=self.data.get('useLocalCache'), jans_help=self.app.get_help_from_schema(self.schema, 'useLocalCache'), style=cli_style.check_box,widget_style=cli_style.scim_widget),
+ self.app.getTitledCheckBox(_("Disable Jdk Logger"), name='disableJdkLogger', checked=self.data.get('disableJdkLogger'), jans_help=self.app.get_help_from_schema(self.schema, 'disableJdkLogger'), style=cli_style.check_box,widget_style=cli_style.scim_widget),
self.app.getTitledWidget(
_("Logging Level"),
name='loggingLevel',
@@ -107,13 +110,13 @@ def create_widgets(self):
value=self.data.get('loggingLevel')
),
jans_help=self.app.get_help_from_schema(self.schema, 'loggingLevel'),
- style='class:outh-client-dropdown'
+ style=cli_style.edit_text
),
- self.app.getTitledText(_("Logging Layout"), name='loggingLayout', value=self.data.get('loggingLayout',''), jans_help=self.app.get_help_from_schema(self.schema, 'loggingLayout'), style='class:outh-scope-text'),
- self.app.getTitledText(_("External Logger Configuration"), name='externalLoggerConfiguration', value=self.data.get('externalLoggerConfiguration',''), jans_help=self.app.get_help_from_schema(self.schema, 'externalLoggerConfiguration'), style='class:outh-scope-text'),
- self.app.getTitledText(_("Metric Reporter Interval"), name='metricReporterInterval', value=self.data.get('metricReporterInterval',''), jans_help=self.app.get_help_from_schema(self.schema, 'metricReporterInterval'), style='class:outh-scope-text', text_type='integer'),
- self.app.getTitledText(_("Metric Reporter Keep Data Days"), name='metricReporterKeepDataDays', value=self.data.get('metricReporterKeepDataDays',''), jans_help=self.app.get_help_from_schema(self.schema, 'metricReporterKeepDataDays'), style='class:outh-scope-text', text_type='integer'),
- self.app.getTitledCheckBox(_("Metric Reporter Enabled"), name='metricReporterEnabled', checked=self.data.get('metricReporterEnabled'), jans_help=self.app.get_help_from_schema(self.schema, 'metricReporterEnabled'), style='class:outh-client-checkbox'),
+ self.app.getTitledText(_("Logging Layout"), name='loggingLayout', value=self.data.get('loggingLayout',''), jans_help=self.app.get_help_from_schema(self.schema, 'loggingLayout'), style='class:outh-scope-text',widget_style=cli_style.scim_widget),
+ self.app.getTitledText(_("External Logger Configuration"), name='externalLoggerConfiguration', value=self.data.get('externalLoggerConfiguration',''), jans_help=self.app.get_help_from_schema(self.schema, 'externalLoggerConfiguration'), style='class:outh-scope-text',widget_style=cli_style.scim_widget),
+ self.app.getTitledText(_("Metric Reporter Interval"), name='metricReporterInterval', value=self.data.get('metricReporterInterval',''), jans_help=self.app.get_help_from_schema(self.schema, 'metricReporterInterval'), style='class:outh-scope-text', text_type='integer',widget_style=cli_style.scim_widget),
+ self.app.getTitledText(_("Metric Reporter Keep Data Days"), name='metricReporterKeepDataDays', value=self.data.get('metricReporterKeepDataDays',''), jans_help=self.app.get_help_from_schema(self.schema, 'metricReporterKeepDataDays'), style='class:outh-scope-text', text_type='integer',widget_style=cli_style.scim_widget),
+ self.app.getTitledCheckBox(_("Metric Reporter Enabled"), name='metricReporterEnabled', checked=self.data.get('metricReporterEnabled'), jans_help=self.app.get_help_from_schema(self.schema, 'metricReporterEnabled'), style=cli_style.check_box,widget_style=cli_style.scim_widget),
self.app.getTitledText(
_("Person Custom Object Classes"),
name='personCustomObjectClassList',
@@ -121,9 +124,12 @@ def create_widgets(self):
height=3,
jans_help=self.app.get_help_from_schema(self.schema, 'personCustomObjectClassList'),
style='class:outh-scope-text'
+ ,widget_style=cli_style.scim_widget
),
Window(height=1),
- VSplit([Window(), Button(_("Save"), handler=self.save_config), Window()]),
+ VSplit([Window(),
+ HSplit([Button(_("Save"), handler=self.save_config)]),
+ Window()]),
],
width=D()
)
@@ -160,17 +166,17 @@ def create_widgets(self):
)
self.tabs['static'] = HSplit([
- self.app.getTitledText(_("Authenticator Certificates Folder"), name='authenticatorCertsFolder', value=fido2_static_config.get('authenticatorCertsFolder',''), jans_help=self.app.get_help_from_schema(static_schema, 'authenticatorCertsFolder'), style='class:outh-scope-text'),
- self.app.getTitledText(_("MDS Access Token"), name='mdsAccessToken', value=fido2_static_config.get('mdsAccessToken',''), jans_help=self.app.get_help_from_schema(static_schema, 'mdsAccessToken'), style='class:outh-scope-text'),
- self.app.getTitledText(_("MDS TOC Certificates Folder"), name='mdsCertsFolder', value=fido2_static_config.get('mdsCertsFolder',''), jans_help=self.app.get_help_from_schema(static_schema, 'mdsCertsFolder'), style='class:outh-scope-text'),
- self.app.getTitledText(_("MDS TOC Files Folder"), name='mdsTocsFolder', value=fido2_static_config.get('mdsTocsFolder',''), jans_help=self.app.get_help_from_schema(static_schema, 'mdsTocsFolder'), style='class:outh-scope-text'),
- self.app.getTitledCheckBox(_("Check U2f Attestations"), name='checkU2fAttestations', checked=fido2_static_config.get('checkU2fAttestations'), jans_help=self.app.get_help_from_schema(static_schema, 'checkU2fAttestations'), style='class:outh-client-checkbox'),
- self.app.getTitledCheckBox(_("Check U2f Attestations"), name='checkU2fAttestations', checked=fido2_static_config.get('checkU2fAttestations'), jans_help=self.app.get_help_from_schema(static_schema, 'checkU2fAttestations'), style='class:outh-client-checkbox'),
- self.app.getTitledText(_("Unfinished Request Expiration"), name='unfinishedRequestExpiration', value=fido2_static_config.get('unfinishedRequestExpiration',''), jans_help=self.app.get_help_from_schema(static_schema, 'unfinishedRequestExpiration'), style='class:outh-scope-text', text_type='integer'),
- self.app.getTitledText(_("Authentication History Expiration"), name='authenticationHistoryExpiration', value=fido2_static_config.get('authenticationHistoryExpiration',''), jans_help=self.app.get_help_from_schema(static_schema, 'authenticationHistoryExpiration'), style='class:outh-scope-text', text_type='integer'),
- self.app.getTitledText(_("Server Metadata Folder"), name='serverMetadataFolder', value=fido2_static_config.get('serverMetadataFolder',''), jans_help=self.app.get_help_from_schema(static_schema, 'serverMetadataFolder'), style='class:outh-scope-text'),
-
- self.app.getTitledCheckBox(_("User Auto Enrollment"), name='userAutoEnrollment', checked=fido2_static_config.get('userAutoEnrollment'), jans_help=self.app.get_help_from_schema(static_schema, 'userAutoEnrollment'), style='class:outh-client-checkbox'),
+ self.app.getTitledText(_("Authenticator Certificates Folder"), name='authenticatorCertsFolder', value=fido2_static_config.get('authenticatorCertsFolder',''), jans_help=self.app.get_help_from_schema(static_schema, 'authenticatorCertsFolder'), style='class:outh-scope-text',widget_style=cli_style.scim_widget),
+ self.app.getTitledText(_("MDS Access Token"), name='mdsAccessToken', value=fido2_static_config.get('mdsAccessToken',''), jans_help=self.app.get_help_from_schema(static_schema, 'mdsAccessToken'), style='class:outh-scope-text',widget_style=cli_style.scim_widget),
+ self.app.getTitledText(_("MDS TOC Certificates Folder"), name='mdsCertsFolder', value=fido2_static_config.get('mdsCertsFolder',''), jans_help=self.app.get_help_from_schema(static_schema, 'mdsCertsFolder'), style='class:outh-scope-text',widget_style=cli_style.scim_widget),
+ self.app.getTitledText(_("MDS TOC Files Folder"), name='mdsTocsFolder', value=fido2_static_config.get('mdsTocsFolder',''), jans_help=self.app.get_help_from_schema(static_schema, 'mdsTocsFolder'), style='class:outh-scope-text',widget_style=cli_style.scim_widget),
+ self.app.getTitledCheckBox(_("Check U2f Attestations"), name='checkU2fAttestations', checked=fido2_static_config.get('checkU2fAttestations'), jans_help=self.app.get_help_from_schema(static_schema, 'checkU2fAttestations'), style=cli_style.check_box,widget_style=cli_style.scim_widget),
+ self.app.getTitledCheckBox(_("Check U2f Attestations"), name='checkU2fAttestations', checked=fido2_static_config.get('checkU2fAttestations'), jans_help=self.app.get_help_from_schema(static_schema, 'checkU2fAttestations'), style=cli_style.check_box,widget_style=cli_style.scim_widget),
+ self.app.getTitledText(_("Unfinished Request Expiration"), name='unfinishedRequestExpiration', value=fido2_static_config.get('unfinishedRequestExpiration',''), jans_help=self.app.get_help_from_schema(static_schema, 'unfinishedRequestExpiration'), style='class:outh-scope-text', text_type='integer',widget_style=cli_style.scim_widget),
+ self.app.getTitledText(_("Authentication History Expiration"), name='authenticationHistoryExpiration', value=fido2_static_config.get('authenticationHistoryExpiration',''), jans_help=self.app.get_help_from_schema(static_schema, 'authenticationHistoryExpiration'), style='class:outh-scope-text', text_type='integer',widget_style=cli_style.scim_widget),
+ self.app.getTitledText(_("Server Metadata Folder"), name='serverMetadataFolder', value=fido2_static_config.get('serverMetadataFolder',''), jans_help=self.app.get_help_from_schema(static_schema, 'serverMetadataFolder'), style='class:outh-scope-text',widget_style=cli_style.scim_widget),
+
+ self.app.getTitledCheckBox(_("User Auto Enrollment"), name='userAutoEnrollment', checked=fido2_static_config.get('userAutoEnrollment'), jans_help=self.app.get_help_from_schema(static_schema, 'userAutoEnrollment'), style=cli_style.check_box,widget_style=cli_style.scim_widget),
self.app.getTitledText(
_("Requested Credential Types"),
name='requestedCredentialTypes',
@@ -178,21 +184,27 @@ def create_widgets(self):
height=3,
jans_help=self.app.get_help_from_schema(static_schema, 'requestedCredentialTypes'),
style='class:outh-scope-text'
+ ,widget_style=cli_style.scim_widget
),
VSplit([
- Label(text=requested_parties_title, style='class:script-label', width=len(requested_parties_title)+1),
+ HSplit([Label(text=requested_parties_title, style='class:script-label', width=len(requested_parties_title)+1),]),
+
self.requested_parties_container,
Window(width=2),
HSplit([
Window(height=1),
- Button(text=add_party_title, width=len(add_party_title)+4, handler=partial(self.edit_requested_party, jans_name='editRequestedPary')),
+ HSplit([Button(text=add_party_title, width=len(add_party_title)+4, handler=partial(self.edit_requested_party, jans_name='editRequestedPary'))]),
+
]),
],
height=5, width=D(),
),
- VSplit([Window(), Button(_("Save"), handler=self.save_config), Window()]),
+ VSplit([Window(),
+ HSplit([Button(_("Save"), handler=self.save_config)]),
+
+ Window()]),
],
width=D()
)
@@ -261,7 +273,7 @@ def nav_selection_changed(
"""
if selection in self.tabs:
- self.main_area = self.tabs[selection]
+ self.main_area = HSplit([self.tabs[selection]],height=D())
else:
self.main_area = self.app.not_implemented
diff --git a/jans-cli-tui/cli_tui/plugins/030_scim/main.py b/jans-cli-tui/cli_tui/plugins/030_scim/main.py
index c2855473e90..96127155eb4 100755
--- a/jans-cli-tui/cli_tui/plugins/030_scim/main.py
+++ b/jans-cli-tui/cli_tui/plugins/030_scim/main.py
@@ -5,6 +5,7 @@
from prompt_toolkit.widgets import Button, Frame
from wui_components.jans_drop_down import DropDownWidget
from utils.utils import DialogUtils
+from utils.static import cli_style
from utils.multi_lang import _
class Plugin(DialogUtils):
@@ -22,6 +23,7 @@ def __init__(
self.app = app
self.pid = 'scim'
self.name = '[S]CIM'
+ self.server_side_plugin = True
self.app_config = {}
self.widgets_ready = False
self.container = Frame(
@@ -42,16 +44,16 @@ def create_widgets(self) -> None:
self.save_button = Button(_("Save"), handler=self.save_app_config)
schema = self.app.cli_object.get_schema_from_reference('SCIM', '#/components/schemas/AppConfiguration')
self.container = HSplit([
- self.app.getTitledText(_("Base DN"), name='baseDN', value=self.app_config.get('baseDN',''), jans_help=self.app.get_help_from_schema(schema, 'baseDN'), read_only=True, style='class:outh-scope-text'),
- self.app.getTitledText(_("Application Url"), name='applicationUrl', value=self.app_config.get('applicationUrl',''), jans_help=self.app.get_help_from_schema(schema, 'applicationUrl'), style='class:outh-scope-text'),
- self.app.getTitledText(_("Base Endpoint"), name='baseEndpoint', value=self.app_config.get('baseEndpoint',''), jans_help=self.app.get_help_from_schema(schema, 'baseEndpoint'), style='class:outh-scope-text'),
- self.app.getTitledText(_("Person Custom Object Class"), name='personCustomObjectClass', value=self.app_config.get('personCustomObjectClass',''), jans_help=self.app.get_help_from_schema(schema, 'personCustomObjectClass'), style='class:outh-scope-text'),
- self.app.getTitledText(_("Auth Issuer"), name='oxAuthIssuer', value=self.app_config.get('oxAuthIssuer',''), jans_help=self.app.get_help_from_schema(schema, 'oxAuthIssuer'), style='class:outh-scope-text'),
- self.app.getTitledRadioButton(_("Protection Mode"), name='protectionMode', values=[('OAUTH', 'OAUTH'),('BYPASS', 'BYPASS')], current_value=self.app_config.get('protectionMode'), jans_help=self.app.get_help_from_schema(schema, 'protectionMode'), style='class:outh-client-radiobutton'),
- self.app.getTitledText(_("Max Count"), name='maxCount', value=self.app_config.get('maxCount',''), jans_help=self.app.get_help_from_schema(schema, 'maxCount'), text_type='integer', style='class:outh-scope-text'),
- self.app.getTitledText(_("Bulk Max Operations"), name='bulkMaxOperations', value=self.app_config.get('bulkMaxOperations',''), jans_help=self.app.get_help_from_schema(schema, 'bulkMaxOperations'), text_type='integer', style='class:outh-scope-text'),
- self.app.getTitledText(_("Bulk Max Payload Size"), name='bulkMaxPayloadSize', value=self.app_config.get('bulkMaxPayloadSize',''), jans_help=self.app.get_help_from_schema(schema, 'bulkMaxPayloadSize'), text_type='integer', style='class:outh-scope-text'),
- self.app.getTitledText(_("User Extension Schema URI"), name='userExtensionSchemaURI', value=self.app_config.get('userExtensionSchemaURI',''), jans_help=self.app.get_help_from_schema(schema, 'userExtensionSchemaURI'), style='class:outh-scope-text'),
+ self.app.getTitledText(_("Base DN"), name='baseDN', value=self.app_config.get('baseDN',''), jans_help=self.app.get_help_from_schema(schema, 'baseDN'), read_only=True, style=cli_style.edit_text, widget_style=cli_style.scim_widget),
+ self.app.getTitledText(_("Application Url"), name='applicationUrl', value=self.app_config.get('applicationUrl',''), jans_help=self.app.get_help_from_schema(schema, 'applicationUrl'), style=cli_style.edit_text, widget_style=cli_style.scim_widget),
+ self.app.getTitledText(_("Base Endpoint"), name='baseEndpoint', value=self.app_config.get('baseEndpoint',''), jans_help=self.app.get_help_from_schema(schema, 'baseEndpoint'), style=cli_style.edit_text,widget_style=cli_style.scim_widget),
+ self.app.getTitledText(_("Person Custom Object Class"), name='personCustomObjectClass', value=self.app_config.get('personCustomObjectClass',''), jans_help=self.app.get_help_from_schema(schema, 'personCustomObjectClass'), style=cli_style.edit_text,widget_style=cli_style.scim_widget),
+ self.app.getTitledText(_("Auth Issuer"), name='oxAuthIssuer', value=self.app_config.get('oxAuthIssuer',''), jans_help=self.app.get_help_from_schema(schema, 'oxAuthIssuer'), style=cli_style.edit_text,widget_style=cli_style.scim_widget),
+ self.app.getTitledRadioButton(_("Protection Mode"), name='protectionMode', values=[('OAUTH', 'OAUTH'),('BYPASS', 'BYPASS')], current_value=self.app_config.get('protectionMode'), jans_help=self.app.get_help_from_schema(schema, 'protectionMode'), style='class:outh-client-radiobutton',widget_style=cli_style.scim_widget),
+ self.app.getTitledText(_("Max Count"), name='maxCount', value=self.app_config.get('maxCount',''), jans_help=self.app.get_help_from_schema(schema, 'maxCount'), text_type='integer', style=cli_style.edit_text,widget_style=cli_style.scim_widget),
+ self.app.getTitledText(_("Bulk Max Operations"), name='bulkMaxOperations', value=self.app_config.get('bulkMaxOperations',''), jans_help=self.app.get_help_from_schema(schema, 'bulkMaxOperations'), text_type='integer', style=cli_style.edit_text,widget_style=cli_style.scim_widget),
+ self.app.getTitledText(_("Bulk Max Payload Size"), name='bulkMaxPayloadSize', value=self.app_config.get('bulkMaxPayloadSize',''), jans_help=self.app.get_help_from_schema(schema, 'bulkMaxPayloadSize'), text_type='integer', style=cli_style.edit_text,widget_style=cli_style.scim_widget),
+ self.app.getTitledText(_("User Extension Schema URI"), name='userExtensionSchemaURI', value=self.app_config.get('userExtensionSchemaURI',''), jans_help=self.app.get_help_from_schema(schema, 'userExtensionSchemaURI'), style=cli_style.edit_text,widget_style=cli_style.scim_widget),
self.app.getTitledWidget(
_("Logging Level"),
name='loggingLevel',
@@ -62,19 +64,19 @@ def create_widgets(self) -> None:
jans_help=self.app.get_help_from_schema(schema, 'loggingLevel'),
style='class:outh-client-dropdown'
),
- self.app.getTitledText(_("Logging Layout"), name='loggingLayout', value=self.app_config.get('loggingLayout',''), jans_help=self.app.get_help_from_schema(schema, 'loggingLayout'), style='class:outh-scope-text'),
- self.app.getTitledText(_("External Logger Configuration"), name='externalLoggerConfiguration', value=self.app_config.get('externalLoggerConfiguration',''), jans_help=self.app.get_help_from_schema(schema, 'externalLoggerConfiguration'), style='class:outh-scope-text'),
- self.app.getTitledText(_("Metric Reporter Interval"), name='metricReporterInterval', value=self.app_config.get('metricReporterInterval',''), jans_help=self.app.get_help_from_schema(schema, 'metricReporterInterval'), style='class:outh-scope-text', text_type='integer'),
- self.app.getTitledText(_("Metric Reporter Keep Data Days"), name='metricReporterKeepDataDays', value=self.app_config.get('metricReporterKeepDataDays',''), jans_help=self.app.get_help_from_schema(schema, 'metricReporterKeepDataDays'), style='class:outh-scope-text', text_type='integer'),
- self.app.getTitledCheckBox(_("Metric Reporter Enabled"), name='metricReporterEnabled', checked=self.app_config.get('metricReporterEnabled'), jans_help=self.app.get_help_from_schema(schema, 'metricReporterEnabled'), style='class:outh-client-checkbox'),
- self.app.getTitledCheckBox(_("Disable Jdk Logger"), name='disableJdkLogger', checked=self.app_config.get('disableJdkLogger'), jans_help=self.app.get_help_from_schema(schema, 'disableJdkLogger'), style='class:outh-client-checkbox'),
- self.app.getTitledCheckBox(_("Use Local Cache"), name='useLocalCache', checked=self.app_config.get('useLocalCache'), jans_help=self.app.get_help_from_schema(schema, 'useLocalCache'), style='class:outh-client-checkbox'),
+ self.app.getTitledText(_("Logging Layout"), name='loggingLayout', value=self.app_config.get('loggingLayout',''), jans_help=self.app.get_help_from_schema(schema, 'loggingLayout'), style=cli_style.edit_text,widget_style=cli_style.scim_widget),
+ self.app.getTitledText(_("External Logger Configuration"), name='externalLoggerConfiguration', value=self.app_config.get('externalLoggerConfiguration',''), jans_help=self.app.get_help_from_schema(schema, 'externalLoggerConfiguration'), style=cli_style.edit_text,widget_style=cli_style.scim_widget),
+ self.app.getTitledText(_("Metric Reporter Interval"), name='metricReporterInterval', value=self.app_config.get('metricReporterInterval',''), jans_help=self.app.get_help_from_schema(schema, 'metricReporterInterval'), style=cli_style.edit_text, text_type='integer',widget_style=cli_style.scim_widget),
+ self.app.getTitledText(_("Metric Reporter Keep Data Days"), name='metricReporterKeepDataDays', value=self.app_config.get('metricReporterKeepDataDays',''), jans_help=self.app.get_help_from_schema(schema, 'metricReporterKeepDataDays'), style=cli_style.edit_text, text_type='integer',widget_style=cli_style.scim_widget),
+ self.app.getTitledCheckBox(_("Metric Reporter Enabled"), name='metricReporterEnabled', checked=self.app_config.get('metricReporterEnabled'), jans_help=self.app.get_help_from_schema(schema, 'metricReporterEnabled'), style=cli_style.check_box, widget_style=cli_style.scim_widget),
+ self.app.getTitledCheckBox(_("Disable Jdk Logger"), name='disableJdkLogger', checked=self.app_config.get('disableJdkLogger'), jans_help=self.app.get_help_from_schema(schema, 'disableJdkLogger'), style=cli_style.check_box, widget_style=cli_style.scim_widget),
+ self.app.getTitledCheckBox(_("Use Local Cache"), name='useLocalCache', checked=self.app_config.get('useLocalCache'), jans_help=self.app.get_help_from_schema(schema, 'useLocalCache'), style=cli_style.check_box, widget_style=cli_style.scim_widget),
VSplit([Window(), self.save_button, Window()])
],
width=D()
)
- self.app.center_container = self.container
+ self.app.center_container = HSplit([ self.container],style='bg:black', height=D())
def get_app_config(self) -> None:
"""Gets SCIM application configurations from server.
diff --git a/jans-cli-tui/cli_tui/plugins/040_config_api/main.py b/jans-cli-tui/cli_tui/plugins/040_config_api/main.py
index 397c626ff76..21352c82086 100755
--- a/jans-cli-tui/cli_tui/plugins/040_config_api/main.py
+++ b/jans-cli-tui/cli_tui/plugins/040_config_api/main.py
@@ -31,8 +31,9 @@ def __init__(
app (Generic): The main Application class
"""
self.app = app
- self.pid = 'config_api'
+ self.pid = 'admin'
self.name = '[C]onfig-API'
+ self.server_side_plugin = True
self.page_entered = False
self.role_type = 'api-viewer'
self.admin_ui_roles_data = {}
diff --git a/jans-cli-tui/cli_tui/plugins/060_scripts/main.py b/jans-cli-tui/cli_tui/plugins/060_scripts/main.py
index e90cf9f689d..1ab45fb8cbb 100755
--- a/jans-cli-tui/cli_tui/plugins/060_scripts/main.py
+++ b/jans-cli-tui/cli_tui/plugins/060_scripts/main.py
@@ -20,6 +20,7 @@
from edit_script_dialog import EditScriptDialog
from prompt_toolkit.application import Application
from utils.multi_lang import _
+from utils.static import DialogResult, cli_style, common_strings
class Plugin():
"""This is a general class for plugins
@@ -56,7 +57,7 @@ def scripts_prepare_containers(self) -> None:
VSplit([
self.app.getButton(text=_("Get Scripts"), name='scripts:get', jans_help=_("Retreive first %d Scripts") % (20), handler=self.get_scripts),
self.app.getTitledText(_("Search"), name='scripts:search', jans_help=_("Press enter to perform search"), accept_handler=self.search_scripts, style='class:outh_containers_scopes.text'),
- self.app.getButton(text=_("Add Sscript"), name='scripts:add', jans_help=_("To add a new scope press this button"), handler=self.add_script_dialog),
+ self.app.getButton(text=_("Add Script"), name='scripts:add', jans_help=_("To add a new scope press this button"), handler=self.add_script_dialog),
],
padding=3,
width=D(),
@@ -129,8 +130,8 @@ def scripts_update_list(
get_help=(self.get_help,'Scripts'),
on_delete=self.delete_script,
selectes=0,
- headerColor='class:outh-verticalnav-headcolor',
- entriesColor='class:outh-verticalnav-entriescolor',
+ headerColor=cli_style.navbar_headcolor,
+ entriesColor=cli_style.navbar_entriescolor,
all_data=self.data['entries']
)
diff --git a/jans-cli-tui/cli_tui/plugins/070_users/main.py b/jans-cli-tui/cli_tui/plugins/070_users/main.py
index ead042a5973..2babeb13f38 100755
--- a/jans-cli-tui/cli_tui/plugins/070_users/main.py
+++ b/jans-cli-tui/cli_tui/plugins/070_users/main.py
@@ -12,6 +12,9 @@
from utils.utils import DialogUtils, common_data
from utils.static import DialogResult
from utils.multi_lang import _
+from wui_components.jans_cli_dialog import JansGDialog
+from prompt_toolkit.eventloop import get_event_loop
+from utils.static import DialogResult, cli_style, common_strings
common_data.users = SimpleNamespace()
@@ -28,7 +31,8 @@ def __init__(
app (Generic): The main Application class
"""
self.app = app
- self.pid = 'users'
+ self.pid = 'user-management'
+ self.server_side_plugin = True
self.name = '[U]sers'
self.users = {}
self.widgets_ready = False
@@ -79,10 +83,12 @@ def update_user_list_container(self, pattern: Optional[str]='') -> None:
on_display=self.app.data_display_dialog,
on_delete=self.delete_user,
#get_help=(self.get_help,'User'),
+ change_password=self.change_password,
selectes=0,
- headerColor='class:outh-verticalnav-headcolor',
- entriesColor='class:outh-verticalnav-entriescolor',
- all_data=self.users['entries']
+ headerColor=cli_style.navbar_headcolor,
+ entriesColor=cli_style.navbar_entriescolor,
+ all_data=self.users['entries'],
+ jans_help = "Press p to change password"
)
self.user_list_container = self.users_list_box
@@ -142,6 +148,52 @@ def edit_user_dialog(self, **kwargs: Any) -> None:
edit_user_dialog = EditUserDialog(self.app, title=title, data=data, save_handler=self.save_user)
self.app.show_jans_dialog(edit_user_dialog)
+
+ def change_password(self, **kwargs: Any) -> None:
+ """Method to display the edit user dialog
+ """
+ if kwargs:
+ data = kwargs.get('data', {})
+ else:
+ data = {}
+
+ def save(dialog) -> None:
+ async def coroutine():
+ cli_args = {'operation_id': 'patch-user-by-inum', 'endpoint_args': '',
+ 'url_suffix':'inum:{}'.format(data['inum']),
+ 'data':{"jsonPatchString": "",
+ "customAttributes": [
+ {"name": "userPassword",
+ "multiValued": False,
+ "value": "{}".format(self.new_password.me.text)}]}
+ }
+ self.app.start_progressing(_("Changing Password ..."))
+ await get_event_loop().run_in_executor(self.app.executor, self.app.cli_requests, cli_args)
+ self.app.stop_progressing()
+ asyncio.ensure_future(coroutine())
+
+ self.new_password = self.app.getTitledText(
+ _('New Password'),
+ name='passwd',
+ value='',
+ style='class:outh-scope-text',
+ )
+ body = HSplit([
+ self.new_password
+ ],style='class:jans-main-datadisplay')
+ buttons=[
+ Button(
+ text=_("Cancel"),
+ ) ,
+ Button(
+ text=_("Save"),
+ handler=save,
+ ) , ]
+
+ dialog = JansGDialog(self.app, title="Change Password for {}".format(data['userId']), body=body, buttons=buttons)
+
+ self.app.show_jans_dialog(dialog)
+
def delete_user(self, **kwargs: Any) -> None:
"""This method for the deletion of the User
"""
diff --git a/jans-cli-tui/cli_tui/plugins/999_jans/main.py b/jans-cli-tui/cli_tui/plugins/999_jans/main.py
index 5b877812fae..b09e7d6ff88 100755
--- a/jans-cli-tui/cli_tui/plugins/999_jans/main.py
+++ b/jans-cli-tui/cli_tui/plugins/999_jans/main.py
@@ -20,7 +20,7 @@ def __init__(
"""
self.app = app
self.pid = 'jans-menu'
- self.name = '[J]ans Cli'
+ self.name = '[J]ans CLI'
self.menu_container = Frame(
body=HSplit([
diff --git a/jans-cli-tui/cli_tui/utils/static.py b/jans-cli-tui/cli_tui/utils/static.py
index d38b8cbe8fa..0a909300b5d 100755
--- a/jans-cli-tui/cli_tui/utils/static.py
+++ b/jans-cli-tui/cli_tui/utils/static.py
@@ -13,8 +13,11 @@ class cli_style:
tabs = 'class:plugin-tabs'
label = 'class:plugin-label'
container = 'class:plugin-container'
- navbar_headcolor = "class:plugin-navbar-headcolor"
- navbar_entriescolor = "class:plugin-navbar-entriescolor"
+ navbar_headcolor = 'class:plugin-navbar-headcolor'
+ navbar_entriescolor = 'class:plugin-navbar-entriescolor'
+ tab_selected = 'class:tab-selected'
+ scim_widget = 'class:scim-widget'
+ black_bg = 'class:plugin-black-bg'
class common_strings:
enter_to_search = "Press enter to perform search"
diff --git a/jans-cli-tui/cli_tui/utils/utils.py b/jans-cli-tui/cli_tui/utils/utils.py
index f5dd69c1506..eee45e5ff1b 100755
--- a/jans-cli-tui/cli_tui/utils/utils.py
+++ b/jans-cli-tui/cli_tui/utils/utils.py
@@ -42,6 +42,9 @@ def get_item_data(self, item):
if value_:
value_ = int(value_)
+ if getattr(item, 'jans_list_type', False):
+ value_ = value_.split('\n')
+
return {'key':key_, 'value':value_}
diff --git a/jans-cli-tui/cli_tui/wui_components/jans_cli_dialog.py b/jans-cli-tui/cli_tui/wui_components/jans_cli_dialog.py
index 74210bba912..78c493e860d 100755
--- a/jans-cli-tui/cli_tui/wui_components/jans_cli_dialog.py
+++ b/jans-cli-tui/cli_tui/wui_components/jans_cli_dialog.py
@@ -3,9 +3,7 @@
from asyncio import Future
from prompt_toolkit.widgets import Button, Dialog
from typing import Optional, Sequence, Union
-from prompt_toolkit.layout.containers import (
- AnyContainer,
-)
+from prompt_toolkit.layout.containers import AnyContainer
from prompt_toolkit.layout.dimension import AnyDimension
from prompt_toolkit.formatted_text import AnyFormattedText
from utils.multi_lang import _
@@ -16,11 +14,11 @@ class JansGDialog:
def __init__(
self,
parent,
- body: AnyContainer,
+ body: Optional[AnyContainer]=None,
title: Optional[str]= '',
- buttons: Optional[Sequence[Button]]= [],
- width: AnyDimension= None
- )-> Dialog:
+ buttons: Optional[Sequence[Button]]=[],
+ width: AnyDimension=None
+ )-> Dialog:
"""init for JansGDialog
diff --git a/jans-cli-tui/cli_tui/wui_components/jans_dialog_with_nav.py b/jans-cli-tui/cli_tui/wui_components/jans_dialog_with_nav.py
index 3d3aafc1314..062310bd729 100755
--- a/jans-cli-tui/cli_tui/wui_components/jans_dialog_with_nav.py
+++ b/jans-cli-tui/cli_tui/wui_components/jans_dialog_with_nav.py
@@ -62,7 +62,7 @@ def __init__(
self.button_functions = button_functions
self.title = title
self.height = height
- self.width =width
+ self.width = width
self.content = content
self.create_window()
@@ -71,7 +71,7 @@ def create_window(self)-> None:
Todo:
* Change `max_data_str` to be dynamic
"""
- max_data_str = 30 ## TODO TO BE Dynamic
+ max_data_str = 22 ## TODO TO BE Dynamic
wwidth, wheight = get_terminal_size()
height = 19 if wheight <= 30 else wheight - 11
diff --git a/jans-cli-tui/cli_tui/wui_components/jans_label_container.py b/jans-cli-tui/cli_tui/wui_components/jans_label_container.py
new file mode 100644
index 00000000000..5a06f7a7aec
--- /dev/null
+++ b/jans-cli-tui/cli_tui/wui_components/jans_label_container.py
@@ -0,0 +1,146 @@
+from typing import Callable, Optional
+from prompt_toolkit.application import get_app
+
+from prompt_toolkit.formatted_text import HTML, AnyFormattedText, merge_formatted_text
+from prompt_toolkit.key_binding import KeyBindings
+from prompt_toolkit.layout import FormattedTextControl, Window
+from prompt_toolkit.widgets import Label, Frame, Box, Button
+from prompt_toolkit.layout.containers import HSplit
+
+class JansLabelContainer:
+ def __init__(
+ self,
+ title: Optional[str]='',
+ width: Optional[int]=50,
+ on_enter: Optional[Callable]=None,
+ on_delete: Optional[Callable]=None,
+ on_display: Optional[Callable]=None,
+ buttonbox: Optional[Button]=None
+ ) -> None:
+
+ """Label container for Jans
+
+ Args:
+ title (str, optional): title of frame
+ width (int, optional): sets width of container, default is 50
+ on_enter (Callable, optional): When enter this function is called.
+ on_delete (Callable, optional): this function is called when an entry is deleted
+ on_display (Callable, optional): this function is called when user press d on keyboard
+ buttonbox (Button, optional): buntton box to be appended at the end
+ """
+ self.width = width
+ self.on_enter = on_enter
+ self.on_delete = on_delete
+ self.on_display = on_display
+ self.height=2
+ self.entries = []
+ self.invalidate = False
+ self.selected_entry = 0
+ self.body = Window(
+ content=FormattedTextControl(
+ text=self._get_formatted_text,
+ focusable=True,
+ key_bindings=self._get_key_bindings(),
+ ),
+ width=self.width-2,
+ height=self.height
+ )
+ self.line_count = 1
+ widgets = [self.body]
+ if buttonbox:
+ widgets.append(Window(height=1))
+ widgets.append(buttonbox)
+
+ self.container = Box(Frame(HSplit(widgets), title=title, width=self.width))
+
+
+ def _get_formatted_text(self) -> AnyFormattedText:
+ """Internal function for formatting entries
+
+ Returns:
+ merged formatted text.
+ """
+
+ result = []
+ line_width = 0
+ self.line_count = 1
+ for i, entry in enumerate(self.entries):
+ if line_width + len(entry[1]) + 2 > self.width:
+ result.append('\n\n')
+ line_width = 0
+ self.line_count += 2
+
+ line_width += len(entry[1]) + 2
+
+ if i == self.selected_entry:
+ result.append(HTML(''.format("white", "darkgrey", entry[1])))
+ else:
+ result.append(HTML(''.format("black", "lightgrey", entry[1])))
+ result.append(' ')
+
+ self.body.height = self.line_count
+ if self.invalidate:
+ get_app().invalidate()
+ self.invalidate = False
+
+ return merge_formatted_text(result)
+
+ def add_label(
+ self,
+ label_id:str,
+ label_title:str
+ ) -> None:
+ """Adds label to container
+
+ Args:
+ label_id (str): ID for label
+ label_title (str): Text to be displayed as label
+ """
+ self.invalidate = True
+ self.entries.append((label_id, label_title))
+
+
+ def remove_label(self, label_id: str) -> None:
+ """Removes label from container
+
+ Args:
+ label_id (str): ID for label
+ label_title (str): Text to be displayed as label
+ """
+ for entry in self.entries[:]:
+ if entry[0] == label_id:
+ self.entries.remove(entry)
+ self.invalidate = True
+
+ def _get_key_bindings(self) -> None:
+ kb = KeyBindings()
+
+ @kb.add("left")
+ def _go_up(event) -> None:
+ self.selected_entry = (self.selected_entry - 1) % len(self.entries)
+
+ @kb.add("right")
+ def _go_up(event) -> None:
+ self.selected_entry = (self.selected_entry + 1) % len(self.entries)
+
+ @kb.add("enter")
+ def _enter(event) -> None:
+ if self.on_enter:
+ self.on_enter(self.entries[self.selected_entry])
+
+ @kb.add("delete")
+ def _delete(event) -> None:
+ if self.on_delete:
+ self.on_delete(self.entries[self.selected_entry])
+
+ @kb.add('d')
+ def _display(event):
+ if self.on_display:
+ self.on_display(selected=self.entries[self.selected_entry], data=self.entries[self.selected_entry])
+
+ return kb
+
+ def __pt_container__(self) -> Frame:
+ """Returns frame as container
+ """
+ return self.container
diff --git a/jans-cli-tui/cli_tui/wui_components/jans_tab.py b/jans-cli-tui/cli_tui/wui_components/jans_tab.py
new file mode 100644
index 00000000000..d48e78766ac
--- /dev/null
+++ b/jans-cli-tui/cli_tui/wui_components/jans_tab.py
@@ -0,0 +1,195 @@
+import re
+import os
+
+from typing import Callable, Optional
+
+from prompt_toolkit.formatted_text import AnyFormattedText
+from prompt_toolkit.key_binding.key_bindings import KeyBindings, KeyBindingsBase
+from prompt_toolkit.layout.containers import Window, HSplit, VSplit, DynamicContainer, AnyContainer
+from prompt_toolkit.layout.controls import FormattedTextControl
+from prompt_toolkit.formatted_text import HTML, merge_formatted_text
+
+from cli_style import get_color_for_style
+
+selected_tab_style = get_color_for_style('tab-selected')
+unselected_tab_style = get_color_for_style('tab-unselected')
+
+shortcut_re = re.compile(r'\[(.*?)\]')
+
+class JansTab():
+ """This is a tab widget used for Jan Client TUI
+ """
+ def __init__(
+ self,
+ myparent,
+ selection_changed: Optional[Callable]=None,
+ ) -> None:
+
+ """init for JansTab
+
+ Args:
+ myparent (application): This is the parent application for the dialog, to caluclate the size
+ selection_changed (_type_): Callable function when tab selection is changed
+
+ Examples:
+ self.user_tab = JansTab(self)
+ self.user_tab.add_tab(('Users', HSplit([Label("This is user tab")])))
+ self.user_tab.add_tab(('Groups', HSplit([Label("This is group tab")])))
+ """
+ self.myparent = myparent
+ self.selection_changed = selection_changed
+ self.cur_tab = 0
+
+ self.tabs = []
+ self.tab_container = VSplit([])
+ self.create_window()
+
+
+ def _set_nav_width(self):
+ """Sets tab navigation with"""
+ nav_bar_width = 1
+ for tab in self.tabs:
+ nav_bar_width += len(tab[0]) + 3
+ self.tab_nav.width = nav_bar_width
+
+ def add_tab(
+ self,
+ tab_name: str,
+ container: AnyContainer
+ ) -> None:
+ """Adds tab
+
+ Args:
+ tab_name (String): name of tab
+ container (AnyContainer): container of tab
+ """
+ self.tabs.append((tab_name, container))
+ self._set_nav_width()
+
+ if len(self.tabs) == 1:
+ self.tab_container = container
+
+ def remove_tab(self, tab_name: str)->None:
+ """Removes tab
+
+ Args:
+ tab_name (String): name of tab
+ """
+ for tab in self.tabs[:]:
+ if tab[0] == tab_name:
+ self.tabs.remove(tab)
+ self.tab_container = self.tabs[0][1] if self.tabs else VSplit([])
+ self.cur_tab = 0
+ self._set_nav_width()
+
+ def set_tab(self, tab_name:str):
+ """Sets current tab
+
+ Args:
+ tab_name (String): name of tab
+ """
+ for i, tab in enumerate(self.tabs):
+ if tab[0] == tab_name:
+ self.tab_container = tab[1]
+ self.cur_tab = i
+
+ def create_window(self)-> None:
+ """This method creat the tab widget it self
+ """
+
+ self.tab_nav = Window(
+ content=FormattedTextControl(
+ text=self._get_navbar_entries,
+ focusable=True,
+ key_bindings=self.get_nav_bar_key_bindings(),
+ ),
+ style='class:tab-nav-background',
+ height=1,
+ cursorline=False,
+ )
+
+ self.tabbed_container = HSplit([
+ VSplit([self.tab_nav]),
+ DynamicContainer(lambda: self.tab_container)
+ ])
+
+
+ def add_key_binding(
+ self,
+ shorcut_key:str,
+ )-> None:
+ """Key bindings for tab widget"""
+
+ for binding in self.myparent.bindings.bindings:
+ if len(binding.keys) == 2 and binding.keys[0].value == 'escape' and binding.keys[1].lower() == shorcut_key:
+ return
+ self.myparent.bindings.add('escape', shorcut_key.lower())(self._go_tab)
+
+
+ def _get_navbar_entries(self)-> AnyFormattedText:
+ """Get tab navigation entries
+
+ Returns:
+ merge_formatted_text: Merge (Concatenate) several pieces of formatted text together.
+ """
+
+ result = [HTML('')]
+
+ for i, tab in enumerate(self.tabs):
+
+ if i == self.cur_tab:
+ result.append(HTML(''.format(selected_tab_style.fg, selected_tab_style.bg, tab[0])))
+ else:
+ result.append(HTML(''.format(unselected_tab_style.bg, tab[0])))
+ sep_space = HTML('')
+
+ result.append(sep_space)
+
+ return merge_formatted_text(result)
+
+
+ def get_nav_bar_key_bindings(self)-> KeyBindingsBase:
+ """All key binding for the Dialog with Navigation bar
+
+ Returns:
+ KeyBindings: The method according to the binding key
+ """
+ kb = KeyBindings()
+
+ @kb.add('left')
+ def _go_left(event) -> None:
+ if self.cur_tab > 0:
+ self.cur_tab -= 1
+ self.tab_container = self.tabs[self.cur_tab][1]
+ if self.selection_changed:
+ self.selection_changed(self.cur_tab)
+
+ @kb.add('right')
+ def _go_right(event) -> None:
+ if self.cur_tab < len(self.tabs) - 1:
+ self.cur_tab += 1
+ self.tab_container = self.tabs[self.cur_tab][1]
+ if self.selection_changed:
+ self.selection_changed(self.cur_tab)
+
+ @kb.add('c-left')
+ def _go_left(event) -> None:
+ if self.cur_tab > 0:
+ cur = self.tabs.pop(self.cur_tab)
+ self.tabs.insert(self.cur_tab-1, cur)
+ self.cur_tab -= 1
+ self.tab_container = self.tabs[self.cur_tab][1]
+
+ @kb.add('c-right')
+ def _go_right(event) -> None:
+ if self.cur_tab < len(self.tabs) - 1:
+ cur = self.tabs.pop(self.cur_tab)
+ self.tabs.insert(self.cur_tab+1, cur)
+ self.cur_tab += 1
+ self.tab_container = self.tabs[self.cur_tab][1]
+
+
+ return kb
+
+ def __pt_container__(self)-> HSplit:
+ return self.tabbed_container
diff --git a/jans-cli-tui/cli_tui/wui_components/jans_vetrical_nav.py b/jans-cli-tui/cli_tui/wui_components/jans_vetrical_nav.py
index 191a137055c..e6bbc4e8ea7 100644
--- a/jans-cli-tui/cli_tui/wui_components/jans_vetrical_nav.py
+++ b/jans-cli-tui/cli_tui/wui_components/jans_vetrical_nav.py
@@ -23,6 +23,7 @@ def __init__(
on_enter: Callable= None,
get_help: Tuple= None,
on_delete: Callable= None,
+ change_password: Callable= None,
all_data: Optional[list]= [],
preferred_size: Optional[list]= [],
data: Optional[list]= [],
@@ -32,6 +33,7 @@ def __init__(
max_width: AnyDimension = None,
jans_name: Optional[str]= '',
max_height: AnyDimension = None,
+ jans_help: Optional[str]= '',
)->FloatContainer :
"""init for JansVerticalNav
@@ -51,7 +53,7 @@ def __init__(
max_width (int, optional): Maximum width of container.
jans_name (str, optional): Widget name
max_height (int, optional): Maximum hegight of container
-
+ jans_help (str, optional): Status bar help message
Examples:
clients = JansVerticalNav(
myparent=self,
@@ -80,14 +82,15 @@ def __init__(
self.headerColor = headerColor
self.entriesColor = entriesColor
self.max_height = max_height
-
+ self.jans_help = jans_help
self.on_enter = on_enter
self.on_delete = on_delete
self.on_display = on_display
+ self.change_password = change_password
if get_help:
self.get_help, self.scheme = get_help
if self.data :
- self.get_help(data=self.data[self.selectes],scheme=self.scheme)
+ self.get_help(data=self.data[self.selectes], scheme=self.scheme)
else:
self.get_help= None
self.all_data=all_data
@@ -95,7 +98,7 @@ def __init__(
self.handle_header_spaces()
self.create_window()
-
+
def view_data(
self,
@@ -120,6 +123,22 @@ def view_data(
def create_window(self) -> None:
"""This method creat the dialog it self
"""
+
+ self.list_box = Window(
+ content=FormattedTextControl(
+ text=self._get_formatted_text,
+ focusable=True,
+ key_bindings=self._get_key_bindings(),
+ style=self.entriesColor,
+ ),
+ style='class:select-box',
+ height=D(preferred=len(self.data), max=len(self.data)),
+ cursorline=True,
+ right_margins=[ScrollbarMargin(display_arrows=True), ],
+ )
+ if self.jans_help:
+ self.list_box.jans_help = self.jans_help
+
self.container_content = [
Window(
content=FormattedTextControl(
@@ -132,18 +151,7 @@ def create_window(self) -> None:
height=D(preferred=1, max=1),
cursorline=False,
),
- Window(
- content=FormattedTextControl(
- text=self._get_formatted_text,
- focusable=True,
- key_bindings=self._get_key_bindings(),
- style=self.entriesColor,
- ),
- style='class:select-box',
- height=D(preferred=len(self.data), max=len(self.data)),
- cursorline=True,
- right_margins=[ScrollbarMargin(display_arrows=True), ],
- ),
+ self.list_box ,
]
if self.underline_headings:
@@ -295,6 +303,13 @@ def _(event):
if self.on_enter :
self.on_enter(passed=self.data[self.selectes], event=event, size=size, data=self.all_data[self.selectes], selected=self.selectes, jans_name=self.jans_name)
+ @kb.add('p')
+ def _(event):
+ if not self.data:
+ return
+ if self.change_password:
+ self.change_password(data=self.all_data[self.selectes])
+
@kb.add('d')
def _(event):