Project-Specific Context: User Interface (UI) Architecture & Tab System
This document describes the architecture, organization, patterns, and best practices for implementing the user interface of the OCI Policy Analysis tool. It is intended to be the canonical reference for developers working on UI features, designing new tabs, and extending the application.
1. Tab Structure and Organization
All UI (graphical interface) code is located under src/oci_policy_analysis/ui/. Each major tab or functional panel appears as its own module, named <feature>_tab.py. Example: policies_tab.py, users_tab.py, cross_tenancy_tab.py.
Tabs are registered and arranged in main.py (see the App class). Each tab is instantiated as a class (typically a subclass of BaseUITab) and added to the main application’s ttk.Notebook, which manages the tabbed interface.
Key notes:
Project tabs are created and referenced in a specific order for a consistent UX.
New tabs must be imported and instantiated in the
Appclass (src/oci_policy_analysis/main.py).Centralized settings and data models (repositories, engines) are passed to each tab on initialization.
2.1. Built-in Documentation Links
In addition to the page-level help area, BaseUITab provides a small helper for creating in-tab documentation links with a consistent look and behavior.
The create_doc_link_label helper
Defined in src/oci_policy_analysis/ui/base_tab.py:
class BaseUITab(ttk.Frame):
DOCROOT = 'https://agregory999.github.io/oci-policy-analysis'
def create_doc_link_label(self, parent, text: str, url: str, **grid_kwargs) -> ttk.Label:
"""Create a standardized documentation link label.
- Uses Tenancy Setup Guide styling (blue, underlined, hand cursor).
- Binds left-click to open the given URL via BaseUITab.open_link.
"""
link_label = ttk.Label(
parent,
text=text,
foreground='#0645AD',
cursor='hand2',
font=('TkDefaultFont', 10, 'underline'),
)
link_label.bind('<Button-1>', lambda _e: self.open_link(url))
if grid_kwargs:
link_label.grid(**grid_kwargs)
return link_label
Key points:
Consistent styling: All doc links created via this helper use the same visual style as the “Tenancy Setup Guide” link on the Settings tab:
Blue color
#0645AD.Underlined
TkDefaultFontat size 10.Hand cursor (
cursor='hand2').
Consistent behavior: Clicking the label calls
BaseUITab.open_link(url), which centralizes link opening and fallback behavior (showing a message box with the URL if the browser call fails).Grid integration: Optional
**grid_kwargsare passed directly to.grid(**grid_kwargs)if present, so you can both create and place the label in a single call.
Linking to in-repo docs vs. public docs
Links can point to:
Internal documentation pages built from this repository, typically under the
DOCROOTbase URL (e.g.,/setup.html,/usage.html#settings-tab-start-here,/architecture.html#policy-parsing).Public external documentation, such as Oracle Cloud Infrastructure docs.
For internal docs, prefer building URLs using DOCROOT so they stay consistent if the documentation hosting root ever changes:
setup_doc_url = self.DOCROOT + '/setup.html'
setup_guide_link = self.create_doc_link_label(
label_frm_tenancy_config,
text='Tenancy Setup Guide',
url=setup_doc_url,
row=3,
column=3,
padx=3,
pady=(10, 2),
sticky='w',
)
For external docs, pass the absolute URL directly:
session_doc_url = 'https://docs.oracle.com/en-us/iaas/Content/API/SDKDocs/clitoken.htm'
session_auth_link_label = self.create_doc_link_label(
label_frm_tenancy_config,
text='Session Token (oci session authenticate)',
url=session_doc_url,
row=2,
column=0,
columnspan=2,
padx=5,
pady=3,
sticky='w',
)
Examples of usage in existing tabs
Settings Tab (settings_tab.py)
Tenancy Setup Guide link next to the compartment depth selector:
setup_doc_url = self.DOCROOT + '/setup.html'
setup_guide_link = self.create_doc_link_label(
label_frm_tenancy_config,
text='Tenancy Setup Guide',
url=setup_doc_url,
row=3,
column=3,
padx=3,
pady=(10, 2),
sticky='w',
)
self.add_context_help(
setup_guide_link,
'Open the full OCI Policy Analysis setup instructions (docs/source/setup.md) in your web browser.',
)
Session Token (oci session authenticate) link:
session_doc_url = 'https://docs.oracle.com/en-us/iaas/Content/API/SDKDocs/clitoken.htm'
session_auth_link_label = self.create_doc_link_label(
label_frm_tenancy_config,
text='Session Token (oci session authenticate)',
url=session_doc_url,
row=2,
column=0,
columnspan=2,
padx=5,
pady=3,
sticky='w',
)
self.add_context_help(
session_auth_link_label,
CONTEXT_HELP['SESSION_TOKEN'],
)
Policies Tab (policies_tab.py)
Under the policy filter fields, the Policies tab surfaces two documentation links that also use the helper:
effective_path_help = self.create_doc_link_label(
self.frm_policy_filter,
text='What is Effective Path?',
url=self.DOCROOT + '/architecture.html#policy-parsing',
row=6,
column=0,
columnspan=4,
padx=5,
pady=(0, 4),
sticky='w',
)
deny_policies_help = self.create_doc_link_label(
self.frm_policy_filter,
text='OCI Deny Policies Documentation',
url='https://docs.oracle.com/en-us/iaas/Content/Identity/policysyntax/denypolicies.htm',
row=6,
column=4,
columnspan=2,
padx=5,
pady=(0, 4),
sticky='w',
)
These links:
Explain how the Effective Path is derived.
Jump directly to Oracle’s official deny policy syntax documentation.
Match the same look-and-feel as Settings tab links because they all use
create_doc_link_label.
Guidelines for adding new documentation links
When adding a new doc link on any tab:
Always use
self.create_doc_link_label(...)in subclasses ofBaseUITabrather than creating ad-hocttk.Labelinstances for links.Use
self.DOCROOT + '/path.html#anchor'for internal docs that are part of this repository’s Sphinx-built site.Use a full
https://...URL for public docs (e.g., Oracle Cloud Infrastructure documentation).Optionally attach context help via
self.add_context_help(link_label, message)if a short tooltip adds value.
This keeps both the visual style and click behavior of doc links consistent across the entire UI.
3. Tab Registration, Data Model/Engine Wiring, and Load Lifecycle
How Tabs Are Created and Wired Up
All main tabs are instantiated in the
Appclass (src/oci_policy_analysis/main.py). Each receives proper references to shared data models, settings, caches, engines, and the parent notebook.Data models such as
PolicyAnalysisRepository,PolicySimulationEngine, and others are also constructed centrally and passed to tabs as needed.This wiring allows for dependency injection, proper testing, and centralized state management.
Example (simplified):
self.policies_tab = PoliciesTab(self.notebook, self, self.settings)
self.users_tab = UsersTab(self.notebook, self)
self.permissions_report_tab = PermissionsReportTab(self.notebook, self)
self.simulation_tab = SimulationTab(self.notebook, self, self.settings)
All tabs are added to the main notebook using
self.notebook.add(<tab_instance>, text=<tab label>).
Data/State Flow and Loading
Data loading, data refresh, and status updates are handled centrally.
The application uses repositories (e.g.,
PolicyAnalysisRepository) and engines (PolicyIntelligenceEngine,PolicySimulationEngine). These are initialized at the application level and exposed to tabs on creation.Upon data (or cache) load via various methods (tenancy, compliance output, JSON), special post-load update flows run: see
_post_load_update_uifor UART-registered function calls.Each tab exposes a set of update, refresh, or enable functions (e.g.,
update_user_analysis_output,refresh_tree,enable_widgets_after_load) which the application can call to propagate new data/UI states.Central settings changes (context help, font size) are propagated live to all tabs via
App.refresh_all_tabs_settings(), which in turn calls each tab’sapply_settings(...).
Timing and Logging:
Timing for each post-load UI refresh or data push is logged for performance diagnostics.
All tabs support rapid enable/disable and refresh cycles coordinated from the main App.
4. Tab Commonality, Data Models, and Engines
General Similarities:
All tabs provide a consistent pattern for data updates, UI refresh, and state synchronization.
Tabs define or inherit an
apply_settingsmethod and one or more data refresh/update functions.
How Tabs Use Data Models and Engines:
Key data engines/repositories are initialized in
App.__init__(seemain.py). For example:self.policy_compartment_analysis = PolicyAnalysisRepository()self.simulation_engine = PolicySimulationEngine(...)self.reference_data_repo = ReferenceDataRepo()self.policy_intelligence = PolicyIntelligenceEngine(self.policy_compartment_analysis)These are passed into relevant tabs on instantiation or accessed via the parent reference.
Tabs receive model/engine references as constructor arguments and use them for:
Data visualization/loading (
load_xxx_data)Engine-driven analytics (simulation, recommendations, report building)
Data caching and status display
On reload, the main App coordinates model/engine lifecycles, re-creates intelligence models as needed, and triggers each tab’s update/refresh method.
Instantiation/Population:
Tabs can be loaded/refreshed in bulk (see
App._post_load_update_ui) or individually.apply_settingsis always called after load or settings update.UI population is separated from data/model construction, ensuring consistent rerendering and minimizing state bugs.
5. Creating a New Tab: Best Practices
Create the Module
Name as
<feature>_tab.pyand place undersrc/oci_policy_analysis/ui/.Inherit from
BaseUITabif you want plug-and-play context help and unified settings propagation.
Implement Required Interfaces
Always implement
apply_settings(context_help: bool, font_size: str).Define at least one update or refresh method (called by App after load/update).
Use
add_context_help(widget, message)to wire up help for all user-interactive widgets.
Register with the App
Import your tab in
src/oci_policy_analysis/main.py.Instantiate in the App’s
__init__, passing required engines/data/settings.Add it to the
self.notebookwith a descriptive label.
Data/Model Usage
Accept needed model/engine references in the constructor.
Use them for any backend queries, visualizations, or analytics.
Avoid loading or caching data in the tab directly; rely on the app-level repositories and engines.
Context Help/Settings
Always wire up your help and font logic to the tab’s
apply_settingsfor live updating.Use the
default_help_textoption ofBaseUITab.Keep help tooltips short (2 lines max).
Boilerplate/Update Patterns
Place any necessary initialization, enable/disable, and data update calls as methods to be triggered by App.
See other tabs for standard patterns (e.g.,
update_user_analysis_output,refresh_tree).
6. Internal Lifecycles & Patterns
Load and Refresh Events
Central application lifecycle (load/refresh events, cache loads, data reloads) propagate through dedicated App methods, calling each tab’s appropriate update method.
Central settings (context help, font size, etc.) propagate via App, calling
apply_settingson every tab for visual/layout consistency.To minimize race conditions and UI bugs, keep all data and settings flows coordinated by the main application and avoid direct cross-tab communication.
Logging and Timing
Tabs support application-wide logging for performance and debugging, with centralized log level control via settings.
7. Reference: Relevant Files
src/oci_policy_analysis/main.py: App wiring, lifecycle, model/engine initialization, centralized tab management.src/oci_policy_analysis/ui/base_tab.py: Shared base tab implementation.src/oci_policy_analysis/ui/: All tab modules.Other
context/project/CONTEXT_*.mdfiles for individual tab details.
8. Summary
The UI layer of OCI Policy Analysis follows established architectural patterns for maintainability, consistency, and extensibility. Centralized tab management, unified settings propagation, and model/engine separation come together to provide a robust, predictable developer experience for UI extension and maintenance.
For further examples or boilerplate, study main.py and src/oci_policy_analysis/ui/ tab source files directly.
9. Experimental Mode and Preview Tabs
Some UI features (such as the Consolidation Workbench) are considered experimental or preview-only. These are intentionally hidden behind an undocumented CLI flag so they can be iterated on without being part of the default, supported surface area.
9.1. How Experimental Mode is Enabled
Experimental features are toggled at process startup via a hidden command-line flag defined in src/oci_policy_analysis/main.py:
python -m oci_policy_analysis.main --experimental-features
Key points:
--experimental-featuresis parsed byargparsebut suppressed from--helpoutput (usinghelp=argparse.SUPPRESS).The parsed boolean is threaded into the main UI application:
app = App(force_debug=args.verbose, experimental_features=args.experimental_features)
Within
App.__init__, the flag is stored on the instance and used to gate construction of experimental UI components:class App(tk.Tk): def __init__(self, force_debug: bool = False, experimental_features: bool = False): super().__init__() self.experimental_features = experimental_features ...
Developers should treat this flag as internal-only, intended for maintaining and validating experimental UI workbenches.
9.2. Consolidation Workbench Tab (Preview)
The Consolidation Workbench UI is wired into the project but is only instantiated when experimental mode is enabled.
In
main.py, the tab reference is created conditionally:from oci_policy_analysis.ui.consolidation_workbench_tab import ConsolidationWorkbenchTab ... self.consolidation_tab = None if self.experimental_features: self.consolidation_tab = ConsolidationWorkbenchTab(self.notebook, self)
When
experimental_featuresis False (default):self.consolidation_tabremainsNone.No Consolidation tab is constructed, added to the notebook, or used in post-load update flows.
When
experimental_featuresis True:self.consolidation_tabis instantiated.The tab is surfaced as part of the Advanced Tabs control in the Settings tab.
The Settings tab’s “Show Advanced Tabs” toggle (_toggle_advanced_tabs in settings_tab.py) only operates on the Consolidation tab if it exists:
advanced_tabs = [
self.app.permissions_report_tab,
self.app.condition_tester_tab,
self.app.simulation_tab,
self.app.policy_recommendations_tab,
]
# Only treat consolidation tab as advanced if experimental features are enabled
if getattr(self.app, 'consolidation_tab', None) is not None:
advanced_tabs.append(self.app.consolidation_tab)
...
notebook.add(self.app.permissions_report_tab, text='Permissions Report\n(Advanced)')
notebook.add(self.app.condition_tester_tab, text='Condition Tester\n(Advanced)')
notebook.add(self.app.simulation_tab, text='API Simulation\n(Advanced)')
notebook.add(self.app.policy_recommendations_tab, text='Policy Recommendations\n(Preview)')
if getattr(self.app, 'consolidation_tab', None) is not None:
notebook.add(self.app.consolidation_tab, text='Consolidation Workbench\n(Preview)')
This ensures the Consolidation Workbench follows the same advanced/preview pattern as other power-user tabs, but is only reachable when the experimental flag is enabled.
9.3. Status Bar Indicator for Experimental Mode
To make it clear when the UI is running with experimental behavior enabled, the fixed status bar at the bottom of the window is prefixed with an Experimental Mode marker when experimental_features is True.
In App.update_status_bar (in main.py):
prefix = '**Experimental Mode** - ' if self.experimental_features else ''
if loaded:
self.status_var.set(
f"{prefix}Policy Data: {load_source} loaded at {ts_str}{reloaded_str}"
)
else:
self.status_var.set(f'{prefix}Policy Data: (Not Loaded)')
This prefix is non-intrusive (text only) but visually obvious for anyone debugging or testing experimental features.
9.4. Design Guidelines for New Experimental UI
When adding additional experimental tabs or UI features:
Gate Construction
Use the existing
experimental_featuresflag onAppto decide whether to construct the new UI component.Do not reference experimental widgets in
apply_settingsor post-load flows unless they are present; usegetattr(..., None)or explicitis not Nonechecks.
Surface via Advanced Controls
Prefer surfacing experimental tabs through existing “Advanced” mechanisms (e.g., the Advanced Tabs toggle in
SettingsTab) rather than always-on tabs.
Avoid Public Documentation
Do not add the experimental flag or features to end-user documentation or CLI help.
Internal context docs (such as this
CONTEXT_ui.md) are the appropriate place to describe how experimental mode works for developers.
Keep Behavior Reversible
Experimental code paths should be easy to disable entirely by removing the gating logic and any references to the feature, without impacting the rest of the UI.
Following this pattern keeps the production UI stable while still allowing rapid iteration on new ideas behind an explicit, opt-in experimental switch.