diff --git a/Dockerfile b/Dockerfile index d5fc71b..5a9660e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,10 +21,6 @@ RUN npm ci COPY . . -# Build for OSS edition by default, can be overridden with build args -ARG NEXT_PUBLIC_OPSORCH_EDITION=oss -ENV NEXT_PUBLIC_OPSORCH_EDITION=${NEXT_PUBLIC_OPSORCH_EDITION} - # Build the application RUN npm run build @@ -59,4 +55,4 @@ ENV PORT=3000 ENV HOSTNAME="0.0.0.0" # Start the application -CMD ["node", "server.js"] \ No newline at end of file +CMD ["node", "server.js"] diff --git a/LICENSE-ENTERPRISE b/LICENSE-ENTERPRISE deleted file mode 100644 index 272c006..0000000 --- a/LICENSE-ENTERPRISE +++ /dev/null @@ -1,109 +0,0 @@ - OpsOrch Commercial License - Version 1.0, 2025 - https://opsorch.com/license - - TERMS AND CONDITIONS FOR USE OF OPSORCH ENTERPRISE SOFTWARE - - 1. Applicability. - - This License applies solely to the files located in any directory named - "(enterprise)" within the OpsOrch source trees, including all - subdirectories and files contained therein. - - These files are referred to in this document as the "Enterprise Software." - - 'You' Definition. - "You" means the individual or legal entity that has obtained access to - the Enterprise Software under a valid OpsOrch Enterprise License Agreement. - - The Enterprise Software is proprietary, confidential, and not licensed - under the Apache License 2.0 or any other open-source license. All other - components of the OpsOrch Console not explicitly identified as - Enterprise Software remain governed by their respective open-source - licenses. - - No portion of the Enterprise Software is licensed under the Apache - License 2.0 or any other open-source license, and no open-source license - terms apply to it. - - 2. License Grant. - - Subject to a valid and current OpsOrch Enterprise License Agreement - between You and OpsOrch, OpsOrch hereby grants You a limited, revocable, - non-exclusive, non-transferable right to install, use, and modify the - Enterprise Software solely for internal business operations within Your - organization. No rights are granted for any use beyond this scope. - - Access to source code in a repository does not by itself grant any - license rights. Rights are granted solely through an active OpsOrch - Enterprise License Agreement. - - 3. Restrictions. - - You may not reproduce, distribute, publish, sublicense, sell, lease, - rent, loan, or otherwise transfer the Enterprise Software to any third - party. You may not provide the Enterprise Software as part of a hosted, - managed, or commercial service. You may not remove or alter any - proprietary notices or designations. You may not extract, copy, or adapt - enterprise-only features for inclusion in derivative products or - distribute derivative works that incorporate any portion of the - Enterprise Software. - - Any modifications You make to the Enterprise Software must remain - internal to Your organization and may not be distributed or made - available to any third party. - - Any attempt to circumvent the separation between open-source and - enterprise-only components, including combining or linking the - Enterprise Software with open-source components in a manner intended to - evade the restrictions of this License, is strictly prohibited. - - 4. Ownership. - - OpsOrch retains all right, title, and interest in and to the Enterprise - Software, including all copyrights, trade secrets, and other - intellectual property rights. No ownership of the Enterprise Software is - transferred to You under this License. - - 5. Warranty Disclaimer. - - THE ENTERPRISE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY - KIND, EXPRESS OR IMPLIED. OPSORCH DISCLAIMS ALL WARRANTIES, INCLUDING - BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS - FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. YOU ASSUME ALL RISKS - ASSOCIATED WITH THE USE OF THE ENTERPRISE SOFTWARE. - - 6. Limitation of Liability. - - IN NO EVENT SHALL OPSORCH BE LIABLE FOR ANY INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OF ANY KIND ARISING OUT OF - OR RELATING TO THIS LICENSE OR THE USE OR INABILITY TO USE THE - ENTERPRISE SOFTWARE, EVEN IF OPSORCH HAS BEEN ADVISED OF THE POSSIBILITY - OF SUCH DAMAGES. - - 7. Termination. - - This License terminates automatically upon the expiration, suspension, - or termination of Your OpsOrch Enterprise License Agreement, or if You - breach any term of this License. Upon termination, You must immediately - cease use of the Enterprise Software and destroy all copies in Your - possession or control. - - 8. Governing Law. - - This License shall be governed by and interpreted in accordance with the - laws specified in the applicable OpsOrch Enterprise License Agreement. - If no such agreement specifies governing law, the laws of Ireland shall - apply. - - 9. Contact Information. - - For inquiries regarding licensing of the Enterprise Software, please - contact OpsOrch at: license@opsorch.com - - 10. No Trademark Rights. - - This License does not grant You any rights to use the OpsOrch name, - trademarks, or branding. - - END OF TERMS AND CONDITIONS diff --git a/README.md b/README.md index 48d3cb4..4919963 100644 --- a/README.md +++ b/README.md @@ -1,323 +1,50 @@ # OpsOrch Console -[![Version](https://img.shields.io/github/v/release/OpsOrch/opsorch-console)](https://github.com/OpsOrch/opsorch-console/releases) -[![License](https://img.shields.io/github/license/OpsOrch/opsorch-console)](https://github.com/OpsOrch/opsorch-console/blob/main/LICENSE) -[![CI](https://github.com/OpsOrch/opsorch-console/workflows/CI/badge.svg)](https://github.com/OpsOrch/opsorch-console/actions) +OpsOrch Console is the operator UI for OpsOrch. It provides incidents, alerts, logs, metrics, orchestration, services, tickets, teams, settings, and Copilot chat in a single open-source app. -OpsOrch Console is the operator-focused web UI for OpsOrch. It provides a unified interface for browsing and managing incidents, logs, metrics, services, tickets, and AI-powered chat assistance through OpsOrch Copilot. - -## Editions - -OpsOrch Console is available in two editions built from a single codebase: - -- **OSS Edition** - Open source features including incidents, logs, metrics, tickets, services, orchestration, and settings -- **Enterprise Edition** - All OSS features plus AI-powered Copilot assistance and chat history - -The edition is controlled at build time via the `OPSORCH_EDITION` environment variable. - -## Features - -- **Incidents**: Browse, search, and view incident details with timelines. Advanced filtering by query, status, severity, and scope -- **Alerts**: View and search alerts from monitoring providers. Filter by status, severity, service, and more -- **Logs**: Query and analyze logs across integrated providers with advanced search and filtering -- **Metrics**: Visualize and query metrics data with customizable expressions and aggregations -- **Services**: Explore service catalog and dependencies -- **Tickets**: View and manage tickets from integrated ticketing systems -- **Orchestration**: Browse workflow plans, launch runs, monitor run status, and complete manual steps with progress tracking -- **Chat**: AI-powered assistance via OpsOrch Copilot for incident investigation, log analysis, and operational queries. Copilot can generate smart references to filtered views with query parameters -- **Settings**: Configure OpsOrch Core and Copilot endpoints - -### Query Capabilities - -All primary data views (Incidents, Alerts, Logs, Metrics) support: -- **URL-based filtering**: Share filtered views via URL with query parameters -- **Advanced search**: Free-text search across titles and descriptions -- **Status/Severity filters**: Multi-select filtering with comma-separated values -- **Scope filtering**: Filter by service, environment, and team -- **Copilot integration**: AI can generate filtered views and include them as clickable references - -### Copilot Answer Actions - -Copilot responses can include recommended actions to trigger orchestration workflows: - -- `actions` entries use the `orchestration` type and may include `id`, `name`, and `reason` -- When an `id` is present, the UI links directly to `/orchestration/plans/{id}` -- When no `id` is provided, the UI routes operators to the orchestration plan browser - - -## Architecture - -The Console is a Next.js application that communicates with: -- **OpsOrch Core** (via HTTP) for operational data (incidents, logs, metrics, services, tickets) -- **OpsOrch Copilot** (via HTTP) for AI-powered chat assistance - -``` -OpsOrch Console (Next.js UI) - ↓ - ├─→ OpsOrch Core (operational data) - └─→ OpsOrch Copilot (AI chat) -``` - -## Getting Started - -### Prerequisites -- Node.js 20+ installed -- OpsOrch Core running (default: `http://localhost:8080`) -- OpsOrch Copilot running (optional, default: `http://localhost:6060`) - -### Installation +## Development ```bash npm install -``` - -### Development - -Run the development server: - -```bash -# OSS Edition (default) npm run dev -# or explicitly -npm run dev:oss - -# Enterprise Edition -npm run dev:enterprise ``` -Open [http://localhost:3000](http://localhost:3000) to access the console. - -### Environment Configuration - -The console can be configured via environment variables or through the Settings page in the UI. +Open `http://localhost:3000`. -**Edition Control:** -- `NEXT_PUBLIC_OPSORCH_EDITION` - Set to `oss` or `enterprise` (default: `oss`) +Default endpoints: +- Core: `http://localhost:8080` +- Copilot: `http://localhost:6060` -**Service Endpoints:** -- `NEXT_PUBLIC_OPSORCH_CORE_URL` - OpsOrch Core URL (default: `http://localhost:8080`) -- `NEXT_PUBLIC_COPILOT_URL` - OpsOrch Copilot URL (default: `http://localhost:6060`) +Useful env vars: +- `NEXT_PUBLIC_OPSORCH_CORE_URL` +- `NEXT_PUBLIC_COPILOT_URL` -**Runtime Configuration:** -- Navigate to Settings (`/settings`) in the UI to configure endpoints without restarting - -### Production Build - -Build the production bundle: +## Build ```bash -# OSS Edition (default) npm run build -# or explicitly -npm run build:oss - -# Enterprise Edition -npm run build:enterprise - -# Start the server npm start ``` -### Testing - -Run the test suite: +## Test ```bash npm test ``` -### Docker - -Docker images are automatically built and published to GitHub Container Registry with each release. Both OSS and Enterprise editions are available as separate Docker images. - -#### OSS Edition - -```bash -# Pull the latest OSS version -docker pull ghcr.io/opsorch/opsorch-console:latest-oss - -# Run OSS edition with environment variables -docker run -d \ - --name opsorch-console-oss \ - -p 3000:3000 \ - -e NEXT_PUBLIC_OPSORCH_CORE_URL=http://localhost:8080 \ - -e NEXT_PUBLIC_OPSORCH_EDITION=oss \ - ghcr.io/opsorch/opsorch-console:latest-oss - -# Or run a specific OSS version -docker pull ghcr.io/opsorch/opsorch-console:v1.0.0-oss -``` - -#### Enterprise Edition +## Docker ```bash -# Pull the latest Enterprise version -docker pull ghcr.io/opsorch/opsorch-console:latest-enterprise +docker pull ghcr.io/opsorch/opsorch-console:latest -# Run Enterprise edition with environment variables docker run -d \ - --name opsorch-console-enterprise \ + --name opsorch-console \ -p 3000:3000 \ -e NEXT_PUBLIC_OPSORCH_CORE_URL=http://localhost:8080 \ -e NEXT_PUBLIC_COPILOT_URL=http://localhost:6060 \ - -e NEXT_PUBLIC_OPSORCH_EDITION=enterprise \ - ghcr.io/opsorch/opsorch-console:latest-enterprise - -# Or run a specific Enterprise version -docker pull ghcr.io/opsorch/opsorch-console:v1.0.0-enterprise -``` - -#### Docker Compose - -For easier deployment, you can use Docker Compose: - -```yaml -# docker-compose.yml -version: '3.8' -services: - opsorch-console-oss: - image: ghcr.io/opsorch/opsorch-console:latest-oss - ports: - - "3000:3000" - environment: - - NEXT_PUBLIC_OPSORCH_CORE_URL=http://localhost:8080 - - NEXT_PUBLIC_OPSORCH_EDITION=oss - restart: unless-stopped - - # Uncomment for Enterprise edition - # opsorch-console-enterprise: - # image: ghcr.io/opsorch/opsorch-console:latest-enterprise - # ports: - # - "3001:3000" - # environment: - # - NEXT_PUBLIC_OPSORCH_CORE_URL=http://localhost:8080 - # - NEXT_PUBLIC_COPILOT_URL=http://localhost:6060 - # - NEXT_PUBLIC_OPSORCH_EDITION=enterprise - # restart: unless-stopped -``` - -```bash -docker-compose up -d -``` - -**Available Docker tags:** -- `latest-oss` - Latest OSS Edition release -- `latest-enterprise` - Latest Enterprise Edition release -- `v{version}-oss` - Specific OSS version tags (e.g., `v1.0.0-oss`) -- `v{version}-enterprise` - Specific Enterprise version tags (e.g., `v1.0.0-enterprise`) - -The Docker images run as a non-root user and expose port 3000. Both editions support the same environment variables for configuration. - -## Project Structure - -- `app/` - Next.js app router pages and layouts - - `(oss)/` - OSS Edition routes (incidents, logs, metrics, tickets, services, orchestration, settings) - - `(enterprise)/` - Enterprise Edition routes (Copilot home, chat history) - - `components/` - Reusable React components - - `(enterprise)/` - Enterprise-only components (CopilotPanel, etc.) - - `api/` - API routes - - `(enterprise)/` - Enterprise-only API routes (Copilot APIs) - - `lib/` - Utility functions and API clients (shared between editions) - -**Note:** Directories with parentheses `(oss)` and `(enterprise)` are Next.js route groups that organize code without affecting URLs. - -## Licensing - -OpsOrch Console uses a dual-licensing model: - -### OSS Edition - Apache 2.0 License - -The OSS Edition and all shared components are licensed under the **Apache License 2.0**. See the [LICENSE](LICENSE) file for details. - -This includes: -- All code in `app/(oss)/` directory -- Shared components in `app/components/` (excluding `(enterprise)` subdirectory) -- Shared utilities in `app/lib/` -- Shared API routes in `app/api/` (excluding `(enterprise)` subdirectory) - -### Enterprise Edition - Commercial License - -The Enterprise Edition features are proprietary and licensed under the **OpsOrch Commercial License**. See the [LICENSE-ENTERPRISE](LICENSE-ENTERPRISE) file for details. - -This includes: -- All code in `app/(enterprise)/` directory -- Enterprise components in `app/components/(enterprise)/` -- Enterprise API routes in `app/api/(enterprise)/` - -**Enterprise features require a valid OpsOrch Enterprise License Agreement.** For licensing inquiries, contact: license@opsorch.com - -### Directory Structure and Licensing - -The codebase is organized to make licensing clear: - -``` -app/ -├── (oss)/ # Apache 2.0 - OSS routes -├── (enterprise)/ # Commercial - Enterprise routes -├── components/ -│ ├── (enterprise)/ # Commercial - Enterprise components -│ └── [shared components] # Apache 2.0 - Shared components -├── api/ -│ ├── (enterprise)/ # Commercial - Enterprise APIs -│ └── [shared APIs] # Apache 2.0 - Shared APIs -└── lib/ # Apache 2.0 - Shared utilities -``` - -Files in `(enterprise)` directories are proprietary and not included in open-source distributions. - -## Releases - -This project uses automated releases via GitHub Actions. Releases are triggered manually and include: - -- **Semantic versioning** with configurable version bumps (major, minor, patch) -- **Edition selection** (OSS, Enterprise, or both) -- **Automated testing** and linting before release -- **Git tagging** with proper version format (`v{major}.{minor}.{patch}`) -- **Changelog generation** from commit history -- **Docker image publishing** to GitHub Container Registry (separate images for OSS and Enterprise) -- **GitHub releases** with release notes - -### Creating a Release - -Maintainers can create a new release by: - -1. Go to the [Actions tab](https://github.com/OpsOrch/opsorch-console/actions) -2. Select the "Release" workflow -3. Click "Run workflow" -4. Choose the version bump type: - - **patch** - Bug fixes and minor updates (1.0.0 → 1.0.1) - - **minor** - New features, backward compatible (1.0.0 → 1.1.0) - - **major** - Breaking changes (1.0.0 → 2.0.0) -5. Choose the edition to build: - - **oss** - Build only OSS Edition Docker image - - **enterprise** - Build only Enterprise Edition Docker image - - **both** - Build both OSS and Enterprise Docker images -6. Click "Run workflow" - -The release process will automatically: -- Run all tests and linting -- Calculate the next version number -- Create and push a git tag -- Build and publish Docker images for selected editions and multiple architectures (linux/amd64, linux/arm64) -- Create a GitHub release with changelog - -### Installation Options - -**Docker (OSS Edition):** -```bash -docker pull ghcr.io/opsorch/opsorch-console:latest-oss + ghcr.io/opsorch/opsorch-console:latest ``` -**Docker (Enterprise Edition):** -```bash -docker pull ghcr.io/opsorch/opsorch-console:latest-enterprise -``` - -**GitHub Releases:** -Download release artifacts from the [Releases page](https://github.com/OpsOrch/opsorch-console/releases). - -## Learn More +## License -- [OpsOrch Core Documentation](../opsorch-core/README.md) -- [OpsOrch Copilot Documentation](../opsorch-copilot/README.md) -- [Next.js Documentation](https://nextjs.org/docs) +Apache-2.0. See [LICENSE](LICENSE). diff --git a/app/(oss)/alerts/[id]/page.tsx b/app/alerts/[id]/page.tsx similarity index 100% rename from app/(oss)/alerts/[id]/page.tsx rename to app/alerts/[id]/page.tsx diff --git a/app/(oss)/alerts/page.tsx b/app/alerts/page.tsx similarity index 100% rename from app/(oss)/alerts/page.tsx rename to app/alerts/page.tsx diff --git a/app/api/(enterprise)/copilot/chats/[chatId]/route.ts b/app/api/copilot/chats/[chatId]/route.ts similarity index 85% rename from app/api/(enterprise)/copilot/chats/[chatId]/route.ts rename to app/api/copilot/chats/[chatId]/route.ts index 9fce7c5..89d1b29 100644 --- a/app/api/(enterprise)/copilot/chats/[chatId]/route.ts +++ b/app/api/copilot/chats/[chatId]/route.ts @@ -1,6 +1,5 @@ import { NextRequest, NextResponse } from "next/server"; import { trimTrailingSlash } from "@/app/lib/api"; -import { isEnterprise } from "@/app/lib/edition"; const COPILOT_BASE_URL = trimTrailingSlash( process.env.OPS_ORCH_COPILOT_BASE_URL || @@ -15,13 +14,6 @@ export async function GET( request: NextRequest, { params }: { params: Promise<{ chatId: string }> } ) { - if (!isEnterprise()) { - return NextResponse.json( - { error: "Chat details are only available in Enterprise Edition" }, - { status: 404 } - ); - } - const { chatId } = await params; if (!chatId) { diff --git a/app/api/(enterprise)/copilot/chats/route.ts b/app/api/copilot/chats/route.ts similarity index 85% rename from app/api/(enterprise)/copilot/chats/route.ts rename to app/api/copilot/chats/route.ts index 6104ec3..13dac47 100644 --- a/app/api/(enterprise)/copilot/chats/route.ts +++ b/app/api/copilot/chats/route.ts @@ -1,6 +1,5 @@ import { NextResponse } from "next/server"; import { trimTrailingSlash } from "@/app/lib/api"; -import { isEnterprise } from "@/app/lib/edition"; const COPILOT_BASE_URL = trimTrailingSlash( process.env.OPS_ORCH_COPILOT_BASE_URL || @@ -12,13 +11,6 @@ const COPILOT_BASE_URL = trimTrailingSlash( ); export async function GET(request: Request) { - if (!isEnterprise()) { - return NextResponse.json( - { error: "Chat history is only available in Enterprise Edition" }, - { status: 404 } - ); - } - try { const { searchParams } = new URL(request.url); const queryString = searchParams.toString(); diff --git a/app/api/(enterprise)/copilot/chats/search/route.ts b/app/api/copilot/chats/search/route.ts similarity index 85% rename from app/api/(enterprise)/copilot/chats/search/route.ts rename to app/api/copilot/chats/search/route.ts index 30a3499..990f536 100644 --- a/app/api/(enterprise)/copilot/chats/search/route.ts +++ b/app/api/copilot/chats/search/route.ts @@ -1,6 +1,5 @@ import { NextResponse } from "next/server"; import { trimTrailingSlash } from "@/app/lib/api"; -import { isEnterprise } from "@/app/lib/edition"; const COPILOT_BASE_URL = trimTrailingSlash( process.env.OPS_ORCH_COPILOT_BASE_URL || @@ -12,13 +11,6 @@ const COPILOT_BASE_URL = trimTrailingSlash( ); export async function GET(request: Request) { - if (!isEnterprise()) { - return NextResponse.json( - { error: "Chat search is only available in Enterprise Edition" }, - { status: 404 } - ); - } - try { const { searchParams } = new URL(request.url); const queryString = searchParams.toString(); diff --git a/app/api/(enterprise)/copilot/route.ts b/app/api/copilot/route.ts similarity index 92% rename from app/api/(enterprise)/copilot/route.ts rename to app/api/copilot/route.ts index b1510f2..ad19139 100644 --- a/app/api/(enterprise)/copilot/route.ts +++ b/app/api/copilot/route.ts @@ -1,6 +1,5 @@ import { NextRequest, NextResponse } from "next/server"; import { trimTrailingSlash } from "@/app/lib/api"; -import { isEnterprise } from "@/app/lib/edition"; const COPILOT_BASE_URL = trimTrailingSlash( process.env.OPS_ORCH_COPILOT_BASE_URL || @@ -25,13 +24,6 @@ function propagateChatId(payload: unknown, fallback?: string) { } export async function POST(req: NextRequest) { - if (!isEnterprise()) { - return NextResponse.json( - { error: "Copilot is only available in Enterprise Edition" }, - { status: 404 } - ); - } - let body: { message?: string; chatId?: string }; try { body = (await req.json()) as { message?: string; chatId?: string }; diff --git a/app/(enterprise)/chats/[id]/page.tsx b/app/chats/[id]/page.tsx similarity index 64% rename from app/(enterprise)/chats/[id]/page.tsx rename to app/chats/[id]/page.tsx index f879e41..1d22dfd 100644 --- a/app/(enterprise)/chats/[id]/page.tsx +++ b/app/chats/[id]/page.tsx @@ -2,10 +2,8 @@ import { useParams } from "next/navigation"; import { AppShell } from "@/app/components/AppShell"; -import { CopilotPanel } from "@/app/components/(enterprise)/CopilotPanel"; +import { CopilotPanel } from "@/app/components/copilot/CopilotPanel"; import { useMemo } from "react"; -import { isEnterprise } from "@/app/lib/edition"; -import { EnterpriseOnly } from "@/app/components/EnterpriseOnly"; export default function ChatDetailPage() { const params = useParams<{ id?: string }>(); @@ -14,14 +12,6 @@ export default function ChatDetailPage() { return Array.isArray(raw) ? raw[0] : raw; }, [params]); - if (!isEnterprise()) { - return ( - - - - ); - } - return ( clearTimeout(timer); }, [searchQuery]); - if (!isEnterprise()) { - return ( - - - - ); - } - const handleClear = () => { setSearchQuery(""); setDebouncedQuery(""); diff --git a/app/components/AppShell.tsx b/app/components/AppShell.tsx index 92878a9..5909757 100644 --- a/app/components/AppShell.tsx +++ b/app/components/AppShell.tsx @@ -4,17 +4,9 @@ import Image from "next/image"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { ReactNode, useMemo } from "react"; -import { isEnterprise } from "@/app/lib/edition"; - -type NavItem = { - href: string; - label: string; - edition?: "enterprise" | "oss" | "both"; -}; - -const allNavItems: NavItem[] = [ - { href: "/", label: "Home" }, // Available in both editions - { href: "/chats", label: "Chats", edition: "enterprise" }, +const navItems = [ + { href: "/", label: "Home" }, + { href: "/chats", label: "Chats" }, { href: "/incidents", label: "Incidents" }, { href: "/alerts", label: "Alerts" }, { href: "/logs", label: "Logs" }, @@ -27,14 +19,6 @@ const allNavItems: NavItem[] = [ { href: "/settings", label: "Settings" }, ]; -// Filter navigation items based on edition -const navItems = allNavItems.filter((item) => { - if (!item.edition || item.edition === "both") return true; - if (item.edition === "enterprise") return isEnterprise(); - if (item.edition === "oss") return !isEnterprise(); - return true; -}); - export function AppShell({ title, description, diff --git a/app/components/EnterpriseOnly.tsx b/app/components/EnterpriseOnly.tsx deleted file mode 100644 index 7f03736..0000000 --- a/app/components/EnterpriseOnly.tsx +++ /dev/null @@ -1,10 +0,0 @@ -export function EnterpriseOnly({ featureName }: { featureName?: string }) { - return ( -
-

Enterprise Edition Only

-

- {featureName ? `${featureName} is` : "This feature is"} available in the OpsOrch Enterprise Edition. -

-
- ); -} diff --git a/app/components/(enterprise)/copilot/ActionLinks.tsx b/app/components/copilot/ActionLinks.tsx similarity index 100% rename from app/components/(enterprise)/copilot/ActionLinks.tsx rename to app/components/copilot/ActionLinks.tsx diff --git a/app/components/(enterprise)/copilot/ChatHistory.tsx b/app/components/copilot/ChatHistory.tsx similarity index 100% rename from app/components/(enterprise)/copilot/ChatHistory.tsx rename to app/components/copilot/ChatHistory.tsx diff --git a/app/components/(enterprise)/copilot/CollapsibleCodeBlock.tsx b/app/components/copilot/CollapsibleCodeBlock.tsx similarity index 100% rename from app/components/(enterprise)/copilot/CollapsibleCodeBlock.tsx rename to app/components/copilot/CollapsibleCodeBlock.tsx diff --git a/app/components/(enterprise)/copilot/ConfidenceBar.tsx b/app/components/copilot/ConfidenceBar.tsx similarity index 100% rename from app/components/(enterprise)/copilot/ConfidenceBar.tsx rename to app/components/copilot/ConfidenceBar.tsx diff --git a/app/components/(enterprise)/copilot/CopilotConclusion.tsx b/app/components/copilot/CopilotConclusion.tsx similarity index 100% rename from app/components/(enterprise)/copilot/CopilotConclusion.tsx rename to app/components/copilot/CopilotConclusion.tsx diff --git a/app/components/(enterprise)/CopilotPanel.tsx b/app/components/copilot/CopilotPanel.tsx similarity index 98% rename from app/components/(enterprise)/CopilotPanel.tsx rename to app/components/copilot/CopilotPanel.tsx index 26e3df7..e9a0f5c 100644 --- a/app/components/(enterprise)/CopilotPanel.tsx +++ b/app/components/copilot/CopilotPanel.tsx @@ -4,9 +4,9 @@ import { useEffect, useMemo, useRef, useState } from "react"; import { CopilotAnswer, CopilotReferences, TurnExecutionTrace } from "@/app/lib/types"; import { useAsyncState } from "@/app/lib/hooks"; import { Field, Pill, Section, TextArea } from "@/app/lib/ui"; -import { ConfidenceBar } from "@/app/components/(enterprise)/copilot/ConfidenceBar"; -import { CopilotConclusion } from "@/app/components/(enterprise)/copilot/CopilotConclusion"; -import { ResponseDetailsContent } from "@/app/components/(enterprise)/copilot/ResponseDetails"; +import { ConfidenceBar } from "@/app/components/copilot/ConfidenceBar"; +import { CopilotConclusion } from "@/app/components/copilot/CopilotConclusion"; +import { ResponseDetailsContent } from "@/app/components/copilot/ResponseDetails"; import { parseJsonString, stringifyData } from "@/app/lib/utils"; type CopilotTurn = { diff --git a/app/components/(enterprise)/copilot/ReferenceLinks.tsx b/app/components/copilot/ReferenceLinks.tsx similarity index 100% rename from app/components/(enterprise)/copilot/ReferenceLinks.tsx rename to app/components/copilot/ReferenceLinks.tsx diff --git a/app/components/(enterprise)/copilot/ResponseDetails.tsx b/app/components/copilot/ResponseDetails.tsx similarity index 100% rename from app/components/(enterprise)/copilot/ResponseDetails.tsx rename to app/components/copilot/ResponseDetails.tsx diff --git a/app/components/(enterprise)/copilot/ToolExecutionsView.tsx b/app/components/copilot/ToolExecutionsView.tsx similarity index 100% rename from app/components/(enterprise)/copilot/ToolExecutionsView.tsx rename to app/components/copilot/ToolExecutionsView.tsx diff --git a/app/(oss)/deployments/[id]/page.tsx b/app/deployments/[id]/page.tsx similarity index 100% rename from app/(oss)/deployments/[id]/page.tsx rename to app/deployments/[id]/page.tsx diff --git a/app/(oss)/deployments/page.tsx b/app/deployments/page.tsx similarity index 100% rename from app/(oss)/deployments/page.tsx rename to app/deployments/page.tsx diff --git a/app/(oss)/incidents/[id]/page.tsx b/app/incidents/[id]/page.tsx similarity index 100% rename from app/(oss)/incidents/[id]/page.tsx rename to app/incidents/[id]/page.tsx diff --git a/app/(oss)/incidents/page.tsx b/app/incidents/page.tsx similarity index 100% rename from app/(oss)/incidents/page.tsx rename to app/incidents/page.tsx diff --git a/app/layout.tsx b/app/layout.tsx index 78769ed..c2424af 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,17 +1,8 @@ import type { Metadata } from "next"; -import { Geist, Geist_Mono } from "next/font/google"; +import { GeistMono } from "geist/font/mono"; +import { GeistSans } from "geist/font/sans"; import "./globals.css"; -const geistSans = Geist({ - variable: "--font-geist-sans", - subsets: ["latin"], -}); - -const geistMono = Geist_Mono({ - variable: "--font-geist-mono", - subsets: ["latin"], -}); - export const metadata: Metadata = { title: "OpsOrch Console", description: "Unified console for OpsOrch capabilities", @@ -25,7 +16,7 @@ export default function RootLayout({ return ( {children} diff --git a/app/lib/edition.ts b/app/lib/edition.ts deleted file mode 100644 index b77ce7d..0000000 --- a/app/lib/edition.ts +++ /dev/null @@ -1,15 +0,0 @@ -// Read from both server and client environment variables -// NEXT_PUBLIC_ prefix makes it available on the client side -export const EDITION = ( - process.env.NEXT_PUBLIC_OPSORCH_EDITION?.trim() || - process.env.OPSORCH_EDITION?.trim() || - "oss" -); - -export function isEnterprise() { - return EDITION === "enterprise"; -} - -export function isOSS() { - return EDITION !== "enterprise"; -} diff --git a/app/(oss)/logs/page.tsx b/app/logs/page.tsx similarity index 100% rename from app/(oss)/logs/page.tsx rename to app/logs/page.tsx diff --git a/app/(oss)/metrics/page.tsx b/app/metrics/page.tsx similarity index 100% rename from app/(oss)/metrics/page.tsx rename to app/metrics/page.tsx diff --git a/app/(oss)/orchestration/page.tsx b/app/orchestration/page.tsx similarity index 100% rename from app/(oss)/orchestration/page.tsx rename to app/orchestration/page.tsx diff --git a/app/(oss)/orchestration/plans/[planId]/page.tsx b/app/orchestration/plans/[planId]/page.tsx similarity index 100% rename from app/(oss)/orchestration/plans/[planId]/page.tsx rename to app/orchestration/plans/[planId]/page.tsx diff --git a/app/(oss)/orchestration/plans/page.tsx b/app/orchestration/plans/page.tsx similarity index 100% rename from app/(oss)/orchestration/plans/page.tsx rename to app/orchestration/plans/page.tsx diff --git a/app/(oss)/orchestration/runs/[runId]/page.tsx b/app/orchestration/runs/[runId]/page.tsx similarity index 100% rename from app/(oss)/orchestration/runs/[runId]/page.tsx rename to app/orchestration/runs/[runId]/page.tsx diff --git a/app/(oss)/orchestration/runs/page.tsx b/app/orchestration/runs/page.tsx similarity index 100% rename from app/(oss)/orchestration/runs/page.tsx rename to app/orchestration/runs/page.tsx diff --git a/app/page.tsx b/app/page.tsx index d3981b0..9d8a67f 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -2,18 +2,8 @@ import Image from "next/image"; import { useMemo } from "react"; -import Link from "next/link"; import { AppShell } from "@/app/components/AppShell"; -import { isEnterprise } from "@/app/lib/edition"; -import { EnterpriseOnly } from "@/app/components/EnterpriseOnly"; - -// Dynamic import for enterprise features -// eslint-disable-next-line @typescript-eslint/no-explicit-any -let CopilotPanel: any = null; -if (isEnterprise()) { - // eslint-disable-next-line @typescript-eslint/no-require-imports - CopilotPanel = require("@/app/components/(enterprise)/CopilotPanel").CopilotPanel; -} +import { CopilotPanel } from "@/app/components/copilot/CopilotPanel"; export default function Home() { const hero = useMemo( @@ -26,194 +16,14 @@ export default function Home() { [], ); - // Enterprise edition: Show Copilot - if (isEnterprise()) { - return ( - -
- {CopilotPanel ? ( - - ) : ( - - )} -
-
- ); - } - - // OSS edition: Show welcome page with quick links return (
- {/* Welcome Section */} -
-

Welcome to OpsOrch

-

- Access and manage your operational data from a single unified interface. - Navigate through alerts, deployments, incidents, logs, metrics, orchestration, services, teams, and tickets to monitor and maintain your systems. -

-
- - {/* Quick Links */} -
- -
-
- - - -
-

Alerts

-
-

Manage system alerts and notifications

- - - -
-
- - - -
-

Deployments

-
-

Track and manage deployments

- - - -
-
- - - -
-

Orchestration

-
-

Manage workflows and automation

- - - -
-
- - - -
-

Teams

-
-

Manage teams and members

- - - -
-
- - - -
-

Incidents

-
-

View and manage active incidents

- - - -
-
- - - -
-

Logs

-
-

Search and analyze system logs

- - - -
-
- - - -
-

Metrics

-
-

Monitor system performance metrics

- - - -
-
- - - -
-

Tickets

-
-

Track and manage support tickets

- - - -
-
- - - -
-

Services

-
-

View service status and health

- - - -
-
- - - - -
-

Settings

-
-

Configure console preferences

- -
+
); diff --git a/app/(oss)/services/[id]/page.tsx b/app/services/[id]/page.tsx similarity index 100% rename from app/(oss)/services/[id]/page.tsx rename to app/services/[id]/page.tsx diff --git a/app/(oss)/services/page.tsx b/app/services/page.tsx similarity index 100% rename from app/(oss)/services/page.tsx rename to app/services/page.tsx diff --git a/app/(oss)/settings/page.tsx b/app/settings/page.tsx similarity index 100% rename from app/(oss)/settings/page.tsx rename to app/settings/page.tsx diff --git a/app/(oss)/teams/[id]/page.tsx b/app/teams/[id]/page.tsx similarity index 100% rename from app/(oss)/teams/[id]/page.tsx rename to app/teams/[id]/page.tsx diff --git a/app/(oss)/teams/page.tsx b/app/teams/page.tsx similarity index 100% rename from app/(oss)/teams/page.tsx rename to app/teams/page.tsx diff --git a/app/(oss)/tickets/[id]/page.tsx b/app/tickets/[id]/page.tsx similarity index 100% rename from app/(oss)/tickets/[id]/page.tsx rename to app/tickets/[id]/page.tsx diff --git a/app/(oss)/tickets/page.tsx b/app/tickets/page.tsx similarity index 100% rename from app/(oss)/tickets/page.tsx rename to app/tickets/page.tsx diff --git a/package-lock.json b/package-lock.json index 69e738a..22ea2cf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,21 +7,22 @@ "": { "name": "opsorch-console", "version": "0.1.0", - "license": "SEE LICENSE IN LICENSE", + "license": "Apache-2.0", "dependencies": { "@tanstack/react-query": "^5.90.10", - "@xyflow/react": "^12.10.0", - "next": "16.0.3", - "react": "19.2.0", - "react-dom": "19.2.0" + "geist": "^1.7.0", + "next": "^16.1.6", + "react": "^19.2.4", + "react-dom": "^19.2.4" }, "devDependencies": { "@tailwindcss/postcss": "^4", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", + "baseline-browser-mapping": "^2.10.8", "eslint": "^9", - "eslint-config-next": "16.0.3", + "eslint-config-next": "^16.1.6", "tailwindcss": "^4", "typescript": "^5" } @@ -1038,15 +1039,15 @@ } }, "node_modules/@next/env": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/@next/env/-/env-16.0.3.tgz", - "integrity": "sha512-IqgtY5Vwsm14mm/nmQaRMmywCU+yyMIYfk3/MHZ2ZTJvwVbBn3usZnjMi1GacrMVzVcAxJShTCpZlPs26EdEjQ==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.6.tgz", + "integrity": "sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.0.3.tgz", - "integrity": "sha512-6sPWmZetzFWMsz7Dhuxsdmbu3fK+/AxKRtj7OB0/3OZAI2MHB/v2FeYh271LZ9abvnM1WIwWc/5umYjx0jo5sQ==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.1.6.tgz", + "integrity": "sha512-/Qq3PTagA6+nYVfryAtQ7/9FEr/6YVyvOtl6rZnGsbReGLf0jZU6gkpr1FuChAQpvV46a78p4cmHOVP8mbfSMQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1054,9 +1055,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.0.3.tgz", - "integrity": "sha512-MOnbd92+OByu0p6QBAzq1ahVWzF6nyfiH07dQDez4/Nku7G249NjxDVyEfVhz8WkLiOEU+KFVnqtgcsfP2nLXg==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.6.tgz", + "integrity": "sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==", "cpu": [ "arm64" ], @@ -1070,9 +1071,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.0.3.tgz", - "integrity": "sha512-i70C4O1VmbTivYdRlk+5lj9xRc2BlK3oUikt3yJeHT1unL4LsNtN7UiOhVanFdc7vDAgZn1tV/9mQwMkWOJvHg==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.6.tgz", + "integrity": "sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==", "cpu": [ "x64" ], @@ -1086,12 +1087,15 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.0.3.tgz", - "integrity": "sha512-O88gCZ95sScwD00mn/AtalyCoykhhlokxH/wi1huFK+rmiP5LAYVs/i2ruk7xST6SuXN4NI5y4Xf5vepb2jf6A==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.6.tgz", + "integrity": "sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==", "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1102,12 +1106,15 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.0.3.tgz", - "integrity": "sha512-CEErFt78S/zYXzFIiv18iQCbRbLgBluS8z1TNDQoyPi8/Jr5qhR3e8XHAIxVxPBjDbEMITprqELVc5KTfFj0gg==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.6.tgz", + "integrity": "sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==", "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1118,12 +1125,15 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.0.3.tgz", - "integrity": "sha512-Tc3i+nwt6mQ+Dwzcri/WNDj56iWdycGVh5YwwklleClzPzz7UpfaMw1ci7bLl6GRYMXhWDBfe707EXNjKtiswQ==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.6.tgz", + "integrity": "sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==", "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1134,12 +1144,15 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.0.3.tgz", - "integrity": "sha512-zTh03Z/5PBBPdTurgEtr6nY0vI9KR9Ifp/jZCcHlODzwVOEKcKRBtQIGrkc7izFgOMuXDEJBmirwpGqdM/ZixA==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.6.tgz", + "integrity": "sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==", "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1150,9 +1163,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.0.3.tgz", - "integrity": "sha512-Jc1EHxtZovcJcg5zU43X3tuqzl/sS+CmLgjRP28ZT4vk869Ncm2NoF8qSTaL99gh6uOzgM99Shct06pSO6kA6g==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.6.tgz", + "integrity": "sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==", "cpu": [ "arm64" ], @@ -1166,9 +1179,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.3.tgz", - "integrity": "sha512-N7EJ6zbxgIYpI/sWNzpVKRMbfEGgsWuOIvzkML7wxAAZhPk1Msxuo/JDu1PKjWGrAoOLaZcIX5s+/pF5LIbBBg==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.6.tgz", + "integrity": "sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==", "cpu": [ "x64" ], @@ -1588,7 +1601,7 @@ "version": "19.2.5", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.5.tgz", "integrity": "sha512-keKxkZMqnDicuvFoJbzrhbtdLSPhj/rZThDlKWCDbgXmUg0rEUFtRssDXKYmtXluZlIqiC5VqkCgRwzuyLHKHw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "csstype": "^3.0.2" @@ -2174,38 +2187,6 @@ "win32" ] }, - "node_modules/@xyflow/react": { - "version": "12.10.0", - "resolved": "https://registry.npmjs.org/@xyflow/react/-/react-12.10.0.tgz", - "integrity": "sha512-eOtz3whDMWrB4KWVatIBrKuxECHqip6PfA8fTpaS2RUGVpiEAe+nqDKsLqkViVWxDGreq0lWX71Xth/SPAzXiw==", - "license": "MIT", - "dependencies": { - "@xyflow/system": "0.0.74", - "classcat": "^5.0.3", - "zustand": "^4.4.0" - }, - "peerDependencies": { - "react": ">=17", - "react-dom": ">=17" - } - }, - "node_modules/@xyflow/system": { - "version": "0.0.74", - "resolved": "https://registry.npmjs.org/@xyflow/system/-/system-0.0.74.tgz", - "integrity": "sha512-7v7B/PkiVrkdZzSbL+inGAo6tkR/WQHHG0/jhSvLQToCsfa8YubOGmBYd1s08tpKpihdHDZFwzQZeR69QSBb4Q==", - "license": "MIT", - "dependencies": { - "@types/d3-drag": "^3.0.7", - "@types/d3-interpolate": "^3.0.4", - "@types/d3-selection": "^3.0.10", - "@types/d3-transition": "^3.0.8", - "@types/d3-zoom": "^3.0.8", - "d3-drag": "^3.0.0", - "d3-interpolate": "^3.0.1", - "d3-selection": "^3.0.0", - "d3-zoom": "^3.0.0" - } - }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", @@ -2500,13 +2481,15 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.8.28", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.28.tgz", - "integrity": "sha512-gYjt7OIqdM0PcttNYP2aVrr2G0bMALkBaoehD4BuRGjAOtipg0b6wHg1yNL+s5zSnLZZrGHOw4IrND8CD+3oIQ==", - "dev": true, + "version": "2.10.8", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.8.tgz", + "integrity": "sha512-PCLz/LXGBsNTErbtB6i5u4eLpHeMfi93aUv5duMmj6caNu6IphS4q6UevDnL36sZQv9lrP11dbPKGMaXPwMKfQ==", "license": "Apache-2.0", "bin": { - "baseline-browser-mapping": "dist/cli.js" + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" } }, "node_modules/brace-expansion": { @@ -2664,12 +2647,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/classcat": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/classcat/-/classcat-5.0.5.tgz", - "integrity": "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==", - "license": "MIT" - }, "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", @@ -2729,114 +2706,9 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.2.tgz", "integrity": "sha512-D80T+tiqkd/8B0xNlbstWDG4x6aqVfO52+OlSUNIdkTvmNw0uQpJLeos2J/2XvpyidAFuTPmpad+tUxLndwj6g==", - "devOptional": true, + "dev": true, "license": "MIT" }, - "node_modules/d3-color": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-dispatch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", - "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-drag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", - "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", - "license": "ISC", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-selection": "3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-ease": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", - "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-interpolate": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", - "license": "ISC", - "dependencies": { - "d3-color": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-selection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", - "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-timer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", - "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-transition": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", - "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", - "license": "ISC", - "dependencies": { - "d3-color": "1 - 3", - "d3-dispatch": "1 - 3", - "d3-ease": "1 - 3", - "d3-interpolate": "1 - 3", - "d3-timer": "1 - 3" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "d3-selection": "2 - 3" - } - }, - "node_modules/d3-zoom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", - "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", - "license": "ISC", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-drag": "2 - 3", - "d3-interpolate": "1 - 3", - "d3-selection": "2 - 3", - "d3-transition": "2 - 3" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -3286,13 +3158,13 @@ } }, "node_modules/eslint-config-next": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.0.3.tgz", - "integrity": "sha512-5F6qDjcZldf0Y0ZbqvWvap9xzYUxyDf7/of37aeyhvkrQokj/4bT1JYWZdlWUr283aeVa+s52mPq9ogmGg+5dw==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.1.6.tgz", + "integrity": "sha512-vKq40io2B0XtkkNDYyleATwblNt8xuh3FWp8SpSz3pt7P01OkBFlKsJZ2mWt5WsCySlDQLckb1zMY9yE9Qy0LA==", "dev": true, "license": "MIT", "dependencies": { - "@next/eslint-plugin-next": "16.0.3", + "@next/eslint-plugin-next": "16.1.6", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.2", "eslint-plugin-import": "^2.32.0", @@ -3831,6 +3703,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/geist": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/geist/-/geist-1.7.0.tgz", + "integrity": "sha512-ZaoiZwkSf0DwwB1ncdLKp+ggAldqxl5L1+SXaNIBGkPAqcu+xjVJLxlf3/S8vLt9UHx1xu5fz3lbzKCj5iOVdQ==", + "license": "SIL OPEN FONT LICENSE", + "peerDependencies": { + "next": ">=13.2.0" + } + }, "node_modules/generator-function": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", @@ -5161,13 +5042,14 @@ "license": "MIT" }, "node_modules/next": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/next/-/next-16.0.3.tgz", - "integrity": "sha512-Ka0/iNBblPFcIubTA1Jjh6gvwqfjrGq1Y2MTI5lbjeLIAfmC+p5bQmojpRZqgHHVu5cG4+qdIiwXiBSm/8lZ3w==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/next/-/next-16.1.6.tgz", + "integrity": "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==", "license": "MIT", "dependencies": { - "@next/env": "16.0.3", + "@next/env": "16.1.6", "@swc/helpers": "0.5.15", + "baseline-browser-mapping": "^2.8.3", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" @@ -5179,14 +5061,14 @@ "node": ">=20.9.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "16.0.3", - "@next/swc-darwin-x64": "16.0.3", - "@next/swc-linux-arm64-gnu": "16.0.3", - "@next/swc-linux-arm64-musl": "16.0.3", - "@next/swc-linux-x64-gnu": "16.0.3", - "@next/swc-linux-x64-musl": "16.0.3", - "@next/swc-win32-arm64-msvc": "16.0.3", - "@next/swc-win32-x64-msvc": "16.0.3", + "@next/swc-darwin-arm64": "16.1.6", + "@next/swc-darwin-x64": "16.1.6", + "@next/swc-linux-arm64-gnu": "16.1.6", + "@next/swc-linux-arm64-musl": "16.1.6", + "@next/swc-linux-x64-gnu": "16.1.6", + "@next/swc-linux-x64-musl": "16.1.6", + "@next/swc-win32-arm64-msvc": "16.1.6", + "@next/swc-win32-x64-msvc": "16.1.6", "sharp": "^0.34.4" }, "peerDependencies": { @@ -5590,24 +5472,24 @@ "license": "MIT" }, "node_modules/react": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", - "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", + "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/react-dom": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", - "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", "license": "MIT", "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.2.0" + "react": "^19.2.4" } }, "node_modules/react-is": { @@ -6587,15 +6469,6 @@ "punycode": "^2.1.0" } }, - "node_modules/use-sync-external-store": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", - "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", - "license": "MIT", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -6753,34 +6626,6 @@ "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } - }, - "node_modules/zustand": { - "version": "4.5.7", - "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.7.tgz", - "integrity": "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==", - "license": "MIT", - "dependencies": { - "use-sync-external-store": "^1.2.2" - }, - "engines": { - "node": ">=12.7.0" - }, - "peerDependencies": { - "@types/react": ">=16.8", - "immer": ">=9.0.6", - "react": ">=16.8" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "immer": { - "optional": true - }, - "react": { - "optional": true - } - } } } } diff --git a/package.json b/package.json index 29e0176..76b31e2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "opsorch-console", "version": "0.1.0", - "license": "SEE LICENSE IN LICENSE", + "license": "Apache-2.0", "repository": { "type": "git", "url": "git+https://github.com/OpsOrch/opsorch-console.git" @@ -25,28 +25,26 @@ "author": "OpsOrch", "scripts": { "dev": "next dev", - "dev:oss": "NEXT_PUBLIC_OPSORCH_EDITION=oss next dev", - "dev:enterprise": "NEXT_PUBLIC_OPSORCH_EDITION=enterprise next dev", "build": "next build", - "build:oss": "NEXT_PUBLIC_OPSORCH_EDITION=oss next build", - "build:enterprise": "NEXT_PUBLIC_OPSORCH_EDITION=enterprise next build", "start": "next start", "lint": "eslint", "test": "node --test --loader ./scripts/ts-loader.mjs tests/*.test.ts" }, "dependencies": { "@tanstack/react-query": "^5.90.10", - "next": "16.0.3", - "react": "19.2.0", - "react-dom": "19.2.0" + "geist": "^1.7.0", + "next": "^16.1.6", + "react": "^19.2.4", + "react-dom": "^19.2.4" }, "devDependencies": { "@tailwindcss/postcss": "^4", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", + "baseline-browser-mapping": "^2.10.8", "eslint": "^9", - "eslint-config-next": "16.0.3", + "eslint-config-next": "^16.1.6", "tailwindcss": "^4", "typescript": "^5" } diff --git a/tests/edition.test.ts b/tests/edition.test.ts deleted file mode 100644 index a95af2d..0000000 --- a/tests/edition.test.ts +++ /dev/null @@ -1,198 +0,0 @@ -/** - * Unit tests for edition separation - * Feature: edition-separation - */ - -import { test } from "node:test"; -import * as assert from "node:assert"; - -// Import the edition module to test -import { EDITION, isOSS, isEnterprise } from "../app/lib/edition.js"; - -/** - * Test 1: Edition variable defaults to OSS - * Feature: edition-separation, Test 1: Edition variable defaults to OSS - * Validates: Requirements 1.2 - */ -test("Test 1: Edition variable defaults to OSS when undefined", () => { - // Test that the default behavior logic is correct - const testCases = [undefined, "", null, " ", "\t", "\n", " \n\t "]; - - testCases.forEach((envValue) => { - // Simulate what the edition module does with these values - const simulatedEdition = (envValue?.trim() || "oss"); - - assert.strictEqual( - simulatedEdition, - "oss", - `Edition should default to "oss" when OPSORCH_EDITION is ${JSON.stringify(envValue)}` - ); - }); - - // Also verify that if OPSORCH_EDITION was not set during this process, - // the module correctly defaults to "oss" - if (!process.env.OPSORCH_EDITION || process.env.OPSORCH_EDITION.trim() === "") { - assert.strictEqual(EDITION, "oss", "EDITION constant should be 'oss' when env var is not set"); - assert.strictEqual(isOSS(), true, "isOSS() should return true when env var is not set"); - assert.strictEqual(isEnterprise(), false, "isEnterprise() should return false when env var is not set"); - } -}); - -/** - * Test 5: Edition utility returns correct values - * Feature: edition-separation, Test 5: Edition utility returns correct values - * Validates: Requirements 9.2, 9.5 - */ -test("Test 5: Edition utility returns correct values", () => { - const testCases = ["oss", "enterprise", "other"]; - - testCases.forEach((editionValue) => { - // Simulate what isEnterprise() does - const shouldBeEnterprise = editionValue === "enterprise"; - const shouldBeOSS = editionValue !== "enterprise"; - - // Test the logic - assert.strictEqual( - shouldBeEnterprise, - editionValue === "enterprise", - `isEnterprise() should return ${shouldBeEnterprise} for "${editionValue}"` - ); - - assert.strictEqual( - shouldBeOSS, - editionValue !== "enterprise", - `isOSS() should return ${shouldBeOSS} for "${editionValue}"` - ); - }); -}); - -/** - * Test 8: Invalid edition values default to OSS - * Feature: edition-separation, Test 8: Invalid edition values default to OSS - * Validates: Requirements 1.5 - */ -test("Test 8: Invalid edition values default to OSS behavior", () => { - const invalidValues = ["ENTERPRISE", "Enterprise", "OSS", "Oss", "invalid", "test", "prod", "dev"]; - - invalidValues.forEach((invalidValue) => { - // Test that the isEnterprise logic treats any non-"enterprise" value as OSS - const simulatedIsEnterprise = invalidValue === "enterprise"; - const simulatedIsOSS = invalidValue !== "enterprise"; - - assert.strictEqual( - simulatedIsEnterprise, - false, - `isEnterprise() should return false for invalid value "${invalidValue}"` - ); - - assert.strictEqual( - simulatedIsOSS, - true, - `isOSS() should return true for invalid value "${invalidValue}"` - ); - }); -}); - -/** - * Unit test: Verify current edition utilities work correctly - */ -test("Edition utilities work correctly for current environment", () => { - // Test that the functions are consistent with the EDITION constant - if (EDITION === "enterprise") { - assert.strictEqual(isEnterprise(), true, "isEnterprise() should return true when EDITION is 'enterprise'"); - assert.strictEqual(isOSS(), false, "isOSS() should return false when EDITION is 'enterprise'"); - } else { - assert.strictEqual(isEnterprise(), false, "isEnterprise() should return false when EDITION is not 'enterprise'"); - assert.strictEqual(isOSS(), true, "isOSS() should return true when EDITION is not 'enterprise'"); - } -}); - -/** - * Test 3: Navigation filtering matches edition - * Feature: edition-separation, Test 3: Navigation filtering matches edition - * Validates: Requirements 5.1, 5.2, 5.3, 5.4, 5.5 - */ -test("Test 3: Navigation filtering matches edition", () => { - const navItems = [ - { href: "/oss", label: "OSS Item", edition: "oss" }, - { href: "/ent", label: "Enterprise Item", edition: "enterprise" }, - { href: "/both", label: "Shared Item", edition: "both" }, - { href: "/none", label: "No Edition Item" }, // defaults to both - ]; - - const editions = ["oss", "enterprise"]; - - editions.forEach((currentEdition) => { - // Simulate the filtering logic from AppShell - const filteredItems = navItems.filter((item) => { - if (!item.edition || item.edition === "both") return true; - if (item.edition === "enterprise") return currentEdition === "enterprise"; - if (item.edition === "oss") return currentEdition !== "enterprise"; - return true; - }); - - // Verify all filtered items are appropriate for the edition - for (const item of filteredItems) { - if (item.edition === "enterprise") { - assert.strictEqual( - currentEdition, - "enterprise", - `Enterprise-only item "${item.label}" should not appear in OSS edition` - ); - } - } - - // Verify no enterprise items in OSS - if (currentEdition === "oss") { - const hasEnterpriseItems = filteredItems.some((item) => item.edition === "enterprise"); - assert.strictEqual( - hasEnterpriseItems, - false, - "OSS edition should not have any enterprise-only navigation items" - ); - - // Should have OSS items - const hasOSSItems = filteredItems.some((item) => item.edition === "oss"); - assert.strictEqual(hasOSSItems, true, "OSS edition should have OSS items"); - } - - // Verify no OSS items in Enterprise (if that's the logic, though usually Enterprise includes OSS features, - // but the filter logic: if (item.edition === "oss") return currentEdition !== "enterprise"; - // implies "oss" tagged items are OSS-ONLY. Shared items should be "both" or undefined) - if (currentEdition === "enterprise") { - const hasOSSOnlyItems = filteredItems.some((item) => item.edition === "oss"); - assert.strictEqual( - hasOSSOnlyItems, - false, - "Enterprise edition should not have OSS-only items (items tagged explicitly as 'oss')" - ); - } - }); -}); - -/** - * Test 7: Enterprise files are in dedicated directories - * Feature: edition-separation, Test 7: Enterprise files are in dedicated directories - * Validates: Requirements 3.1, 3.2, 3.3, 3.4 - */ -test("Test 7: Enterprise files are in dedicated directories", async () => { - const fs = await import("node:fs/promises"); - const path = await import("node:path"); - - // Verify enterprise directories exist - const enterpriseDirs = [ - "app/(enterprise)", - "app/components/(enterprise)", - "app/api/(enterprise)", - ]; - - for (const dir of enterpriseDirs) { - const fullPath = path.join(process.cwd(), dir); - const stats = await fs.stat(fullPath); - assert.strictEqual( - stats.isDirectory(), - true, - `${dir} should be a directory` - ); - } -});