agent-data-cli 0.1.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.
- agent_data_cli/PYPI_README.md +72 -0
- agent_data_cli/__init__.py +2 -0
- agent_data_cli/__main__.py +7 -0
- agent_data_cli/cli/__init__.py +2 -0
- agent_data_cli/cli/__main__.py +7 -0
- agent_data_cli/cli/commands/__init__.py +85 -0
- agent_data_cli/cli/commands/channel.py +78 -0
- agent_data_cli/cli/commands/common.py +97 -0
- agent_data_cli/cli/commands/config.py +270 -0
- agent_data_cli/cli/commands/content/__init__.py +29 -0
- agent_data_cli/cli/commands/content/common.py +172 -0
- agent_data_cli/cli/commands/content/interact.py +74 -0
- agent_data_cli/cli/commands/content/query.py +111 -0
- agent_data_cli/cli/commands/content/search.py +75 -0
- agent_data_cli/cli/commands/content/update.py +198 -0
- agent_data_cli/cli/commands/dashboard.py +87 -0
- agent_data_cli/cli/commands/group.py +128 -0
- agent_data_cli/cli/commands/help.py +44 -0
- agent_data_cli/cli/commands/hub.py +107 -0
- agent_data_cli/cli/commands/init.py +29 -0
- agent_data_cli/cli/commands/source.py +41 -0
- agent_data_cli/cli/commands/specs.py +241 -0
- agent_data_cli/cli/commands/sub.py +60 -0
- agent_data_cli/cli/formatters.py +537 -0
- agent_data_cli/cli/help.py +149 -0
- agent_data_cli/cli/main.py +46 -0
- agent_data_cli/core/__init__.py +2 -0
- agent_data_cli/core/base.py +222 -0
- agent_data_cli/core/capabilities.py +105 -0
- agent_data_cli/core/config.py +236 -0
- agent_data_cli/core/discovery.py +158 -0
- agent_data_cli/core/help.py +16 -0
- agent_data_cli/core/manifest.py +329 -0
- agent_data_cli/core/models.py +296 -0
- agent_data_cli/core/protocol.py +135 -0
- agent_data_cli/core/registry.py +353 -0
- agent_data_cli/core/source_defaults.py +24 -0
- agent_data_cli/dashboard/__init__.py +2 -0
- agent_data_cli/dashboard/adapters/__init__.py +2 -0
- agent_data_cli/dashboard/adapters/channel.py +73 -0
- agent_data_cli/dashboard/adapters/config.py +153 -0
- agent_data_cli/dashboard/adapters/content.py +350 -0
- agent_data_cli/dashboard/adapters/group.py +47 -0
- agent_data_cli/dashboard/adapters/help.py +32 -0
- agent_data_cli/dashboard/adapters/source.py +61 -0
- agent_data_cli/dashboard/adapters/sub.py +28 -0
- agent_data_cli/dashboard/context.py +29 -0
- agent_data_cli/dashboard/index.py +30 -0
- agent_data_cli/dashboard/pages/01_Source.py +57 -0
- agent_data_cli/dashboard/pages/02_Channel.py +99 -0
- agent_data_cli/dashboard/pages/03_Content_Search.py +64 -0
- agent_data_cli/dashboard/pages/04_Content_Query.py +79 -0
- agent_data_cli/dashboard/pages/05_Content_Update.py +103 -0
- agent_data_cli/dashboard/pages/06_Sub.py +51 -0
- agent_data_cli/dashboard/pages/07_Group.py +116 -0
- agent_data_cli/dashboard/pages/08_Config.py +114 -0
- agent_data_cli/dashboard/pages/09_Help.py +48 -0
- agent_data_cli/dashboard/pages/__init__.py +2 -0
- agent_data_cli/dashboard/runtime.py +208 -0
- agent_data_cli/dashboard/state.py +60 -0
- agent_data_cli/dashboard/widgets/__init__.py +2 -0
- agent_data_cli/dashboard/widgets/common.py +90 -0
- agent_data_cli/dashboard/widgets/forms.py +29 -0
- agent_data_cli/dashboard/widgets/tables.py +10 -0
- agent_data_cli/fetchers/__init__.py +2 -0
- agent_data_cli/fetchers/base.py +61 -0
- agent_data_cli/fetchers/browser.py +44 -0
- agent_data_cli/fetchers/http.py +313 -0
- agent_data_cli/fetchers/jina.py +44 -0
- agent_data_cli/hub/__init__.py +6 -0
- agent_data_cli/hub/models.py +20 -0
- agent_data_cli/hub/service.py +210 -0
- agent_data_cli/init_service.py +29 -0
- agent_data_cli/main.py +72 -0
- agent_data_cli/migration.py +53 -0
- agent_data_cli/runtime_paths.py +90 -0
- agent_data_cli/store/__init__.py +2 -0
- agent_data_cli/store/audit.py +42 -0
- agent_data_cli/store/channels.py +80 -0
- agent_data_cli/store/configs.py +134 -0
- agent_data_cli/store/content.py +770 -0
- agent_data_cli/store/db.py +298 -0
- agent_data_cli/store/groups.py +120 -0
- agent_data_cli/store/health.py +53 -0
- agent_data_cli/store/migrations.py +176 -0
- agent_data_cli/store/repositories.py +136 -0
- agent_data_cli/store/subscriptions.py +119 -0
- agent_data_cli/utils/__init__.py +2 -0
- agent_data_cli/utils/text.py +21 -0
- agent_data_cli/utils/time.py +63 -0
- agent_data_cli/utils/urls.py +8 -0
- agent_data_cli-0.1.0.dist-info/METADATA +104 -0
- agent_data_cli-0.1.0.dist-info/RECORD +97 -0
- agent_data_cli-0.1.0.dist-info/WHEEL +5 -0
- agent_data_cli-0.1.0.dist-info/entry_points.txt +2 -0
- agent_data_cli-0.1.0.dist-info/licenses/LICENSE +21 -0
- agent_data_cli-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from agent_data_cli.core.registry import SourceRegistry, build_default_registry
|
|
7
|
+
from agent_data_cli.runtime_paths import resolve_runtime_paths
|
|
8
|
+
from agent_data_cli.store.db import Store
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass(frozen=True, slots=True)
|
|
12
|
+
class DashboardContext:
|
|
13
|
+
db_path: str
|
|
14
|
+
store: Store
|
|
15
|
+
registry: SourceRegistry
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def build_dashboard_context(
|
|
19
|
+
*,
|
|
20
|
+
db_path: str | None = None,
|
|
21
|
+
sources_dir: Path | None = None,
|
|
22
|
+
) -> DashboardContext:
|
|
23
|
+
resolved_db_path = str(resolve_runtime_paths().db_path) if db_path is None else db_path
|
|
24
|
+
Path(resolved_db_path).parent.mkdir(parents=True, exist_ok=True)
|
|
25
|
+
store = Store(resolved_db_path)
|
|
26
|
+
store.init_schema()
|
|
27
|
+
registry = build_default_registry(store, sources_dir=sources_dir)
|
|
28
|
+
store.init_schema(storage_specs=registry.list_storage_specs())
|
|
29
|
+
return DashboardContext(db_path=resolved_db_path, store=store, registry=registry)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import streamlit as st
|
|
4
|
+
|
|
5
|
+
from agent_data_cli.dashboard.runtime import get_dashboard_status
|
|
6
|
+
from agent_data_cli.dashboard.widgets.common import render_object_details, running_in_streamlit
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def render_page() -> None:
|
|
10
|
+
st.set_page_config(page_title="Agent-Data-Cli Dashboard", layout="wide")
|
|
11
|
+
st.title("Agent-Data-Cli Dashboard")
|
|
12
|
+
st.caption("Streamlit Dashboard for Human to Understand the Projetc")
|
|
13
|
+
|
|
14
|
+
status = get_dashboard_status()
|
|
15
|
+
st.subheader("Runtime")
|
|
16
|
+
render_object_details(
|
|
17
|
+
{
|
|
18
|
+
"running": status.running,
|
|
19
|
+
"pid": status.pid,
|
|
20
|
+
"host": status.host,
|
|
21
|
+
"port": status.port,
|
|
22
|
+
"url": status.url,
|
|
23
|
+
"started_at": status.started_at,
|
|
24
|
+
"log_path": status.log_path,
|
|
25
|
+
}
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
if running_in_streamlit():
|
|
30
|
+
render_page()
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import streamlit as st
|
|
4
|
+
|
|
5
|
+
from agent_data_cli.dashboard.adapters.source import check_source_config, check_source_health, list_sources
|
|
6
|
+
from agent_data_cli.dashboard.context import build_dashboard_context
|
|
7
|
+
from agent_data_cli.dashboard.state import ensure_page_result, get_page_state, save_page_result
|
|
8
|
+
from agent_data_cli.dashboard.widgets.common import render_exception, render_object_details, running_in_streamlit
|
|
9
|
+
from agent_data_cli.dashboard.widgets.forms import source_select
|
|
10
|
+
from agent_data_cli.dashboard.widgets.tables import render_rows
|
|
11
|
+
from agent_data_cli.utils.time import utc_now_iso
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def render_page() -> None:
|
|
15
|
+
ctx = build_dashboard_context()
|
|
16
|
+
page_state = ensure_page_result(
|
|
17
|
+
st.session_state,
|
|
18
|
+
"source_page_state",
|
|
19
|
+
loader=lambda: {"rows": list_sources(ctx.registry)},
|
|
20
|
+
updated_at=utc_now_iso(),
|
|
21
|
+
)
|
|
22
|
+
st.title("Source")
|
|
23
|
+
|
|
24
|
+
if st.button("Refresh Sources", key="source_refresh"):
|
|
25
|
+
rows = list_sources(ctx.registry)
|
|
26
|
+
save_page_result(st.session_state, "source_page_state", inputs={}, result={"rows": rows}, updated_at=utc_now_iso())
|
|
27
|
+
page_state = get_page_state(st.session_state, "source_page_state")
|
|
28
|
+
render_rows(None if page_state["result"] is None else page_state["result"]["rows"], empty_message="No source data yet.")
|
|
29
|
+
|
|
30
|
+
selected_source = source_select(ctx.registry, key="source_page_source")
|
|
31
|
+
col1, col2 = st.columns(2)
|
|
32
|
+
with col1:
|
|
33
|
+
if st.button("Check Health", key="source_health") and selected_source is not None:
|
|
34
|
+
try:
|
|
35
|
+
result = check_source_health(ctx.registry, ctx.store, selected_source)
|
|
36
|
+
page_state["health_result"] = result
|
|
37
|
+
st.session_state["source_page_state"] = page_state
|
|
38
|
+
except Exception as exc: # noqa: BLE001
|
|
39
|
+
render_exception(exc)
|
|
40
|
+
|
|
41
|
+
if page_state.get("health_result") is not None:
|
|
42
|
+
render_object_details(page_state["health_result"], title="Health")
|
|
43
|
+
|
|
44
|
+
with col2:
|
|
45
|
+
if st.button("Config Check", key="source_config_check") and selected_source is not None:
|
|
46
|
+
try:
|
|
47
|
+
page_state["config_check_result"] = check_source_config(ctx.registry, selected_source)
|
|
48
|
+
st.session_state["source_page_state"] = page_state
|
|
49
|
+
except Exception as exc: # noqa: BLE001
|
|
50
|
+
render_exception(exc)
|
|
51
|
+
|
|
52
|
+
if page_state.get("config_check_result") is not None:
|
|
53
|
+
render_object_details(page_state["config_check_result"], title="Config Check")
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
if running_in_streamlit():
|
|
57
|
+
render_page()
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import streamlit as st
|
|
4
|
+
|
|
5
|
+
from agent_data_cli.dashboard.adapters.channel import list_channel_options, list_channels, search_channels
|
|
6
|
+
from agent_data_cli.dashboard.adapters.group import add_channel_to_group
|
|
7
|
+
from agent_data_cli.dashboard.adapters.sub import add_subscription, remove_subscription
|
|
8
|
+
from agent_data_cli.dashboard.context import build_dashboard_context
|
|
9
|
+
from agent_data_cli.dashboard.state import get_page_state, invalidate_pages, save_page_result
|
|
10
|
+
from agent_data_cli.dashboard.widgets.common import render_exception, running_in_streamlit
|
|
11
|
+
from agent_data_cli.dashboard.widgets.forms import optional_channel_select, optional_group_select, source_select
|
|
12
|
+
from agent_data_cli.dashboard.widgets.tables import render_rows
|
|
13
|
+
from agent_data_cli.utils.time import utc_now_iso
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def render_page() -> None:
|
|
17
|
+
ctx = build_dashboard_context()
|
|
18
|
+
st.title("Channel")
|
|
19
|
+
form_row1 = st.columns(2)
|
|
20
|
+
with form_row1[0]:
|
|
21
|
+
source_name = source_select(ctx.registry, key="channel_source")
|
|
22
|
+
with form_row1[1]:
|
|
23
|
+
query = st.text_input("Query", key="channel_query")
|
|
24
|
+
form_row2 = st.columns(2)
|
|
25
|
+
with form_row2[0]:
|
|
26
|
+
limit = st.number_input("Limit", min_value=1, value=20, key="channel_limit")
|
|
27
|
+
page_state = get_page_state(st.session_state, "channel_page_state")
|
|
28
|
+
|
|
29
|
+
with form_row2[1]:
|
|
30
|
+
action_row = st.columns(2)
|
|
31
|
+
with action_row[0]:
|
|
32
|
+
list_clicked = st.button("List Channels", key="channel_list", width="stretch")
|
|
33
|
+
with action_row[1]:
|
|
34
|
+
search_clicked = st.button("Search Channels", key="channel_search", width="stretch")
|
|
35
|
+
|
|
36
|
+
if list_clicked and source_name is not None:
|
|
37
|
+
try:
|
|
38
|
+
rows = list_channels(ctx.registry, ctx.store, source_name)
|
|
39
|
+
save_page_result(
|
|
40
|
+
st.session_state,
|
|
41
|
+
"channel_page_state",
|
|
42
|
+
inputs={"source": source_name, "mode": "list"},
|
|
43
|
+
result={"rows": rows},
|
|
44
|
+
updated_at=utc_now_iso(),
|
|
45
|
+
)
|
|
46
|
+
page_state = get_page_state(st.session_state, "channel_page_state")
|
|
47
|
+
except Exception as exc: # noqa: BLE001
|
|
48
|
+
render_exception(exc)
|
|
49
|
+
if search_clicked and source_name is not None:
|
|
50
|
+
try:
|
|
51
|
+
rows = search_channels(ctx.registry, ctx.store, source_name, query=query, limit=int(limit))
|
|
52
|
+
save_page_result(
|
|
53
|
+
st.session_state,
|
|
54
|
+
"channel_page_state",
|
|
55
|
+
inputs={"source": source_name, "query": query, "limit": int(limit)},
|
|
56
|
+
result={"rows": rows},
|
|
57
|
+
updated_at=utc_now_iso(),
|
|
58
|
+
)
|
|
59
|
+
page_state = get_page_state(st.session_state, "channel_page_state")
|
|
60
|
+
except Exception as exc: # noqa: BLE001
|
|
61
|
+
render_exception(exc)
|
|
62
|
+
|
|
63
|
+
render_rows(None if page_state["result"] is None else page_state["result"]["rows"], empty_message="Search or list channels.")
|
|
64
|
+
|
|
65
|
+
action_inputs = st.columns(2)
|
|
66
|
+
with action_inputs[0]:
|
|
67
|
+
selected_channel = optional_channel_select(
|
|
68
|
+
[] if source_name is None else list_channel_options(ctx.registry, ctx.store, source_name),
|
|
69
|
+
key="channel_selected",
|
|
70
|
+
label="Selected Channel",
|
|
71
|
+
)
|
|
72
|
+
with action_inputs[1]:
|
|
73
|
+
selected_group = optional_group_select(ctx.store, key="channel_group")
|
|
74
|
+
col1, col2, col3 = st.columns(3)
|
|
75
|
+
with col1:
|
|
76
|
+
if st.button("Subscribe", key="channel_sub") and source_name is not None and selected_channel:
|
|
77
|
+
try:
|
|
78
|
+
add_subscription(ctx.registry, source_name, selected_channel)
|
|
79
|
+
invalidate_pages(st.session_state, "sub_page_state", "channel_page_state", "content_update_page_state")
|
|
80
|
+
except Exception as exc: # noqa: BLE001
|
|
81
|
+
render_exception(exc)
|
|
82
|
+
with col2:
|
|
83
|
+
if st.button("Unsubscribe", key="channel_unsub") and source_name is not None and selected_channel:
|
|
84
|
+
try:
|
|
85
|
+
remove_subscription(ctx.registry, source_name, selected_channel)
|
|
86
|
+
invalidate_pages(st.session_state, "sub_page_state", "channel_page_state", "content_update_page_state")
|
|
87
|
+
except Exception as exc: # noqa: BLE001
|
|
88
|
+
render_exception(exc)
|
|
89
|
+
with col3:
|
|
90
|
+
if st.button("Add To Group", key="channel_group_add") and source_name is not None and selected_channel and selected_group:
|
|
91
|
+
try:
|
|
92
|
+
add_channel_to_group(ctx.store, selected_group, source_name, selected_channel)
|
|
93
|
+
invalidate_pages(st.session_state, "group_page_state", "content_update_page_state", "content_query_page_state")
|
|
94
|
+
except Exception as exc: # noqa: BLE001
|
|
95
|
+
render_exception(exc)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
if running_in_streamlit():
|
|
99
|
+
render_page()
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import streamlit as st
|
|
4
|
+
|
|
5
|
+
from agent_data_cli.dashboard.adapters.channel import list_channel_options
|
|
6
|
+
from agent_data_cli.dashboard.adapters.content import search_content
|
|
7
|
+
from agent_data_cli.dashboard.context import build_dashboard_context
|
|
8
|
+
from agent_data_cli.dashboard.state import get_page_state, save_page_result
|
|
9
|
+
from agent_data_cli.dashboard.widgets.common import render_exception, running_in_streamlit
|
|
10
|
+
from agent_data_cli.dashboard.widgets.forms import optional_channel_select, source_select
|
|
11
|
+
from agent_data_cli.dashboard.widgets.tables import render_rows
|
|
12
|
+
from agent_data_cli.utils.time import utc_now_iso
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def render_page() -> None:
|
|
16
|
+
ctx = build_dashboard_context()
|
|
17
|
+
st.title("Content Search")
|
|
18
|
+
row1 = st.columns(2)
|
|
19
|
+
with row1[0]:
|
|
20
|
+
source_name = source_select(ctx.registry, key="content_search_source")
|
|
21
|
+
with row1[1]:
|
|
22
|
+
channel = optional_channel_select(
|
|
23
|
+
[] if source_name is None else list_channel_options(ctx.registry, ctx.store, source_name),
|
|
24
|
+
key="content_search_channel",
|
|
25
|
+
)
|
|
26
|
+
row2 = st.columns(2)
|
|
27
|
+
with row2[0]:
|
|
28
|
+
query = st.text_input("Query", key="content_search_query")
|
|
29
|
+
with row2[1]:
|
|
30
|
+
since = st.text_input("Since", key="content_search_since")
|
|
31
|
+
row3 = st.columns(2)
|
|
32
|
+
with row3[0]:
|
|
33
|
+
limit = st.number_input("Limit", min_value=1, value=20, key="content_search_limit")
|
|
34
|
+
page_state = get_page_state(st.session_state, "content_search_page_state")
|
|
35
|
+
|
|
36
|
+
with row3[1]:
|
|
37
|
+
run_clicked = st.button("Run Search", key="content_search_run", width="stretch")
|
|
38
|
+
|
|
39
|
+
if run_clicked and source_name is not None:
|
|
40
|
+
try:
|
|
41
|
+
rows = search_content(
|
|
42
|
+
ctx.registry,
|
|
43
|
+
source_name,
|
|
44
|
+
channel=channel or None,
|
|
45
|
+
query=query or None,
|
|
46
|
+
since=since or None,
|
|
47
|
+
limit=int(limit),
|
|
48
|
+
)
|
|
49
|
+
save_page_result(
|
|
50
|
+
st.session_state,
|
|
51
|
+
"content_search_page_state",
|
|
52
|
+
inputs={"source": source_name, "channel": channel, "query": query, "since": since, "limit": int(limit)},
|
|
53
|
+
result={"rows": rows},
|
|
54
|
+
updated_at=utc_now_iso(),
|
|
55
|
+
)
|
|
56
|
+
page_state = get_page_state(st.session_state, "content_search_page_state")
|
|
57
|
+
except Exception as exc: # noqa: BLE001
|
|
58
|
+
render_exception(exc)
|
|
59
|
+
|
|
60
|
+
render_rows(None if page_state["result"] is None else page_state["result"]["rows"], empty_message="Run a remote content search.")
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
if running_in_streamlit():
|
|
64
|
+
render_page()
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import streamlit as st
|
|
4
|
+
|
|
5
|
+
from agent_data_cli.dashboard.adapters.channel import list_channel_options
|
|
6
|
+
from agent_data_cli.dashboard.adapters.content import query_content
|
|
7
|
+
from agent_data_cli.dashboard.context import build_dashboard_context
|
|
8
|
+
from agent_data_cli.dashboard.state import get_page_state, save_page_result
|
|
9
|
+
from agent_data_cli.dashboard.widgets.common import render_exception, running_in_streamlit
|
|
10
|
+
from agent_data_cli.dashboard.widgets.forms import optional_channel_select, optional_group_select, source_select
|
|
11
|
+
from agent_data_cli.dashboard.widgets.tables import render_rows
|
|
12
|
+
from agent_data_cli.utils.time import utc_now_iso
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def render_page() -> None:
|
|
16
|
+
ctx = build_dashboard_context()
|
|
17
|
+
st.title("Content Query")
|
|
18
|
+
mode = st.radio("Mode", ["source", "group"], horizontal=True, key="content_query_mode")
|
|
19
|
+
row1 = st.columns(2)
|
|
20
|
+
with row1[0]:
|
|
21
|
+
source_name = source_select(ctx.registry, key="content_query_source") if mode == "source" else None
|
|
22
|
+
with row1[1]:
|
|
23
|
+
group_name = optional_group_select(ctx.store, key="content_query_group") if mode == "group" else None
|
|
24
|
+
row2 = st.columns(2)
|
|
25
|
+
with row2[0]:
|
|
26
|
+
channel_key = (
|
|
27
|
+
optional_channel_select(
|
|
28
|
+
[] if source_name is None else list_channel_options(ctx.registry, ctx.store, source_name),
|
|
29
|
+
key="content_query_channel",
|
|
30
|
+
)
|
|
31
|
+
if mode == "source"
|
|
32
|
+
else None
|
|
33
|
+
)
|
|
34
|
+
with row2[1]:
|
|
35
|
+
keywords = st.text_input("Keywords", key="content_query_keywords")
|
|
36
|
+
row3 = st.columns(2)
|
|
37
|
+
with row3[0]:
|
|
38
|
+
since = st.text_input("Since", key="content_query_since")
|
|
39
|
+
with row3[1]:
|
|
40
|
+
limit = st.number_input("Limit", min_value=1, value=20, key="content_query_limit")
|
|
41
|
+
page_state = get_page_state(st.session_state, "content_query_page_state")
|
|
42
|
+
|
|
43
|
+
run_clicked = st.button("Run Query", key="content_query_run")
|
|
44
|
+
if run_clicked:
|
|
45
|
+
try:
|
|
46
|
+
result = query_content(
|
|
47
|
+
ctx.registry,
|
|
48
|
+
ctx.store,
|
|
49
|
+
source_name=source_name,
|
|
50
|
+
group_name=group_name,
|
|
51
|
+
channel_key=channel_key or None,
|
|
52
|
+
keywords=keywords or None,
|
|
53
|
+
since=since or None,
|
|
54
|
+
limit=int(limit),
|
|
55
|
+
)
|
|
56
|
+
save_page_result(
|
|
57
|
+
st.session_state,
|
|
58
|
+
"content_query_page_state",
|
|
59
|
+
inputs={
|
|
60
|
+
"mode": mode,
|
|
61
|
+
"source": source_name,
|
|
62
|
+
"group": group_name,
|
|
63
|
+
"channel": channel_key,
|
|
64
|
+
"keywords": keywords,
|
|
65
|
+
"since": since,
|
|
66
|
+
"limit": int(limit),
|
|
67
|
+
},
|
|
68
|
+
result=result,
|
|
69
|
+
updated_at=utc_now_iso(),
|
|
70
|
+
)
|
|
71
|
+
page_state = get_page_state(st.session_state, "content_query_page_state")
|
|
72
|
+
except Exception as exc: # noqa: BLE001
|
|
73
|
+
render_exception(exc)
|
|
74
|
+
|
|
75
|
+
render_rows(None if page_state["result"] is None else page_state["result"]["rows"], empty_message="Query the local database.")
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
if running_in_streamlit():
|
|
79
|
+
render_page()
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import streamlit as st
|
|
4
|
+
|
|
5
|
+
from agent_data_cli.dashboard.adapters.channel import list_subscribed_channel_options
|
|
6
|
+
from agent_data_cli.dashboard.adapters.content import update_content
|
|
7
|
+
from agent_data_cli.dashboard.context import build_dashboard_context
|
|
8
|
+
from agent_data_cli.dashboard.state import get_page_state, invalidate_pages, save_page_result
|
|
9
|
+
from agent_data_cli.dashboard.widgets.common import render_exception, render_object_details, running_in_streamlit
|
|
10
|
+
from agent_data_cli.dashboard.widgets.forms import optional_channel_select, optional_group_select, source_select
|
|
11
|
+
from agent_data_cli.dashboard.widgets.tables import render_rows
|
|
12
|
+
from agent_data_cli.utils.time import utc_now_iso
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def build_result_overview(result: dict[str, object]) -> dict[str, object]:
|
|
16
|
+
overview: dict[str, object] = {}
|
|
17
|
+
for key in ("dry_run", "saved_count", "skipped_count"):
|
|
18
|
+
if key in result:
|
|
19
|
+
overview[key] = result[key]
|
|
20
|
+
return overview
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def render_page() -> None:
|
|
24
|
+
ctx = build_dashboard_context()
|
|
25
|
+
st.title("Content Update")
|
|
26
|
+
mode = st.radio("Mode", ["source", "group"], horizontal=True, key="content_update_mode")
|
|
27
|
+
row1 = st.columns(2)
|
|
28
|
+
with row1[0]:
|
|
29
|
+
source_name = source_select(ctx.registry, key="content_update_source") if mode == "source" else None
|
|
30
|
+
with row1[1]:
|
|
31
|
+
group_name = optional_group_select(ctx.store, key="content_update_group") if mode == "group" else None
|
|
32
|
+
row2 = st.columns(2)
|
|
33
|
+
with row2[0]:
|
|
34
|
+
channel_key = (
|
|
35
|
+
optional_channel_select(
|
|
36
|
+
[] if source_name is None else list_subscribed_channel_options(ctx.store, source_name),
|
|
37
|
+
key="content_update_channel",
|
|
38
|
+
)
|
|
39
|
+
if mode == "source"
|
|
40
|
+
else None
|
|
41
|
+
)
|
|
42
|
+
with row2[1]:
|
|
43
|
+
since = st.text_input("Since", key="content_update_since")
|
|
44
|
+
row3 = st.columns(2)
|
|
45
|
+
with row3[0]:
|
|
46
|
+
limit = st.number_input("Limit", min_value=1, value=20, key="content_update_limit")
|
|
47
|
+
with row3[1]:
|
|
48
|
+
checkbox_row = st.columns(2)
|
|
49
|
+
with checkbox_row[0]:
|
|
50
|
+
fetch_all = st.checkbox("All", key="content_update_all")
|
|
51
|
+
with checkbox_row[1]:
|
|
52
|
+
dry_run = st.checkbox("Dry Run", key="content_update_dry_run")
|
|
53
|
+
page_state = get_page_state(st.session_state, "content_update_page_state")
|
|
54
|
+
|
|
55
|
+
run_clicked = st.button("Run Update", key="content_update_run")
|
|
56
|
+
if run_clicked:
|
|
57
|
+
try:
|
|
58
|
+
result = update_content(
|
|
59
|
+
ctx.registry,
|
|
60
|
+
ctx.store,
|
|
61
|
+
source_name=source_name,
|
|
62
|
+
group_name=group_name,
|
|
63
|
+
channel_key=channel_key or None,
|
|
64
|
+
since=since or None,
|
|
65
|
+
limit=int(limit),
|
|
66
|
+
fetch_all=fetch_all,
|
|
67
|
+
dry_run=dry_run,
|
|
68
|
+
)
|
|
69
|
+
save_page_result(
|
|
70
|
+
st.session_state,
|
|
71
|
+
"content_update_page_state",
|
|
72
|
+
inputs={
|
|
73
|
+
"mode": mode,
|
|
74
|
+
"source": source_name,
|
|
75
|
+
"group": group_name,
|
|
76
|
+
"channel": channel_key,
|
|
77
|
+
"since": since,
|
|
78
|
+
"limit": int(limit),
|
|
79
|
+
"all": fetch_all,
|
|
80
|
+
"dry_run": dry_run,
|
|
81
|
+
},
|
|
82
|
+
result=result,
|
|
83
|
+
updated_at=utc_now_iso(),
|
|
84
|
+
)
|
|
85
|
+
invalidate_pages(st.session_state, "content_query_page_state", "source_page_state")
|
|
86
|
+
page_state = get_page_state(st.session_state, "content_update_page_state")
|
|
87
|
+
except Exception as exc: # noqa: BLE001
|
|
88
|
+
render_exception(exc)
|
|
89
|
+
|
|
90
|
+
if page_state["result"] is not None:
|
|
91
|
+
overview = build_result_overview(page_state["result"])
|
|
92
|
+
if overview:
|
|
93
|
+
render_object_details(overview, title="Update Result")
|
|
94
|
+
if "summaries" in page_state["result"]:
|
|
95
|
+
render_rows(page_state["result"]["summaries"], empty_message="No updates.")
|
|
96
|
+
elif "targets" in page_state["result"]:
|
|
97
|
+
render_rows(page_state["result"]["targets"], empty_message="No targets.")
|
|
98
|
+
else:
|
|
99
|
+
st.info("Run an update against one source or one group.")
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
if running_in_streamlit():
|
|
103
|
+
render_page()
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import streamlit as st
|
|
4
|
+
|
|
5
|
+
from agent_data_cli.dashboard.adapters.sub import list_subscriptions, remove_subscription
|
|
6
|
+
from agent_data_cli.dashboard.context import build_dashboard_context
|
|
7
|
+
from agent_data_cli.dashboard.state import get_page_state, invalidate_pages, save_page_result
|
|
8
|
+
from agent_data_cli.dashboard.widgets.common import render_exception, running_in_streamlit
|
|
9
|
+
from agent_data_cli.dashboard.widgets.forms import source_select
|
|
10
|
+
from agent_data_cli.dashboard.widgets.tables import render_rows
|
|
11
|
+
from agent_data_cli.utils.time import utc_now_iso
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def render_page() -> None:
|
|
15
|
+
ctx = build_dashboard_context()
|
|
16
|
+
st.title("Subscriptions")
|
|
17
|
+
selected_source = st.checkbox("Filter by source", key="sub_filter_enabled")
|
|
18
|
+
source_name = source_select(ctx.registry, key="sub_source") if selected_source else None
|
|
19
|
+
page_state = get_page_state(st.session_state, "sub_page_state")
|
|
20
|
+
|
|
21
|
+
if st.button("Refresh Subscriptions", key="sub_refresh"):
|
|
22
|
+
rows = list_subscriptions(ctx.store, source_name=source_name)
|
|
23
|
+
save_page_result(
|
|
24
|
+
st.session_state,
|
|
25
|
+
"sub_page_state",
|
|
26
|
+
inputs={"source": source_name},
|
|
27
|
+
result={"rows": rows},
|
|
28
|
+
updated_at=utc_now_iso(),
|
|
29
|
+
)
|
|
30
|
+
page_state = get_page_state(st.session_state, "sub_page_state")
|
|
31
|
+
|
|
32
|
+
render_rows(None if page_state["result"] is None else page_state["result"]["rows"], empty_message="No subscriptions yet.")
|
|
33
|
+
|
|
34
|
+
channel_key = st.text_input("Channel To Remove", key="sub_remove_channel")
|
|
35
|
+
if st.button("Remove Subscription", key="sub_remove") and source_name is not None and channel_key:
|
|
36
|
+
try:
|
|
37
|
+
rows = remove_subscription(ctx.registry, source_name, channel_key)
|
|
38
|
+
save_page_result(
|
|
39
|
+
st.session_state,
|
|
40
|
+
"sub_page_state",
|
|
41
|
+
inputs={"source": source_name},
|
|
42
|
+
result={"rows": rows},
|
|
43
|
+
updated_at=utc_now_iso(),
|
|
44
|
+
)
|
|
45
|
+
invalidate_pages(st.session_state, "channel_page_state", "content_update_page_state")
|
|
46
|
+
except Exception as exc: # noqa: BLE001
|
|
47
|
+
render_exception(exc)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
if running_in_streamlit():
|
|
51
|
+
render_page()
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import streamlit as st
|
|
4
|
+
|
|
5
|
+
from agent_data_cli.dashboard.adapters.group import (
|
|
6
|
+
add_channel_to_group,
|
|
7
|
+
add_source_to_group,
|
|
8
|
+
create_group,
|
|
9
|
+
delete_group,
|
|
10
|
+
list_group_members,
|
|
11
|
+
list_groups,
|
|
12
|
+
remove_channel_from_group,
|
|
13
|
+
remove_source_from_group,
|
|
14
|
+
)
|
|
15
|
+
from agent_data_cli.dashboard.context import build_dashboard_context
|
|
16
|
+
from agent_data_cli.dashboard.state import get_page_state, invalidate_pages, save_page_result
|
|
17
|
+
from agent_data_cli.dashboard.widgets.common import render_exception, running_in_streamlit
|
|
18
|
+
from agent_data_cli.dashboard.widgets.forms import optional_group_select, source_select
|
|
19
|
+
from agent_data_cli.dashboard.widgets.tables import render_rows
|
|
20
|
+
from agent_data_cli.utils.time import utc_now_iso
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def render_page() -> None:
|
|
24
|
+
ctx = build_dashboard_context()
|
|
25
|
+
st.title("Group")
|
|
26
|
+
page_state = get_page_state(st.session_state, "group_page_state")
|
|
27
|
+
|
|
28
|
+
if st.button("Refresh Groups", key="group_refresh"):
|
|
29
|
+
rows = list_groups(ctx.store)
|
|
30
|
+
save_page_result(st.session_state, "group_page_state", inputs={}, result={"rows": rows}, updated_at=utc_now_iso())
|
|
31
|
+
page_state = get_page_state(st.session_state, "group_page_state")
|
|
32
|
+
|
|
33
|
+
render_rows(None if page_state["result"] is None else page_state["result"]["rows"], empty_message="No groups yet.")
|
|
34
|
+
|
|
35
|
+
input_row1 = st.columns(2)
|
|
36
|
+
with input_row1[0]:
|
|
37
|
+
group_name = st.text_input("Group Name", key="group_name")
|
|
38
|
+
with input_row1[1]:
|
|
39
|
+
selected_group = optional_group_select(ctx.store, key="group_selected")
|
|
40
|
+
input_row2 = st.columns(2)
|
|
41
|
+
with input_row2[0]:
|
|
42
|
+
source_name = source_select(ctx.registry, key="group_source")
|
|
43
|
+
with input_row2[1]:
|
|
44
|
+
channel_key = st.text_input("Channel", key="group_channel")
|
|
45
|
+
|
|
46
|
+
row1 = st.columns(2)
|
|
47
|
+
with row1[0]:
|
|
48
|
+
if st.button("Create Group", key="group_create") and group_name:
|
|
49
|
+
try:
|
|
50
|
+
rows = create_group(ctx.store, group_name)
|
|
51
|
+
save_page_result(
|
|
52
|
+
st.session_state,
|
|
53
|
+
"group_page_state",
|
|
54
|
+
inputs={},
|
|
55
|
+
result={"rows": rows},
|
|
56
|
+
updated_at=utc_now_iso(),
|
|
57
|
+
)
|
|
58
|
+
invalidate_pages(st.session_state, "content_update_page_state", "content_query_page_state")
|
|
59
|
+
except Exception as exc: # noqa: BLE001
|
|
60
|
+
render_exception(exc)
|
|
61
|
+
with row1[1]:
|
|
62
|
+
if st.button("Delete Group", key="group_delete") and selected_group:
|
|
63
|
+
try:
|
|
64
|
+
rows = delete_group(ctx.store, selected_group)
|
|
65
|
+
save_page_result(
|
|
66
|
+
st.session_state,
|
|
67
|
+
"group_page_state",
|
|
68
|
+
inputs={},
|
|
69
|
+
result={"rows": rows},
|
|
70
|
+
updated_at=utc_now_iso(),
|
|
71
|
+
)
|
|
72
|
+
invalidate_pages(st.session_state, "content_update_page_state", "content_query_page_state")
|
|
73
|
+
except Exception as exc: # noqa: BLE001
|
|
74
|
+
render_exception(exc)
|
|
75
|
+
|
|
76
|
+
row2 = st.columns(2)
|
|
77
|
+
with row2[0]:
|
|
78
|
+
if st.button("Show Members", key="group_members_show") and selected_group:
|
|
79
|
+
try:
|
|
80
|
+
st.write(list_group_members(ctx.store, selected_group))
|
|
81
|
+
except Exception as exc: # noqa: BLE001
|
|
82
|
+
render_exception(exc)
|
|
83
|
+
with row2[1]:
|
|
84
|
+
if st.button("Add Source", key="group_add_source") and selected_group and source_name:
|
|
85
|
+
try:
|
|
86
|
+
st.write(add_source_to_group(ctx.store, selected_group, source_name))
|
|
87
|
+
invalidate_pages(st.session_state, "content_update_page_state", "content_query_page_state")
|
|
88
|
+
except Exception as exc: # noqa: BLE001
|
|
89
|
+
render_exception(exc)
|
|
90
|
+
|
|
91
|
+
row3 = st.columns(2)
|
|
92
|
+
with row3[0]:
|
|
93
|
+
if st.button("Add Channel", key="group_add_channel") and selected_group and source_name and channel_key:
|
|
94
|
+
try:
|
|
95
|
+
st.write(add_channel_to_group(ctx.store, selected_group, source_name, channel_key))
|
|
96
|
+
invalidate_pages(st.session_state, "content_update_page_state", "content_query_page_state")
|
|
97
|
+
except Exception as exc: # noqa: BLE001
|
|
98
|
+
render_exception(exc)
|
|
99
|
+
with row3[1]:
|
|
100
|
+
if st.button("Remove Source", key="group_remove_source") and selected_group and source_name:
|
|
101
|
+
try:
|
|
102
|
+
st.write(remove_source_from_group(ctx.store, selected_group, source_name))
|
|
103
|
+
invalidate_pages(st.session_state, "content_update_page_state", "content_query_page_state")
|
|
104
|
+
except Exception as exc: # noqa: BLE001
|
|
105
|
+
render_exception(exc)
|
|
106
|
+
|
|
107
|
+
if st.button("Remove Channel", key="group_remove_channel") and selected_group and source_name and channel_key:
|
|
108
|
+
try:
|
|
109
|
+
st.write(remove_channel_from_group(ctx.store, selected_group, source_name, channel_key))
|
|
110
|
+
invalidate_pages(st.session_state, "content_update_page_state", "content_query_page_state")
|
|
111
|
+
except Exception as exc: # noqa: BLE001
|
|
112
|
+
render_exception(exc)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
if running_in_streamlit():
|
|
116
|
+
render_page()
|