misata 0.3.1b0__py3-none-any.whl → 0.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- misata/__init__.py +1 -1
- misata/agents/__init__.py +23 -0
- misata/agents/pipeline.py +286 -0
- misata/causal/__init__.py +5 -0
- misata/causal/graph.py +109 -0
- misata/causal/solver.py +115 -0
- misata/cli.py +31 -0
- misata/generators/__init__.py +19 -0
- misata/generators/copula.py +198 -0
- misata/llm_parser.py +180 -137
- misata/quality.py +78 -33
- misata/reference_data.py +221 -0
- misata/research/__init__.py +3 -0
- misata/research/agent.py +70 -0
- misata/schema.py +25 -0
- misata/simulator.py +131 -0
- misata/smart_values.py +144 -6
- misata/studio/__init__.py +55 -0
- misata/studio/app.py +49 -0
- misata/studio/components/inspector.py +81 -0
- misata/studio/components/sidebar.py +35 -0
- misata/studio/constraint_generator.py +781 -0
- misata/studio/inference.py +319 -0
- misata/studio/outcome_curve.py +284 -0
- misata/studio/state/store.py +55 -0
- misata/studio/tabs/configure.py +50 -0
- misata/studio/tabs/generate.py +117 -0
- misata/studio/tabs/outcome_curve.py +149 -0
- misata/studio/tabs/schema_designer.py +217 -0
- misata/studio/utils/styles.py +143 -0
- misata/studio_constraints/__init__.py +29 -0
- misata/studio_constraints/z3_solver.py +259 -0
- {misata-0.3.1b0.dist-info → misata-0.5.0.dist-info}/METADATA +13 -2
- misata-0.5.0.dist-info/RECORD +61 -0
- {misata-0.3.1b0.dist-info → misata-0.5.0.dist-info}/WHEEL +1 -1
- {misata-0.3.1b0.dist-info → misata-0.5.0.dist-info}/entry_points.txt +1 -0
- misata-0.3.1b0.dist-info/RECORD +0 -37
- {misata-0.3.1b0.dist-info → misata-0.5.0.dist-info}/licenses/LICENSE +0 -0
- {misata-0.3.1b0.dist-info → misata-0.5.0.dist-info}/top_level.txt +0 -0
misata/smart_values.py
CHANGED
|
@@ -86,6 +86,22 @@ class SmartValueGenerator:
|
|
|
86
86
|
"feature_name": ["feature", "capability", "functionality"],
|
|
87
87
|
"bug_type": ["bug", "issue", "defect", "error"],
|
|
88
88
|
"api_endpoint": ["endpoint", "api", "route", "path"],
|
|
89
|
+
|
|
90
|
+
# NEW v0.5.0: Additional domain patterns
|
|
91
|
+
"payment_method": ["payment_method", "pay_type", "payment_option"],
|
|
92
|
+
"order_status": ["order_status", "status", "state"],
|
|
93
|
+
"customer_segment": ["segment", "customer_type", "tier", "classification"],
|
|
94
|
+
"license_type": ["license", "licence"],
|
|
95
|
+
"file_type": ["file_type", "document_type", "mime_type"],
|
|
96
|
+
"priority_level": ["priority", "urgency", "importance"],
|
|
97
|
+
"subscription_plan": ["plan", "subscription", "tier", "package"],
|
|
98
|
+
|
|
99
|
+
# Generic patterns - lowest priority but always match on exact column names
|
|
100
|
+
"name": ["name"],
|
|
101
|
+
"description": ["description", "desc", "about", "summary", "details"],
|
|
102
|
+
"title": ["title", "heading"],
|
|
103
|
+
"status": ["status", "state"],
|
|
104
|
+
"type": ["type", "kind", "category"],
|
|
89
105
|
}
|
|
90
106
|
|
|
91
107
|
# Curated fallback pools (no LLM needed)
|
|
@@ -346,6 +362,108 @@ class SmartValueGenerator:
|
|
|
346
362
|
"/api/v1/notifications", "/api/v1/settings", "/api/v1/search",
|
|
347
363
|
"/api/v1/reports", "/api/v1/webhooks", "/api/v1/integrations",
|
|
348
364
|
],
|
|
365
|
+
# NEW v0.5.0: Additional high-quality domain pools
|
|
366
|
+
"medical_specialty": [
|
|
367
|
+
"Cardiology", "Dermatology", "Emergency Medicine", "Endocrinology",
|
|
368
|
+
"Family Medicine", "Gastroenterology", "General Surgery", "Geriatrics",
|
|
369
|
+
"Hematology", "Infectious Disease", "Internal Medicine", "Nephrology",
|
|
370
|
+
"Neurology", "Obstetrics & Gynecology", "Oncology", "Ophthalmology",
|
|
371
|
+
"Orthopedic Surgery", "Otolaryngology", "Pediatrics", "Psychiatry",
|
|
372
|
+
"Pulmonology", "Radiology", "Rheumatology", "Urology", "Anesthesiology",
|
|
373
|
+
],
|
|
374
|
+
"transaction_type": [
|
|
375
|
+
"Purchase", "Refund", "Transfer", "Deposit", "Withdrawal",
|
|
376
|
+
"Payment", "Credit", "Debit", "Fee", "Interest",
|
|
377
|
+
"Dividend", "Commission", "Bonus", "Adjustment", "Reversal",
|
|
378
|
+
"Wire Transfer", "ACH Transfer", "Direct Deposit", "Check Payment",
|
|
379
|
+
"Cash Advance", "Balance Transfer", "Loan Disbursement", "Bill Payment",
|
|
380
|
+
],
|
|
381
|
+
"account_type": [
|
|
382
|
+
"Checking Account", "Savings Account", "Money Market Account",
|
|
383
|
+
"Certificate of Deposit", "Individual Retirement Account (IRA)",
|
|
384
|
+
"401(k) Account", "Brokerage Account", "Business Checking",
|
|
385
|
+
"Business Savings", "Health Savings Account (HSA)", "Joint Account",
|
|
386
|
+
"Trust Account", "Custodial Account", "Student Account", "Premium Account",
|
|
387
|
+
],
|
|
388
|
+
"brand": [
|
|
389
|
+
"Apple", "Samsung", "Sony", "LG", "Nike", "Adidas", "Puma", "Under Armour",
|
|
390
|
+
"Toyota", "Honda", "Ford", "Tesla", "Microsoft", "Google", "Amazon",
|
|
391
|
+
"Dell", "HP", "Lenovo", "ASUS", "Acer", "Canon", "Nikon", "Bose",
|
|
392
|
+
"JBL", "Philips", "Panasonic", "Whirlpool", "GE", "Bosch", "Dyson",
|
|
393
|
+
"IKEA", "Williams-Sonoma", "Crate & Barrel", "West Elm", "Pottery Barn",
|
|
394
|
+
],
|
|
395
|
+
"payment_method": [
|
|
396
|
+
"Credit Card (Visa)", "Credit Card (Mastercard)", "Credit Card (Amex)",
|
|
397
|
+
"Debit Card", "PayPal", "Apple Pay", "Google Pay", "Bank Transfer",
|
|
398
|
+
"Wire Transfer", "Check", "Cash", "Cryptocurrency", "Venmo",
|
|
399
|
+
"Klarna", "Afterpay", "Shop Pay", "Amazon Pay", "ACH Direct Debit",
|
|
400
|
+
],
|
|
401
|
+
"order_status": [
|
|
402
|
+
"Pending", "Confirmed", "Processing", "Shipped", "In Transit",
|
|
403
|
+
"Out for Delivery", "Delivered", "Completed", "Cancelled", "Refunded",
|
|
404
|
+
"On Hold", "Backordered", "Returned", "Partially Shipped", "Failed",
|
|
405
|
+
],
|
|
406
|
+
"customer_segment": [
|
|
407
|
+
"Enterprise", "Mid-Market", "Small Business", "Startup", "Individual",
|
|
408
|
+
"Premium", "Standard", "Basic", "Trial", "Churned", "At-Risk",
|
|
409
|
+
"Champion", "Loyal", "New Customer", "VIP", "Wholesale", "Retail",
|
|
410
|
+
],
|
|
411
|
+
"license_type": [
|
|
412
|
+
"MIT License", "Apache License 2.0", "GNU GPL v3", "BSD 3-Clause",
|
|
413
|
+
"Creative Commons BY 4.0", "Proprietary", "Commercial", "Educational",
|
|
414
|
+
"Open Source", "Freeware", "Shareware", "Enterprise License",
|
|
415
|
+
"Single User", "Multi-User", "Site License", "Perpetual License",
|
|
416
|
+
],
|
|
417
|
+
"file_type": [
|
|
418
|
+
"PDF Document", "Word Document", "Excel Spreadsheet", "PowerPoint Presentation",
|
|
419
|
+
"JPEG Image", "PNG Image", "MP4 Video", "MP3 Audio", "ZIP Archive",
|
|
420
|
+
"CSV File", "JSON File", "XML File", "HTML Page", "Python Script",
|
|
421
|
+
"JavaScript File", "SQL Database", "Markdown Document", "Text File",
|
|
422
|
+
],
|
|
423
|
+
"priority_level": [
|
|
424
|
+
"Critical", "High", "Medium", "Low", "Trivial",
|
|
425
|
+
"Urgent", "Normal", "Deferred", "Blocked", "In Review",
|
|
426
|
+
],
|
|
427
|
+
"subscription_plan": [
|
|
428
|
+
"Free Tier", "Basic Plan", "Professional Plan", "Business Plan",
|
|
429
|
+
"Enterprise Plan", "Starter Plan", "Growth Plan", "Scale Plan",
|
|
430
|
+
"Team Plan", "Individual Plan", "Student Plan", "Nonprofit Plan",
|
|
431
|
+
"Annual Pro", "Monthly Basic", "Lifetime Access", "Pay-As-You-Go",
|
|
432
|
+
],
|
|
433
|
+
# Generic fallbacks for common column patterns
|
|
434
|
+
"name": [
|
|
435
|
+
"Alpha Project", "Beta Initiative", "Gamma Solution", "Delta System",
|
|
436
|
+
"Epsilon Framework", "Zeta Platform", "Eta Service", "Theta Module",
|
|
437
|
+
"Iota Component", "Kappa Engine", "Lambda Protocol", "Mu Architecture",
|
|
438
|
+
"Strategic Modernization", "Digital Transformation", "Innovation Hub",
|
|
439
|
+
"Next Generation Platform", "Cloud Migration", "Data Integration Suite",
|
|
440
|
+
],
|
|
441
|
+
"description": [
|
|
442
|
+
"High-performance solution designed for enterprise-scale deployments with robust security features.",
|
|
443
|
+
"User-friendly platform offering seamless integration with existing workflows and systems.",
|
|
444
|
+
"Cutting-edge technology stack built for reliability, scalability, and maintainability.",
|
|
445
|
+
"Comprehensive toolkit featuring advanced analytics and real-time monitoring capabilities.",
|
|
446
|
+
"Industry-leading service with proven track record of customer satisfaction and uptime.",
|
|
447
|
+
"Streamlined workflow automation reducing manual effort and improving efficiency.",
|
|
448
|
+
"Innovative approach combining best practices with modern architectural patterns.",
|
|
449
|
+
"Full-featured solution supporting multiple deployment options and configuration flexibility.",
|
|
450
|
+
],
|
|
451
|
+
"title": [
|
|
452
|
+
"Senior Software Engineer", "Product Manager", "Data Analyst",
|
|
453
|
+
"Marketing Director", "Sales Representative", "Customer Success Manager",
|
|
454
|
+
"Technical Lead", "UX Designer", "DevOps Engineer", "Quality Analyst",
|
|
455
|
+
"Project Coordinator", "Business Analyst", "Account Executive",
|
|
456
|
+
],
|
|
457
|
+
"status": [
|
|
458
|
+
"Active", "Inactive", "Pending", "Approved", "Rejected",
|
|
459
|
+
"Under Review", "Completed", "In Progress", "On Hold", "Archived",
|
|
460
|
+
"Draft", "Published", "Expired", "Suspended", "Verified",
|
|
461
|
+
],
|
|
462
|
+
"type": [
|
|
463
|
+
"Standard", "Premium", "Custom", "Default", "Advanced",
|
|
464
|
+
"Basic", "Professional", "Enterprise", "Starter", "Legacy",
|
|
465
|
+
"Internal", "External", "Public", "Private", "Hybrid",
|
|
466
|
+
],
|
|
349
467
|
"skill": [
|
|
350
468
|
"Python", "JavaScript", "SQL", "Machine Learning", "Data Analysis",
|
|
351
469
|
"Project Management", "Communication", "Leadership", "Problem Solving",
|
|
@@ -541,14 +659,28 @@ Return ONLY a JSON array of strings, no explanation. Example:
|
|
|
541
659
|
use_llm: Whether to use LLM for generation
|
|
542
660
|
|
|
543
661
|
Returns:
|
|
544
|
-
List of domain-appropriate values
|
|
662
|
+
List of domain-appropriate values (NEVER empty - falls back to generic pools)
|
|
545
663
|
"""
|
|
546
664
|
# Determine domain
|
|
547
665
|
domain = domain_hint or self.detect_domain(column_name, table_name)
|
|
548
666
|
|
|
667
|
+
# If no domain detected, infer from column name patterns
|
|
549
668
|
if domain is None:
|
|
550
|
-
|
|
551
|
-
|
|
669
|
+
col_lower = column_name.lower()
|
|
670
|
+
# Try to match generic patterns
|
|
671
|
+
if "name" in col_lower:
|
|
672
|
+
domain = "name"
|
|
673
|
+
elif "desc" in col_lower or "about" in col_lower:
|
|
674
|
+
domain = "description"
|
|
675
|
+
elif "title" in col_lower:
|
|
676
|
+
domain = "title"
|
|
677
|
+
elif "status" in col_lower or "state" in col_lower:
|
|
678
|
+
domain = "status"
|
|
679
|
+
elif "type" in col_lower or "kind" in col_lower:
|
|
680
|
+
domain = "type"
|
|
681
|
+
else:
|
|
682
|
+
# Ultimate fallback - use "name" pool for any unknown TEXT column
|
|
683
|
+
domain = "name"
|
|
552
684
|
|
|
553
685
|
# Build context string
|
|
554
686
|
full_context = context or f"{table_name} {column_name}".strip()
|
|
@@ -570,10 +702,16 @@ Return ONLY a JSON array of strings, no explanation. Example:
|
|
|
570
702
|
else:
|
|
571
703
|
pool = self.FALLBACK_POOLS.get(domain, [])[:size]
|
|
572
704
|
|
|
705
|
+
# Ensure we never return empty - cascade through fallbacks
|
|
706
|
+
if not pool:
|
|
707
|
+
pool = self.FALLBACK_POOLS.get(domain, [])[:size]
|
|
708
|
+
if not pool:
|
|
709
|
+
# Absolute fallback - use generic name pool
|
|
710
|
+
pool = self.FALLBACK_POOLS.get("name", ["Item A", "Item B", "Item C"])[:size]
|
|
711
|
+
|
|
573
712
|
# Cache the pool
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
self._save_pool_to_cache(cache_key, pool)
|
|
713
|
+
self._pool_cache[cache_key] = pool
|
|
714
|
+
self._save_pool_to_cache(cache_key, pool)
|
|
577
715
|
|
|
578
716
|
return pool
|
|
579
717
|
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Misata Studio - Visual Schema Designer & Reverse Graph Editor
|
|
3
|
+
|
|
4
|
+
The GUI for reverse-engineering schemas from sample data and
|
|
5
|
+
designing custom distributions visually.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
pip install misata[studio]
|
|
9
|
+
misata studio
|
|
10
|
+
|
|
11
|
+
# Or from Python:
|
|
12
|
+
from misata.studio import launch
|
|
13
|
+
launch()
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from typing import Optional
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def launch(
|
|
20
|
+
port: int = 8501,
|
|
21
|
+
host: str = "localhost",
|
|
22
|
+
open_browser: bool = True,
|
|
23
|
+
) -> None:
|
|
24
|
+
"""Launch Misata Studio GUI.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
port: Port to run on (default 8501)
|
|
28
|
+
host: Host to bind to (default localhost)
|
|
29
|
+
open_browser: Open browser automatically
|
|
30
|
+
"""
|
|
31
|
+
try:
|
|
32
|
+
import streamlit.web.cli as stcli
|
|
33
|
+
import sys
|
|
34
|
+
import os
|
|
35
|
+
|
|
36
|
+
# Get the path to app.py
|
|
37
|
+
app_path = os.path.join(os.path.dirname(__file__), "app.py")
|
|
38
|
+
|
|
39
|
+
sys.argv = [
|
|
40
|
+
"streamlit", "run", app_path,
|
|
41
|
+
f"--server.port={port}",
|
|
42
|
+
f"--server.address={host}",
|
|
43
|
+
"--server.headless=true" if not open_browser else "",
|
|
44
|
+
]
|
|
45
|
+
sys.argv = [arg for arg in sys.argv if arg] # Remove empty strings
|
|
46
|
+
|
|
47
|
+
stcli.main()
|
|
48
|
+
except ImportError:
|
|
49
|
+
raise ImportError(
|
|
50
|
+
"Misata Studio requires streamlit. Install with:\n"
|
|
51
|
+
" pip install misata[studio]"
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
__all__ = ["launch"]
|
misata/studio/app.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import streamlit as st
|
|
2
|
+
from misata.studio.state.store import StudioStore
|
|
3
|
+
from misata.studio.utils.styles import apply_custom_styles
|
|
4
|
+
from misata.studio.components.sidebar import render_sidebar
|
|
5
|
+
from misata.studio.tabs.schema_designer import render_schema_tab
|
|
6
|
+
from misata.studio.tabs.outcome_curve import render_outcome_tab
|
|
7
|
+
from misata.studio.tabs.configure import render_configure_tab
|
|
8
|
+
from misata.studio.tabs.generate import render_generate_tab
|
|
9
|
+
|
|
10
|
+
# Page Config
|
|
11
|
+
st.set_page_config(
|
|
12
|
+
page_title="Misata Studio",
|
|
13
|
+
page_icon="M",
|
|
14
|
+
layout="wide",
|
|
15
|
+
initial_sidebar_state="expanded"
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
def main():
|
|
19
|
+
"""Main Orchestrator for Misata Studio."""
|
|
20
|
+
|
|
21
|
+
# 1. Initialize State & Styles
|
|
22
|
+
StudioStore.init()
|
|
23
|
+
apply_custom_styles()
|
|
24
|
+
|
|
25
|
+
# 2. Render Sidebar
|
|
26
|
+
render_sidebar()
|
|
27
|
+
|
|
28
|
+
# 3. Router
|
|
29
|
+
active_tab = StudioStore.get("active_tab", "Schema")
|
|
30
|
+
|
|
31
|
+
# Content Area
|
|
32
|
+
with st.container():
|
|
33
|
+
if active_tab == "Schema":
|
|
34
|
+
render_schema_tab()
|
|
35
|
+
|
|
36
|
+
elif active_tab == "Outcome":
|
|
37
|
+
render_outcome_tab()
|
|
38
|
+
|
|
39
|
+
elif active_tab == "Configure":
|
|
40
|
+
render_configure_tab()
|
|
41
|
+
|
|
42
|
+
elif active_tab == "Generate":
|
|
43
|
+
render_generate_tab()
|
|
44
|
+
|
|
45
|
+
else:
|
|
46
|
+
st.error(f"Unknown View: {active_tab}")
|
|
47
|
+
|
|
48
|
+
if __name__ == "__main__":
|
|
49
|
+
main()
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import streamlit as st
|
|
2
|
+
from misata.studio.state.store import StudioStore
|
|
3
|
+
from misata.schema import Column
|
|
4
|
+
import random
|
|
5
|
+
|
|
6
|
+
def render_table_inspector():
|
|
7
|
+
"""Render the detailed inspector panel for the selected table."""
|
|
8
|
+
selected_table_name = StudioStore.get("selected_table")
|
|
9
|
+
schema_config = StudioStore.get("schema_config")
|
|
10
|
+
|
|
11
|
+
if not selected_table_name or not schema_config:
|
|
12
|
+
return
|
|
13
|
+
|
|
14
|
+
# Find the table object
|
|
15
|
+
table = next((t for t in schema_config.tables if t.name == selected_table_name), None)
|
|
16
|
+
if not table:
|
|
17
|
+
return
|
|
18
|
+
|
|
19
|
+
with st.expander(f"🛠 Edit Table: {table.name}", expanded=True):
|
|
20
|
+
# 1. Table Properties
|
|
21
|
+
c1, c2 = st.columns([2, 1])
|
|
22
|
+
with c1:
|
|
23
|
+
new_name = st.text_input("Table Name", table.name)
|
|
24
|
+
if new_name != table.name:
|
|
25
|
+
table.name = new_name
|
|
26
|
+
st.rerun()
|
|
27
|
+
|
|
28
|
+
with c2:
|
|
29
|
+
new_rows = st.number_input("Rows", 1, 1000000, table.row_count)
|
|
30
|
+
table.row_count = new_rows
|
|
31
|
+
|
|
32
|
+
st.markdown("---")
|
|
33
|
+
st.markdown("**Columns**")
|
|
34
|
+
|
|
35
|
+
# 2. Column Editor
|
|
36
|
+
columns = schema_config.columns.get(table.name, [])
|
|
37
|
+
|
|
38
|
+
# List existing
|
|
39
|
+
for i, col in enumerate(columns):
|
|
40
|
+
with st.container():
|
|
41
|
+
c_name, c_type, c_del = st.columns([3, 2, 1])
|
|
42
|
+
|
|
43
|
+
with c_name:
|
|
44
|
+
new_col_name = st.text_input(f"Name", col.name, key=f"cn_{table.name}_{i}", label_visibility="collapsed")
|
|
45
|
+
col.name = new_col_name
|
|
46
|
+
|
|
47
|
+
with c_type:
|
|
48
|
+
type_options = ["int", "float", "date", "text", "categorical", "boolean", "foreign_key"]
|
|
49
|
+
new_type = st.selectbox("Type", type_options, index=type_options.index(col.type) if col.type in type_options else 3, key=f"ct_{table.name}_{i}", label_visibility="collapsed")
|
|
50
|
+
col.type = new_type
|
|
51
|
+
|
|
52
|
+
with c_del:
|
|
53
|
+
if st.button("🗑", key=f"del_{table.name}_{i}"):
|
|
54
|
+
columns.pop(i)
|
|
55
|
+
st.rerun()
|
|
56
|
+
|
|
57
|
+
# Distribution Tweak (Simple expander for now)
|
|
58
|
+
with st.expander("Distribution Settings", expanded=False):
|
|
59
|
+
if col.type in ["int", "float"]:
|
|
60
|
+
min_v = st.number_input("Min", value=float(col.distribution_params.get('min', 0)), key=f"min_{table.name}_{i}")
|
|
61
|
+
max_v = st.number_input("Max", value=float(col.distribution_params.get('max', 100)), key=f"max_{table.name}_{i}")
|
|
62
|
+
col.distribution_params['min'] = min_v
|
|
63
|
+
col.distribution_params['max'] = max_v
|
|
64
|
+
elif col.type == "categorical":
|
|
65
|
+
cats = st.text_input("Categories (comma sep)", value=",".join(col.distribution_params.get('choices', [])), key=f"cat_{table.name}_{i}")
|
|
66
|
+
col.distribution_params['choices'] = [c.strip() for c in cats.split(",")]
|
|
67
|
+
|
|
68
|
+
# Add New Column Button
|
|
69
|
+
if st.button("+ Add Column", key=f"add_col_{table.name}"):
|
|
70
|
+
new_col = Column(
|
|
71
|
+
name=f"new_column_{len(columns)+1}",
|
|
72
|
+
type="text",
|
|
73
|
+
distribution_params={}
|
|
74
|
+
)
|
|
75
|
+
columns.append(new_col)
|
|
76
|
+
st.rerun()
|
|
77
|
+
|
|
78
|
+
# Save/Close
|
|
79
|
+
if st.button("Done Editing", type="primary", use_container_width=True):
|
|
80
|
+
StudioStore.set("selected_table", None)
|
|
81
|
+
st.rerun()
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import streamlit as st
|
|
2
|
+
from misata.studio.state.store import StudioStore
|
|
3
|
+
|
|
4
|
+
def render_sidebar():
|
|
5
|
+
"""Render the sidebar with navigation and branding."""
|
|
6
|
+
with st.sidebar:
|
|
7
|
+
# 1. Branding
|
|
8
|
+
st.markdown('<div class="brand-logo">Misata</div>', unsafe_allow_html=True)
|
|
9
|
+
st.markdown('<p style="font-size: 0.8rem; color: var(--text-tertiary); margin-top: -10px;">SYNTHETIC STUDIO PRO</p>', unsafe_allow_html=True)
|
|
10
|
+
st.markdown("---")
|
|
11
|
+
|
|
12
|
+
# 2. Navigation
|
|
13
|
+
current_tab = StudioStore.get("active_tab", "Schema")
|
|
14
|
+
|
|
15
|
+
# Helper for nav buttons
|
|
16
|
+
def nav_button(label, key, icon=""):
|
|
17
|
+
if st.button(f"{label}", key=key, use_container_width=True):
|
|
18
|
+
StudioStore.set("active_tab", label.replace(" Builder", "").replace(" Curve", ""))
|
|
19
|
+
st.rerun()
|
|
20
|
+
|
|
21
|
+
nav_button("Schema Builder", "nav_schema")
|
|
22
|
+
nav_button("Outcome Curve", "nav_outcome")
|
|
23
|
+
nav_button("Configure", "nav_config")
|
|
24
|
+
nav_button("Generate", "nav_gen")
|
|
25
|
+
|
|
26
|
+
st.markdown("---")
|
|
27
|
+
|
|
28
|
+
# 3. Status
|
|
29
|
+
st.markdown("""
|
|
30
|
+
<div style="background: rgba(255,255,255,0.1); padding: 1rem; border-radius: 8px; border: 1px solid rgba(255,255,255,0.1);">
|
|
31
|
+
<div style="font-size: 0.75rem; color: rgba(255,255,255,0.6); text-transform: uppercase; letter-spacing: 0.05em;">Status</div>
|
|
32
|
+
<div style="color: #FFFFFF !important; font-weight: 500; margin-top: 4px;">API Connected</div>
|
|
33
|
+
<div style="font-size: 0.7rem; color: rgba(255,255,255,0.8) !important; margin-top: 4px;">v2.0.0 (World Class)</div>
|
|
34
|
+
</div>
|
|
35
|
+
""", unsafe_allow_html=True)
|