+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('Loading...') }}
+
+
+
+
+
+
+ {{ kpi.value }}
+
+
+ {{ $t(kpi.label) }}
+
+
+
+
+
+ {{ $t('Guardrails') }}
+
+
+
+
+
+ {{ $t('Guardrail outcomes') }}
+
+
+
+
+
+ {{ $t(emptyGuardrails) }}
+
+
+
+
+
+ {{ $t('Block rate by FlowGenie') }}
+
+
+
+
+
+ {{ $t(emptyBlocks) }}
+
+
+
+
+
+
+
+ {{ $t('Violations by kind') }}
+
+
+
+
+
+ {{ $t('No violations in this period.') }}
+
+
+
+
+
+ {{ $t('Where it fired') }}
+
+
+
+
+
+ {{ $t(emptyGuardrails) }}
+
+
+
+
+
+
+ {{ $t('Blocked vs redacted sessions') }}
+
+
+
+
+
+
+
+ {{ $t('Usage') }}
+
+
+
+
+
+ {{ $t('Tokens in vs out') }}
+
+
+
+
+
+ {{ $t(emptyTokens) }}
+
+
+
+
+
+ {{ $t('Tokens by FlowGenie') }}
+
+
+
+
+
+ {{ $t(emptyTokens) }}
+
+
+
+
+
+
+
+ {{ $t('Sessions per day') }}
+
+
+
+
+
+
+
+
+ {{ $t('Session status') }}
+
+
+
+
+
+ {{ $t('No sessions in this period.') }}
+
+
+
+
+
+
+ {{ $t('Top users by blocks') }}
+
+
+
+
+
+ | {{ $t('User') }} |
+ {{ $t('FlowGenie') }} |
+ {{ $t('Sessions') }} |
+ {{ $t('Blocks') }} |
+ {{ $t('Block rate') }} |
+
+
+
+
+ | {{ row.user }} |
+ {{ row.genie }} |
+ {{ row.sessions }} |
+ {{ row.blocks }} |
+ {{ formatRate(row.block_rate) }} |
+
+
+
+
+ {{ $t(emptyBlocks) }}
+
+
+
+
+
+
+
+
+
+
diff --git a/resources/js/admin/logs/components/Logs/Monitoring/index.js b/resources/js/admin/logs/components/Logs/Monitoring/index.js
new file mode 100644
index 0000000000..baa481f302
--- /dev/null
+++ b/resources/js/admin/logs/components/Logs/Monitoring/index.js
@@ -0,0 +1,2 @@
+// eslint-disable-next-line import/prefer-default-export
+export { default as MonitoringDashboard } from './MonitoringDashboard.vue';
diff --git a/resources/js/admin/logs/components/Logs/Sidebar/Sidebar.vue b/resources/js/admin/logs/components/Logs/Sidebar/Sidebar.vue
index a2276bbff7..6d947d71ca 100644
--- a/resources/js/admin/logs/components/Logs/Sidebar/Sidebar.vue
+++ b/resources/js/admin/logs/components/Logs/Sidebar/Sidebar.vue
@@ -104,7 +104,7 @@
:visible="isAgentsActive"
>
- FlowGenie Agents logs
+ {{ $t('Monitoring') }}
+
+
+ {{ $t('FlowGenie Agents logs') }}
@@ -153,13 +170,25 @@ export default {
isAgentsActive() {
return this.$route.path.startsWith("/agents");
},
+ isAgentsLogsActive() {
+ return this.$route.path === '/agents/design' || this.$route.path === '/agents/execution';
+ },
+ isMonitoringActive() {
+ return this.$route.path.startsWith('/agents/monitoring');
+ },
emailLinkClasses() {
- return this.isEmailActive
- ? "tw-bg-blue-50 tw-font-semibold tw-text-blue-500"
- : "tw-font-medium tw-text-zinc-700 hover:tw-bg-zinc-50";
+ return this.linkClasses(this.isEmailActive);
+ },
+ agentsLogsLinkClasses() {
+ return this.linkClasses(this.isAgentsLogsActive);
},
- agentsLinkClasses() {
- return this.isAgentsActive
+ monitoringLinkClasses() {
+ return this.linkClasses(this.isMonitoringActive);
+ },
+ },
+ methods: {
+ linkClasses(isActive) {
+ return isActive
? "tw-bg-blue-50 tw-font-semibold tw-text-blue-500"
: "tw-font-medium tw-text-zinc-700 hover:tw-bg-zinc-50";
},
diff --git a/resources/js/admin/logs/components/Logs/charts/BarChart.vue b/resources/js/admin/logs/components/Logs/charts/BarChart.vue
new file mode 100644
index 0000000000..fd46f8cb06
--- /dev/null
+++ b/resources/js/admin/logs/components/Logs/charts/BarChart.vue
@@ -0,0 +1,38 @@
+
diff --git a/resources/js/admin/logs/components/Logs/charts/ChartFrame.vue b/resources/js/admin/logs/components/Logs/charts/ChartFrame.vue
new file mode 100644
index 0000000000..e010c4054f
--- /dev/null
+++ b/resources/js/admin/logs/components/Logs/charts/ChartFrame.vue
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/resources/js/admin/logs/components/Logs/charts/DoughnutChart.vue b/resources/js/admin/logs/components/Logs/charts/DoughnutChart.vue
new file mode 100644
index 0000000000..5691a36bbd
--- /dev/null
+++ b/resources/js/admin/logs/components/Logs/charts/DoughnutChart.vue
@@ -0,0 +1,38 @@
+
diff --git a/resources/js/admin/logs/components/Logs/charts/HorizontalBarChart.vue b/resources/js/admin/logs/components/Logs/charts/HorizontalBarChart.vue
new file mode 100644
index 0000000000..5ddcfa75b7
--- /dev/null
+++ b/resources/js/admin/logs/components/Logs/charts/HorizontalBarChart.vue
@@ -0,0 +1,38 @@
+
diff --git a/resources/js/admin/logs/components/Logs/charts/LineChart.vue b/resources/js/admin/logs/components/Logs/charts/LineChart.vue
new file mode 100644
index 0000000000..fa8a6674e9
--- /dev/null
+++ b/resources/js/admin/logs/components/Logs/charts/LineChart.vue
@@ -0,0 +1,38 @@
+
diff --git a/resources/js/admin/logs/components/Logs/charts/chartTheme.js b/resources/js/admin/logs/components/Logs/charts/chartTheme.js
new file mode 100644
index 0000000000..8ad3a3fa92
--- /dev/null
+++ b/resources/js/admin/logs/components/Logs/charts/chartTheme.js
@@ -0,0 +1,93 @@
+export const CHART_COLORS = {
+ pass: '#0CA442',
+ redact: '#EC8E00',
+ block: '#EC5962',
+ info: '#2773F3',
+ muted: '#728092',
+ completed: '#0CA442',
+ error: '#EC5962',
+};
+
+export const doughnutOptions = {
+ legend: {
+ display: true,
+ position: 'bottom',
+ },
+ maintainAspectRatio: false,
+ responsive: true,
+ cutoutPercentage: 60,
+ layout: {
+ padding: 4,
+ },
+};
+
+export const horizontalBarOptions = (valueSuffix = '') => ({
+ legend: {
+ display: false,
+ },
+ maintainAspectRatio: false,
+ responsive: true,
+ layout: {
+ padding: {
+ right: 12,
+ },
+ },
+ scales: {
+ xAxes: [{
+ ticks: {
+ beginAtZero: true,
+ callback: (value) => `${value}${valueSuffix}`,
+ },
+ }],
+ yAxes: [{
+ gridLines: {
+ display: false,
+ },
+ afterFit: (scale) => {
+ scale.width = Math.min(scale.width, 140);
+ },
+ }],
+ },
+});
+
+export const stackedBarOptions = {
+ legend: {
+ display: true,
+ position: 'bottom',
+ },
+ maintainAspectRatio: false,
+ responsive: true,
+ layout: {
+ padding: 4,
+ },
+ scales: {
+ xAxes: [{ stacked: true }],
+ yAxes: [{
+ stacked: true,
+ ticks: { beginAtZero: true },
+ }],
+ },
+};
+
+export const lineOptions = {
+ legend: {
+ display: true,
+ position: 'bottom',
+ },
+ maintainAspectRatio: false,
+ responsive: true,
+ layout: {
+ padding: 4,
+ },
+ scales: {
+ yAxes: [{
+ ticks: { beginAtZero: true },
+ }],
+ },
+};
+
+export const chartBoxStyles = {
+ width: '100%',
+ height: '220px',
+ position: 'relative',
+};
diff --git a/resources/js/admin/logs/components/Logs/routes.js b/resources/js/admin/logs/components/Logs/routes.js
index 398d462193..85443ea7d3 100644
--- a/resources/js/admin/logs/components/Logs/routes.js
+++ b/resources/js/admin/logs/components/Logs/routes.js
@@ -1,4 +1,5 @@
import { LogTable } from "./LogTable";
+import { MonitoringDashboard } from "./Monitoring";
export default {};
@@ -70,6 +71,18 @@ export const routes = [
path: "/agents",
redirect: "/agents/design",
},
+ {
+ name: "logs.agents.monitoring",
+ path: "/agents/monitoring",
+ component: MonitoringDashboard,
+ beforeEnter: (to, from, next) => {
+ if (!hasAiPackage()) {
+ next(hasEmailPackage() ? "/email/errors" : "/");
+ } else {
+ next();
+ }
+ },
+ },
{
name: "logs.agents",
path: "/agents/:logType",