chore: Rename Astroglobe -> Astrolabe
This commit is contained in:
@@ -515,7 +515,7 @@ docker compose exec app php occ user_oidc:provider keycloak
|
|||||||
docker compose exec app cat /var/www/html/data/nextcloud.log | jq | tail
|
docker compose exec app cat /var/www/html/data/nextcloud.log | jq | tail
|
||||||
|
|
||||||
# Filter by app
|
# Filter by app
|
||||||
docker compose exec app cat /var/www/html/data/nextcloud.log | jq 'select(.app == "astroglobe")' | tail
|
docker compose exec app cat /var/www/html/data/nextcloud.log | jq 'select(.app == "astrolabe")' | tail
|
||||||
|
|
||||||
# Filter by log level (0=DEBUG, 1=INFO, 2=WARN, 3=ERROR, 4=FATAL)
|
# Filter by log level (0=DEBUG, 1=INFO, 2=WARN, 3=ERROR, 4=FATAL)
|
||||||
docker compose exec app cat /var/www/html/data/nextcloud.log | jq 'select(.level >= 3)' | tail
|
docker compose exec app cat /var/www/html/data/nextcloud.log | jq 'select(.level >= 3)' | tail
|
||||||
|
|||||||
+27
-27
@@ -2,32 +2,32 @@
|
|||||||
|
|
||||||
set -euox pipefail
|
set -euox pipefail
|
||||||
|
|
||||||
echo "Installing and configuring Astroglobe app for testing..."
|
echo "Installing and configuring Astrolabe app for testing..."
|
||||||
|
|
||||||
# Check if development astroglobe app is mounted at /opt/apps/astroglobe
|
# Check if development astrolabe app is mounted at /opt/apps/astrolabe
|
||||||
if [ -d /opt/apps/astroglobe ]; then
|
if [ -d /opt/apps/astrolabe ]; then
|
||||||
echo "Development astroglobe app found at /opt/apps/astroglobe"
|
echo "Development astrolabe app found at /opt/apps/astrolabe"
|
||||||
|
|
||||||
# Remove any existing astroglobe app in custom_apps (from app store or old symlink)
|
# Remove any existing astrolabe app in custom_apps (from app store or old symlink)
|
||||||
if [ -e /var/www/html/custom_apps/astroglobe ]; then
|
if [ -e /var/www/html/custom_apps/astrolabe ]; then
|
||||||
echo "Removing existing astroglobe in custom_apps..."
|
echo "Removing existing astrolabe in custom_apps..."
|
||||||
rm -rf /var/www/html/custom_apps/astroglobe
|
rm -rf /var/www/html/custom_apps/astrolabe
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create symlink from custom_apps to the mounted development version
|
# Create symlink from custom_apps to the mounted development version
|
||||||
# Per Nextcloud docs: apps outside server root need symlinks in server root
|
# Per Nextcloud docs: apps outside server root need symlinks in server root
|
||||||
echo "Creating symlink: custom_apps/astroglobe -> /opt/apps/astroglobe"
|
echo "Creating symlink: custom_apps/astrolabe -> /opt/apps/astrolabe"
|
||||||
ln -sf /opt/apps/astroglobe /var/www/html/custom_apps/astroglobe
|
ln -sf /opt/apps/astrolabe /var/www/html/custom_apps/astrolabe
|
||||||
|
|
||||||
echo "Enabling astroglobe app from /opt/apps (development mode via symlink)"
|
echo "Enabling astrolabe app from /opt/apps (development mode via symlink)"
|
||||||
php /var/www/html/occ app:enable astroglobe
|
php /var/www/html/occ app:enable astrolabe
|
||||||
elif [ -d /var/www/html/custom_apps/astroglobe ]; then
|
elif [ -d /var/www/html/custom_apps/astrolabe ]; then
|
||||||
echo "astroglobe app directory found in custom_apps (already installed)"
|
echo "astrolabe app directory found in custom_apps (already installed)"
|
||||||
php /var/www/html/occ app:enable astroglobe
|
php /var/www/html/occ app:enable astrolabe
|
||||||
else
|
else
|
||||||
echo "astroglobe app not found, installing from app store..."
|
echo "astrolabe app not found, installing from app store..."
|
||||||
php /var/www/html/occ app:install astroglobe
|
php /var/www/html/occ app:install astrolabe
|
||||||
php /var/www/html/occ app:enable astroglobe
|
php /var/www/html/occ app:enable astrolabe
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Configure MCP server URLs in Nextcloud system config
|
# Configure MCP server URLs in Nextcloud system config
|
||||||
@@ -36,14 +36,14 @@ fi
|
|||||||
php /var/www/html/occ config:system:set mcp_server_url --value='http://mcp-oauth:8001'
|
php /var/www/html/occ config:system:set mcp_server_url --value='http://mcp-oauth:8001'
|
||||||
php /var/www/html/occ config:system:set mcp_server_public_url --value='http://localhost:8001'
|
php /var/www/html/occ config:system:set mcp_server_public_url --value='http://localhost:8001'
|
||||||
|
|
||||||
# Create OAuth client for Astroglobe app
|
# Create OAuth client for Astrolabe app
|
||||||
# The resource_url MUST match what the MCP server expects as token audience
|
# The resource_url MUST match what the MCP server expects as token audience
|
||||||
# This allows tokens from this client to be validated by MCP server's UnifiedTokenVerifier
|
# This allows tokens from this client to be validated by MCP server's UnifiedTokenVerifier
|
||||||
MCP_CLIENT_ID="nextcloudMcpServerUIPublicClient"
|
MCP_CLIENT_ID="nextcloudMcpServerUIPublicClient"
|
||||||
MCP_RESOURCE_URL="http://localhost:8001"
|
MCP_RESOURCE_URL="http://localhost:8001"
|
||||||
MCP_REDIRECT_URI="http://localhost:8080/apps/astroglobe/oauth/callback"
|
MCP_REDIRECT_URI="http://localhost:8080/apps/astrolabe/oauth/callback"
|
||||||
|
|
||||||
echo "Configuring OAuth client for Astroglobe..."
|
echo "Configuring OAuth client for Astrolabe..."
|
||||||
|
|
||||||
# Check if client already exists
|
# Check if client already exists
|
||||||
if php /var/www/html/occ oidc:list 2>/dev/null | grep -q "$MCP_CLIENT_ID"; then
|
if php /var/www/html/occ oidc:list 2>/dev/null | grep -q "$MCP_CLIENT_ID"; then
|
||||||
@@ -54,7 +54,7 @@ fi
|
|||||||
# Create OAuth client with correct resource_url for MCP server audience
|
# Create OAuth client with correct resource_url for MCP server audience
|
||||||
echo "Creating OAuth confidential client with resource_url=$MCP_RESOURCE_URL"
|
echo "Creating OAuth confidential client with resource_url=$MCP_RESOURCE_URL"
|
||||||
CLIENT_OUTPUT=$(php /var/www/html/occ oidc:create \
|
CLIENT_OUTPUT=$(php /var/www/html/occ oidc:create \
|
||||||
"Astroglobe" \
|
"Astrolabe" \
|
||||||
"$MCP_REDIRECT_URI" \
|
"$MCP_REDIRECT_URI" \
|
||||||
--client_id="$MCP_CLIENT_ID" \
|
--client_id="$MCP_CLIENT_ID" \
|
||||||
--type=confidential \
|
--type=confidential \
|
||||||
@@ -69,16 +69,16 @@ echo "$CLIENT_OUTPUT"
|
|||||||
CLIENT_SECRET=$(echo "$CLIENT_OUTPUT" | php -r 'echo json_decode(file_get_contents("php://stdin"), true)["client_secret"] ?? "";')
|
CLIENT_SECRET=$(echo "$CLIENT_OUTPUT" | php -r 'echo json_decode(file_get_contents("php://stdin"), true)["client_secret"] ?? "";')
|
||||||
|
|
||||||
if [ -n "$CLIENT_SECRET" ]; then
|
if [ -n "$CLIENT_SECRET" ]; then
|
||||||
echo "Configuring Astroglobe client secret in system config..."
|
echo "Configuring Astrolabe client secret in system config..."
|
||||||
php /var/www/html/occ config:system:set astroglobe_client_secret --value="$CLIENT_SECRET"
|
php /var/www/html/occ config:system:set astrolabe_client_secret --value="$CLIENT_SECRET"
|
||||||
echo "✓ Client secret configured: ${CLIENT_SECRET:0:8}..."
|
echo "✓ Client secret configured: ${CLIENT_SECRET:0:8}..."
|
||||||
else
|
else
|
||||||
echo "⚠ Warning: Could not extract client_secret from OIDC client creation"
|
echo "⚠ Warning: Could not extract client_secret from OIDC client creation"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Configure OAuth client ID in system config
|
# Configure OAuth client ID in system config
|
||||||
echo "Configuring Astroglobe client ID in system config..."
|
echo "Configuring Astrolabe client ID in system config..."
|
||||||
php /var/www/html/occ config:system:set astroglobe_client_id --value="$MCP_CLIENT_ID"
|
php /var/www/html/occ config:system:set astrolabe_client_id --value="$MCP_CLIENT_ID"
|
||||||
echo "✓ Client ID configured: $MCP_CLIENT_ID"
|
echo "✓ Client ID configured: $MCP_CLIENT_ID"
|
||||||
|
|
||||||
echo "Astroglobe app installed and configured successfully"
|
echo "Astrolabe app installed and configured successfully"
|
||||||
+1
-1
@@ -35,7 +35,7 @@ services:
|
|||||||
# Mount OIDC development directory outside /var/www/html to avoid rsync conflicts
|
# Mount OIDC development directory outside /var/www/html to avoid rsync conflicts
|
||||||
# The post-installation hook will register /opt/apps as an additional app directory
|
# The post-installation hook will register /opt/apps as an additional app directory
|
||||||
#- ./third_party:/opt/apps:ro
|
#- ./third_party:/opt/apps:ro
|
||||||
- ./third_party/astroglobe:/opt/apps/astroglobe:ro
|
- ./third_party/astrolabe:/opt/apps/astrolabe:ro
|
||||||
environment:
|
environment:
|
||||||
- NEXTCLOUD_TRUSTED_DOMAINS=app
|
- NEXTCLOUD_TRUSTED_DOMAINS=app
|
||||||
- NEXTCLOUD_ADMIN_USER=admin
|
- NEXTCLOUD_ADMIN_USER=admin
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ Claude Desktop → MCP Server /mcp/sse endpoint
|
|||||||
The MCP server supports three deployment modes, each with different authentication requirements for the three critical communication paths:
|
The MCP server supports three deployment modes, each with different authentication requirements for the three critical communication paths:
|
||||||
|
|
||||||
1. **External MCP Client → MCP Server** (e.g., Claude Desktop)
|
1. **External MCP Client → MCP Server** (e.g., Claude Desktop)
|
||||||
2. **Astroglobe UI → MCP Server** (PHP app REST API calls)
|
2. **Astrolabe UI → MCP Server** (PHP app REST API calls)
|
||||||
3. **MCP Server → Nextcloud** (background jobs, vector sync)
|
3. **MCP Server → Nextcloud** (background jobs, vector sync)
|
||||||
|
|
||||||
#### Mode 1: Basic Single-User (Development/Simple Deployments)
|
#### Mode 1: Basic Single-User (Development/Simple Deployments)
|
||||||
@@ -218,7 +218,7 @@ NEXTCLOUD_PASSWORD=admin_password
|
|||||||
| Communication Path | Method |
|
| Communication Path | Method |
|
||||||
|-------------------|--------|
|
|-------------------|--------|
|
||||||
| MCP Client → Server | None (assumes single user) |
|
| MCP Client → Server | None (assumes single user) |
|
||||||
| Astroglobe UI → Server | None (uses env credentials) |
|
| Astrolabe UI → Server | None (uses env credentials) |
|
||||||
| Server → Nextcloud | BasicAuth from environment |
|
| Server → Nextcloud | BasicAuth from environment |
|
||||||
|
|
||||||
**Use Cases:**
|
**Use Cases:**
|
||||||
@@ -244,7 +244,7 @@ DEPLOYMENT_MODE=basic_multiuser
|
|||||||
| Communication Path | Method |
|
| Communication Path | Method |
|
||||||
|-------------------|--------|
|
|-------------------|--------|
|
||||||
| MCP Client → Server | BasicAuth with Nextcloud app password |
|
| MCP Client → Server | BasicAuth with Nextcloud app password |
|
||||||
| Astroglobe UI → Server | BasicAuth with Nextcloud app password |
|
| Astrolabe UI → Server | BasicAuth with Nextcloud app password |
|
||||||
| Server → Nextcloud | Pass-through client's credentials |
|
| Server → Nextcloud | Pass-through client's credentials |
|
||||||
|
|
||||||
**Architecture:**
|
**Architecture:**
|
||||||
@@ -360,7 +360,7 @@ Users generate app passwords in Nextcloud settings:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Astroglobe UI in BasicAuth Multi-User:**
|
**Astrolabe UI in BasicAuth Multi-User:**
|
||||||
|
|
||||||
The PHP app prompts users to save their app password:
|
The PHP app prompts users to save their app password:
|
||||||
|
|
||||||
@@ -373,11 +373,11 @@ public function search(string $query, array $options = []): array {
|
|||||||
|
|
||||||
// Get user's app password from settings
|
// Get user's app password from settings
|
||||||
$appPassword = $this->config->getUserValue(
|
$appPassword = $this->config->getUserValue(
|
||||||
$userId, 'astroglobe', 'app_password', ''
|
$userId, 'astrolabe', 'app_password', ''
|
||||||
);
|
);
|
||||||
|
|
||||||
if (empty($appPassword)) {
|
if (empty($appPassword)) {
|
||||||
return ['error' => 'Please configure app password in Astroglobe settings'];
|
return ['error' => 'Please configure app password in Astrolabe settings'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$response = $this->httpClient->post(
|
$response = $this->httpClient->post(
|
||||||
@@ -453,14 +453,14 @@ ENABLE_OFFLINE_ACCESS=true # For background jobs
|
|||||||
| Communication Path | Method |
|
| Communication Path | Method |
|
||||||
|-------------------|--------|
|
|-------------------|--------|
|
||||||
| MCP Client → Server | OAuth Bearer token (PKCE flow) |
|
| MCP Client → Server | OAuth Bearer token (PKCE flow) |
|
||||||
| Astroglobe UI → Server | OAuth Bearer token (PKCE flow) |
|
| Astrolabe UI → Server | OAuth Bearer token (PKCE flow) |
|
||||||
| Server → Nextcloud | Token exchange OR refresh token (Flow 2) |
|
| Server → Nextcloud | Token exchange OR refresh token (Flow 2) |
|
||||||
|
|
||||||
**Architecture:**
|
**Architecture:**
|
||||||
|
|
||||||
```
|
```
|
||||||
┌─────────────────────────────────────────────────────┐
|
┌─────────────────────────────────────────────────────┐
|
||||||
│ MCP Client / Astroglobe UI │
|
│ MCP Client / Astrolabe UI │
|
||||||
└──────────────────────┬──────────────────────────────┘
|
└──────────────────────┬──────────────────────────────┘
|
||||||
│ PKCE OAuth Flow
|
│ PKCE OAuth Flow
|
||||||
▼
|
▼
|
||||||
@@ -512,7 +512,7 @@ Choose deployment mode based on requirements:
|
|||||||
| **Multi-user support** | ❌ | ✅ | ✅ |
|
| **Multi-user support** | ❌ | ✅ | ✅ |
|
||||||
| **Per-user identity** | ❌ | ✅ | ✅ |
|
| **Per-user identity** | ❌ | ✅ | ✅ |
|
||||||
| **External MCP clients** | ⚠️ No auth | ✅ BasicAuth | ✅ OAuth |
|
| **External MCP clients** | ⚠️ No auth | ✅ BasicAuth | ✅ OAuth |
|
||||||
| **Astroglobe UI access** | ✅ | ✅ | ✅ |
|
| **Astrolabe UI access** | ✅ | ✅ | ✅ |
|
||||||
| **Background jobs** | ✅ | ✅ | ✅ |
|
| **Background jobs** | ✅ | ✅ | ✅ |
|
||||||
| **OIDC required** | ❌ | ❌ | ✅ |
|
| **OIDC required** | ❌ | ❌ | ✅ |
|
||||||
| **Token scoping** | ❌ | ❌ | ✅ |
|
| **Token scoping** | ❌ | ❌ | ✅ |
|
||||||
@@ -1586,7 +1586,7 @@ MANAGEMENT_API_ENABLED=true # Required
|
|||||||
|
|
||||||
**Proposed Architecture:**
|
**Proposed Architecture:**
|
||||||
```
|
```
|
||||||
External MCP Client → Astroglobe PHP App (SSE proxy) → MCP Container
|
External MCP Client → Astrolabe PHP App (SSE proxy) → MCP Container
|
||||||
```
|
```
|
||||||
|
|
||||||
**Pros:**
|
**Pros:**
|
||||||
@@ -1629,11 +1629,11 @@ location /mcp/ {
|
|||||||
- PHP is fundamentally ill-suited for SSE proxying (request-response vs streaming)
|
- PHP is fundamentally ill-suited for SSE proxying (request-response vs streaming)
|
||||||
- Reverse proxy at web server layer is simpler, more performant, and standard practice
|
- Reverse proxy at web server layer is simpler, more performant, and standard practice
|
||||||
- No value added by PHP layer - authentication handled by container regardless
|
- No value added by PHP layer - authentication handled by container regardless
|
||||||
- Rest API for Astroglobe UI is sufficient for internal NC integration
|
- Rest API for Astrolabe UI is sufficient for internal NC integration
|
||||||
|
|
||||||
**Note:** This alternative would have made sense if it enabled new use cases. However:
|
**Note:** This alternative would have made sense if it enabled new use cases. However:
|
||||||
1. **External MCP clients**: Work fine connecting directly to container (via reverse proxy)
|
1. **External MCP clients**: Work fine connecting directly to container (via reverse proxy)
|
||||||
2. **Astroglobe UI**: Doesn't need MCP protocol - REST API sufficient
|
2. **Astrolabe UI**: Doesn't need MCP protocol - REST API sufficient
|
||||||
3. **Authentication**: Solved by BasicAuth multi-user mode (pass-through) for non-OIDC deployments
|
3. **Authentication**: Solved by BasicAuth multi-user mode (pass-through) for non-OIDC deployments
|
||||||
|
|
||||||
The REST API + BasicAuth multi-user architecture achieves the same goals (multi-user access without OIDC) without the complexity of SSE proxying.
|
The REST API + BasicAuth multi-user architecture achieves the same goals (multi-user access without OIDC) without the complexity of SSE proxying.
|
||||||
|
|||||||
@@ -1,106 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
echo "====================================="
|
|
||||||
echo "Testing MCP Server UI App Installation"
|
|
||||||
echo "====================================="
|
|
||||||
|
|
||||||
cd "$(dirname "$0")"
|
|
||||||
|
|
||||||
# Colors for output
|
|
||||||
GREEN='\033[0;32m'
|
|
||||||
RED='\033[0;31m'
|
|
||||||
YELLOW='\033[1;33m'
|
|
||||||
NC='\033[0m' # No Color
|
|
||||||
|
|
||||||
echo -e "\n${YELLOW}Step 1: Stopping existing services...${NC}"
|
|
||||||
docker compose down
|
|
||||||
|
|
||||||
echo -e "\n${YELLOW}Step 2: Starting services...${NC}"
|
|
||||||
docker compose up -d app mcp-oauth
|
|
||||||
|
|
||||||
echo -e "\n${YELLOW}Step 3: Waiting for Nextcloud to be healthy...${NC}"
|
|
||||||
timeout=180
|
|
||||||
elapsed=0
|
|
||||||
while ! docker compose exec -T app curl -f http://localhost/status.php 2>/dev/null | grep -q '"installed":true'; do
|
|
||||||
if [ $elapsed -ge $timeout ]; then
|
|
||||||
echo -e "${RED}ERROR: Nextcloud failed to become healthy within ${timeout}s${NC}"
|
|
||||||
echo "Nextcloud logs:"
|
|
||||||
docker compose logs app | tail -50
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "Waiting for Nextcloud... ($elapsed/$timeout)"
|
|
||||||
sleep 5
|
|
||||||
elapsed=$((elapsed + 5))
|
|
||||||
done
|
|
||||||
echo -e "${GREEN}✓ Nextcloud is healthy${NC}"
|
|
||||||
|
|
||||||
echo -e "\n${YELLOW}Step 4: Checking if astroglobe app is enabled...${NC}"
|
|
||||||
if docker compose exec -T app php /var/www/html/occ app:list | grep -A 1 "Enabled:" | grep -q "astroglobe"; then
|
|
||||||
echo -e "${GREEN}✓ astroglobe app is enabled${NC}"
|
|
||||||
else
|
|
||||||
echo -e "${RED}✗ astroglobe app is NOT enabled${NC}"
|
|
||||||
echo "Available apps:"
|
|
||||||
docker compose exec -T app php /var/www/html/occ app:list
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "\n${YELLOW}Step 5: Checking app info...${NC}"
|
|
||||||
docker compose exec -T app php /var/www/html/occ app:list | grep -A 5 astroglobe || true
|
|
||||||
|
|
||||||
echo -e "\n${YELLOW}Step 6: Verifying MCP server URL configuration...${NC}"
|
|
||||||
mcp_url=$(docker compose exec -T app php /var/www/html/occ config:system:get mcp_server_url || echo "NOT_SET")
|
|
||||||
if [ "$mcp_url" = "http://mcp-oauth:8001" ]; then
|
|
||||||
echo -e "${GREEN}✓ MCP server URL is configured correctly: $mcp_url${NC}"
|
|
||||||
else
|
|
||||||
echo -e "${RED}✗ MCP server URL is incorrect: $mcp_url${NC}"
|
|
||||||
echo "Expected: http://mcp-oauth:8001"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "\n${YELLOW}Step 7: Checking if symlink was created...${NC}"
|
|
||||||
if docker compose exec -T app test -L /var/www/html/custom_apps/astroglobe; then
|
|
||||||
echo -e "${GREEN}✓ Symlink exists at /var/www/html/custom_apps/astroglobe${NC}"
|
|
||||||
docker compose exec -T app ls -la /var/www/html/custom_apps/astroglobe
|
|
||||||
else
|
|
||||||
echo -e "${RED}✗ Symlink does not exist${NC}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "\n${YELLOW}Step 8: Checking app structure...${NC}"
|
|
||||||
docker compose exec -T app test -f /opt/apps/astroglobe/appinfo/info.xml && echo -e "${GREEN}✓ info.xml exists${NC}" || echo -e "${RED}✗ info.xml missing${NC}"
|
|
||||||
docker compose exec -T app test -f /opt/apps/astroglobe/lib/Controller/OAuthController.php && echo -e "${GREEN}✓ OAuthController.php exists${NC}" || echo -e "${RED}✗ OAuthController.php missing${NC}"
|
|
||||||
docker compose exec -T app test -f /opt/apps/astroglobe/lib/Service/McpTokenStorage.php && echo -e "${GREEN}✓ McpTokenStorage.php exists${NC}" || echo -e "${RED}✗ McpTokenStorage.php missing${NC}"
|
|
||||||
docker compose exec -T app test -f /opt/apps/astroglobe/appinfo/routes.php && echo -e "${GREEN}✓ routes.php exists${NC}" || echo -e "${RED}✗ routes.php missing${NC}"
|
|
||||||
|
|
||||||
echo -e "\n${YELLOW}Step 9: Checking if admin can access settings...${NC}"
|
|
||||||
# Try to access the admin settings page (this will check if the app loads without errors)
|
|
||||||
if docker compose exec -T app curl -s -u admin:admin http://localhost/index.php/settings/admin/mcp >/dev/null 2>&1; then
|
|
||||||
echo -e "${GREEN}✓ Admin settings page is accessible${NC}"
|
|
||||||
else
|
|
||||||
echo -e "${YELLOW}⚠ Admin settings page returned an error (may be expected if not fully configured)${NC}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "\n${YELLOW}Step 10: Checking Nextcloud logs for errors...${NC}"
|
|
||||||
error_count=$(docker compose exec -T app grep -c "astroglobe" /var/www/html/data/nextcloud.log 2>/dev/null || echo "0")
|
|
||||||
if [ "$error_count" -gt 0 ]; then
|
|
||||||
echo -e "${YELLOW}⚠ Found $error_count log entries mentioning astroglobe${NC}"
|
|
||||||
docker compose exec -T app grep "astroglobe" /var/www/html/data/nextcloud.log | tail -10 || true
|
|
||||||
else
|
|
||||||
echo -e "${GREEN}✓ No errors in Nextcloud logs${NC}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "\n${GREEN}====================================="
|
|
||||||
echo "Testing Complete!"
|
|
||||||
echo "=====================================${NC}"
|
|
||||||
echo ""
|
|
||||||
echo "Next steps:"
|
|
||||||
echo "1. Open http://localhost:8080 in your browser"
|
|
||||||
echo "2. Login with admin/admin"
|
|
||||||
echo "3. Go to Settings → Personal → MCP Server"
|
|
||||||
echo "4. You should see the OAuth authorization UI"
|
|
||||||
echo ""
|
|
||||||
echo "To view logs:"
|
|
||||||
echo " docker compose logs -f app"
|
|
||||||
echo ""
|
|
||||||
echo "To access occ commands:"
|
|
||||||
echo " docker compose exec app php /var/www/html/occ app:list"
|
|
||||||
@@ -52,7 +52,7 @@ async def test_capture_settings_page(browser):
|
|||||||
"Authorization Required",
|
"Authorization Required",
|
||||||
"MCP Server",
|
"MCP Server",
|
||||||
"Sign In Again",
|
"Sign In Again",
|
||||||
"astroglobe",
|
"astrolabe",
|
||||||
]
|
]
|
||||||
|
|
||||||
for check in checks:
|
for check in checks:
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
"""Test OAuth authorization flow for Nextcloud PHP app (astroglobe).
|
"""Test OAuth authorization flow for Nextcloud PHP app (astrolabe).
|
||||||
|
|
||||||
Tests the complete PKCE OAuth flow from the NC PHP app perspective:
|
Tests the complete PKCE OAuth flow from the NC PHP app perspective:
|
||||||
1. User navigates to personal settings
|
1. User navigates to personal settings
|
||||||
|
|||||||
-11
@@ -1,11 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
use OCP\Util;
|
|
||||||
|
|
||||||
Util::addScript(OCA\Astroglobe\AppInfo\Application::APP_ID, OCA\Astroglobe\AppInfo\Application::APP_ID . '-main');
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
||||||
<div id="astroglobe"></div>
|
|
||||||
Vendored
Vendored
@@ -63,9 +63,9 @@ NC PHP App → User's OAuth Token → MCP Server validates
|
|||||||
|
|
||||||
### Manual Installation
|
### Manual Installation
|
||||||
|
|
||||||
1. Clone or download this directory to `apps/astroglobe`
|
1. Clone or download this directory to `apps/astrolabe`
|
||||||
2. Install dependencies: `composer install`
|
2. Install dependencies: `composer install`
|
||||||
3. Enable the app: `occ app:enable astroglobe`
|
3. Enable the app: `occ app:enable astrolabe`
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ Located in: **Settings → Administration → MCP Server**
|
|||||||
### Structure
|
### Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
astroglobe/
|
astrolabe/
|
||||||
├── lib/
|
├── lib/
|
||||||
│ ├── Controller/
|
│ ├── Controller/
|
||||||
│ │ ├── ApiController.php # Form handlers (revoke, etc.)
|
│ │ ├── ApiController.php # Form handlers (revoke, etc.)
|
||||||
@@ -159,17 +159,17 @@ astroglobe/
|
|||||||
│ ├── admin.php # Admin settings template
|
│ ├── admin.php # Admin settings template
|
||||||
│ └── error.php # Error template
|
│ └── error.php # Error template
|
||||||
├── css/
|
├── css/
|
||||||
│ └── astroglobe-settings.css # Settings styles
|
│ └── astrolabe-settings.css # Settings styles
|
||||||
└── js/
|
└── js/
|
||||||
├── astroglobe-personalSettings.js
|
├── astrolabe-personalSettings.js
|
||||||
└── astroglobe-adminSettings.js
|
└── astrolabe-adminSettings.js
|
||||||
```
|
```
|
||||||
|
|
||||||
### Testing
|
### Testing
|
||||||
|
|
||||||
1. Start MCP server with management API enabled
|
1. Start MCP server with management API enabled
|
||||||
2. Configure Nextcloud (config.php)
|
2. Configure Nextcloud (config.php)
|
||||||
3. Enable the app: `occ app:enable astroglobe`
|
3. Enable the app: `occ app:enable astrolabe`
|
||||||
4. Navigate to settings panels
|
4. Navigate to settings panels
|
||||||
5. Verify data loads from MCP server API
|
5. Verify data loads from MCP server API
|
||||||
|
|
||||||
+13
-13
@@ -1,13 +1,13 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
|
xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
|
||||||
<id>astroglobe</id>
|
<id>astrolabe</id>
|
||||||
<name>Astroglobe</name>
|
<name>Astrolabe</name>
|
||||||
<summary>AI-powered semantic search across your Nextcloud</summary>
|
<summary>AI-powered semantic search across your Nextcloud</summary>
|
||||||
<description>< for conf
|
|||||||
<version>0.1.0</version>
|
<version>0.1.0</version>
|
||||||
<licence>agpl</licence>
|
<licence>agpl</licence>
|
||||||
<author mail="chris@coutinho.io" homepage="https://github.com/cbcoutinho">Chris Coutinho</author>
|
<author mail="chris@coutinho.io" homepage="https://github.com/cbcoutinho">Chris Coutinho</author>
|
||||||
<namespace>Astroglobe</namespace>
|
<namespace>Astrolabe</namespace>
|
||||||
<category>ai</category>
|
<category>ai</category>
|
||||||
<bugs>https://github.com/cbcoutinho/nextcloud-mcp-server/issues</bugs>
|
<bugs>https://github.com/cbcoutinho/nextcloud-mcp-server/issues</bugs>
|
||||||
<repository type="git">https://github.com/cbcoutinho/nextcloud-mcp-server</repository>
|
<repository type="git">https://github.com/cbcoutinho/nextcloud-mcp-server</repository>
|
||||||
@@ -41,16 +41,16 @@ See [documentation](https://github.com/cbcoutinho/nextcloud-mcp-server) for conf
|
|||||||
<nextcloud min-version="30" max-version="32"/>
|
<nextcloud min-version="30" max-version="32"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<settings>
|
<settings>
|
||||||
<personal>OCA\Astroglobe\Settings\Personal</personal>
|
<personal>OCA\Astrolabe\Settings\Personal</personal>
|
||||||
<personal-section>OCA\Astroglobe\Settings\PersonalSection</personal-section>
|
<personal-section>OCA\Astrolabe\Settings\PersonalSection</personal-section>
|
||||||
<admin>OCA\Astroglobe\Settings\Admin</admin>
|
<admin>OCA\Astrolabe\Settings\Admin</admin>
|
||||||
<admin-section>OCA\Astroglobe\Settings\AdminSection</admin-section>
|
<admin-section>OCA\Astrolabe\Settings\AdminSection</admin-section>
|
||||||
</settings>
|
</settings>
|
||||||
<navigations>
|
<navigations>
|
||||||
<navigation>
|
<navigation>
|
||||||
<id>astroglobe</id>
|
<id>astrolabe</id>
|
||||||
<name>Astroglobe</name>
|
<name>Astrolabe</name>
|
||||||
<route>astroglobe.page.index</route>
|
<route>astrolabe.page.index</route>
|
||||||
<icon>app.svg</icon>
|
<icon>app.svg</icon>
|
||||||
<type>link</type>
|
<type>link</type>
|
||||||
</navigation>
|
</navigation>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "nextcloud/astroglobe",
|
"name": "nextcloud/astrolabe",
|
||||||
"description": "This app provides a management UI for the Nextcloud MCP Server",
|
"description": "This app provides a management UI for the Nextcloud MCP Server",
|
||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
"authors": [
|
"authors": [
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
],
|
],
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"OCA\\Astroglobe\\": "lib/"
|
"OCA\\Astrolabe\\": "lib/"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
+3
-3
@@ -2,16 +2,16 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace OCA\Astroglobe\AppInfo;
|
namespace OCA\Astrolabe\AppInfo;
|
||||||
|
|
||||||
use OCA\Astroglobe\Search\SemanticSearchProvider;
|
use OCA\Astrolabe\Search\SemanticSearchProvider;
|
||||||
use OCP\AppFramework\App;
|
use OCP\AppFramework\App;
|
||||||
use OCP\AppFramework\Bootstrap\IBootContext;
|
use OCP\AppFramework\Bootstrap\IBootContext;
|
||||||
use OCP\AppFramework\Bootstrap\IBootstrap;
|
use OCP\AppFramework\Bootstrap\IBootstrap;
|
||||||
use OCP\AppFramework\Bootstrap\IRegistrationContext;
|
use OCP\AppFramework\Bootstrap\IRegistrationContext;
|
||||||
|
|
||||||
class Application extends App implements IBootstrap {
|
class Application extends App implements IBootstrap {
|
||||||
public const APP_ID = 'astroglobe';
|
public const APP_ID = 'astrolabe';
|
||||||
|
|
||||||
/** @psalm-suppress PossiblyUnusedMethod */
|
/** @psalm-suppress PossiblyUnusedMethod */
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
+9
-9
@@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace OCA\Astroglobe\Controller;
|
namespace OCA\Astrolabe\Controller;
|
||||||
|
|
||||||
use OCA\Astroglobe\Service\IdpTokenRefresher;
|
use OCA\Astrolabe\Service\IdpTokenRefresher;
|
||||||
use OCA\Astroglobe\Service\McpServerClient;
|
use OCA\Astrolabe\Service\McpServerClient;
|
||||||
use OCA\Astroglobe\Service\McpTokenStorage;
|
use OCA\Astrolabe\Service\McpTokenStorage;
|
||||||
use OCA\Astroglobe\Service\WebhookPresets;
|
use OCA\Astrolabe\Service\WebhookPresets;
|
||||||
use OCA\Astroglobe\Settings\Admin as AdminSettings;
|
use OCA\Astrolabe\Settings\Admin as AdminSettings;
|
||||||
use OCP\AppFramework\Controller;
|
use OCP\AppFramework\Controller;
|
||||||
use OCP\AppFramework\Http;
|
use OCP\AppFramework\Http;
|
||||||
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
|
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
|
||||||
@@ -70,7 +70,7 @@ class ApiController extends Controller {
|
|||||||
// Should not happen (NoAdminRequired ensures user is logged in)
|
// Should not happen (NoAdminRequired ensures user is logged in)
|
||||||
$this->logger->error('Revoke access called without authenticated user');
|
$this->logger->error('Revoke access called without authenticated user');
|
||||||
return new RedirectResponse(
|
return new RedirectResponse(
|
||||||
$this->urlGenerator->linkToRoute('settings.PersonalSettings.index', ['section' => 'astroglobe'])
|
$this->urlGenerator->linkToRoute('settings.PersonalSettings.index', ['section' => 'astrolabe'])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ class ApiController extends Controller {
|
|||||||
if (!$token) {
|
if (!$token) {
|
||||||
$this->logger->error("Cannot revoke access: No token found for user $userId");
|
$this->logger->error("Cannot revoke access: No token found for user $userId");
|
||||||
return new RedirectResponse(
|
return new RedirectResponse(
|
||||||
$this->urlGenerator->linkToRoute('settings.PersonalSettings.index', ['section' => 'astroglobe'])
|
$this->urlGenerator->linkToRoute('settings.PersonalSettings.index', ['section' => 'astrolabe'])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ class ApiController extends Controller {
|
|||||||
|
|
||||||
// Redirect back to personal settings
|
// Redirect back to personal settings
|
||||||
return new RedirectResponse(
|
return new RedirectResponse(
|
||||||
$this->urlGenerator->linkToRoute('settings.PersonalSettings.index', ['section' => 'astroglobe'])
|
$this->urlGenerator->linkToRoute('settings.PersonalSettings.index', ['section' => 'astrolabe'])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
+14
-14
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace OCA\Astroglobe\Controller;
|
namespace OCA\Astrolabe\Controller;
|
||||||
|
|
||||||
use OCA\Astroglobe\Service\McpServerClient;
|
use OCA\Astrolabe\Service\McpServerClient;
|
||||||
use OCA\Astroglobe\Service\McpTokenStorage;
|
use OCA\Astrolabe\Service\McpTokenStorage;
|
||||||
use OCP\AppFramework\Controller;
|
use OCP\AppFramework\Controller;
|
||||||
use OCP\AppFramework\Http;
|
use OCP\AppFramework\Http;
|
||||||
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
|
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
|
||||||
@@ -83,7 +83,7 @@ class OAuthController extends Controller {
|
|||||||
if (!$user) {
|
if (!$user) {
|
||||||
$this->logger->error('initiateOAuth: User not authenticated');
|
$this->logger->error('initiateOAuth: User not authenticated');
|
||||||
return new TemplateResponse(
|
return new TemplateResponse(
|
||||||
'astroglobe',
|
'astrolabe',
|
||||||
'settings/error',
|
'settings/error',
|
||||||
['error' => $this->l->t('User not authenticated')]
|
['error' => $this->l->t('User not authenticated')]
|
||||||
);
|
);
|
||||||
@@ -99,7 +99,7 @@ class OAuthController extends Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if confidential client secret is configured
|
// Check if confidential client secret is configured
|
||||||
$clientSecret = $this->config->getSystemValue('astroglobe_client_secret', '');
|
$clientSecret = $this->config->getSystemValue('astrolabe_client_secret', '');
|
||||||
$isConfidentialClient = !empty($clientSecret);
|
$isConfidentialClient = !empty($clientSecret);
|
||||||
|
|
||||||
// Generate PKCE values only for public clients
|
// Generate PKCE values only for public clients
|
||||||
@@ -142,7 +142,7 @@ class OAuthController extends Controller {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
return new TemplateResponse(
|
return new TemplateResponse(
|
||||||
'astroglobe',
|
'astrolabe',
|
||||||
'settings/error',
|
'settings/error',
|
||||||
['error' => $this->l->t('Failed to initiate OAuth: %s', [$e->getMessage()])]
|
['error' => $this->l->t('Failed to initiate OAuth: %s', [$e->getMessage()])]
|
||||||
);
|
);
|
||||||
@@ -185,7 +185,7 @@ class OAuthController extends Controller {
|
|||||||
$codeVerifier = $this->session->get('mcp_oauth_code_verifier');
|
$codeVerifier = $this->session->get('mcp_oauth_code_verifier');
|
||||||
|
|
||||||
// Check if we have either client_secret or code_verifier
|
// Check if we have either client_secret or code_verifier
|
||||||
$clientSecret = $this->config->getSystemValue('astroglobe_client_secret', '');
|
$clientSecret = $this->config->getSystemValue('astrolabe_client_secret', '');
|
||||||
if (empty($clientSecret) && empty($codeVerifier)) {
|
if (empty($clientSecret) && empty($codeVerifier)) {
|
||||||
throw new \Exception('Neither client secret nor code verifier available for authentication');
|
throw new \Exception('Neither client secret nor code verifier available for authentication');
|
||||||
}
|
}
|
||||||
@@ -226,7 +226,7 @@ class OAuthController extends Controller {
|
|||||||
|
|
||||||
// Redirect back to personal settings
|
// Redirect back to personal settings
|
||||||
return new RedirectResponse(
|
return new RedirectResponse(
|
||||||
$this->urlGenerator->linkToRoute('settings.PersonalSettings.index', ['section' => 'astroglobe'])
|
$this->urlGenerator->linkToRoute('settings.PersonalSettings.index', ['section' => 'astrolabe'])
|
||||||
);
|
);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$this->logger->error('OAuth callback failed', [
|
$this->logger->error('OAuth callback failed', [
|
||||||
@@ -241,7 +241,7 @@ class OAuthController extends Controller {
|
|||||||
// Redirect to settings with error
|
// Redirect to settings with error
|
||||||
return new RedirectResponse(
|
return new RedirectResponse(
|
||||||
$this->urlGenerator->linkToRoute('settings.PersonalSettings.index', [
|
$this->urlGenerator->linkToRoute('settings.PersonalSettings.index', [
|
||||||
'section' => 'astroglobe',
|
'section' => 'astrolabe',
|
||||||
'error' => urlencode($e->getMessage())
|
'error' => urlencode($e->getMessage())
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
@@ -260,7 +260,7 @@ class OAuthController extends Controller {
|
|||||||
$user = $this->userSession->getUser();
|
$user = $this->userSession->getUser();
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
return new RedirectResponse(
|
return new RedirectResponse(
|
||||||
$this->urlGenerator->linkToRoute('settings.PersonalSettings.index', ['section' => 'astroglobe'])
|
$this->urlGenerator->linkToRoute('settings.PersonalSettings.index', ['section' => 'astrolabe'])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,7 +276,7 @@ class OAuthController extends Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return new RedirectResponse(
|
return new RedirectResponse(
|
||||||
$this->urlGenerator->linkToRoute('settings.PersonalSettings.index', ['section' => 'astroglobe'])
|
$this->urlGenerator->linkToRoute('settings.PersonalSettings.index', ['section' => 'astrolabe'])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,7 +390,7 @@ class OAuthController extends Controller {
|
|||||||
|
|
||||||
// Build callback URL
|
// Build callback URL
|
||||||
$redirectUri = $this->urlGenerator->linkToRouteAbsolute(
|
$redirectUri = $this->urlGenerator->linkToRouteAbsolute(
|
||||||
'astroglobe.oauth.oauthCallback'
|
'astrolabe.oauth.oauthCallback'
|
||||||
);
|
);
|
||||||
|
|
||||||
// Get public MCP server URL for token audience (RFC 8707 Resource Indicator)
|
// Get public MCP server URL for token audience (RFC 8707 Resource Indicator)
|
||||||
@@ -483,7 +483,7 @@ class OAuthController extends Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$redirectUri = $this->urlGenerator->linkToRouteAbsolute(
|
$redirectUri = $this->urlGenerator->linkToRouteAbsolute(
|
||||||
'astroglobe.oauth.oauthCallback'
|
'astrolabe.oauth.oauthCallback'
|
||||||
);
|
);
|
||||||
|
|
||||||
// Build token request parameters
|
// Build token request parameters
|
||||||
@@ -495,7 +495,7 @@ class OAuthController extends Controller {
|
|||||||
];
|
];
|
||||||
|
|
||||||
// Add client authentication based on client type
|
// Add client authentication based on client type
|
||||||
$clientSecret = $this->config->getSystemValue('astroglobe_client_secret', '');
|
$clientSecret = $this->config->getSystemValue('astrolabe_client_secret', '');
|
||||||
|
|
||||||
if (!empty($clientSecret)) {
|
if (!empty($clientSecret)) {
|
||||||
// Confidential client: use client secret for authentication
|
// Confidential client: use client secret for authentication
|
||||||
+2
-2
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace OCA\Astroglobe\Controller;
|
namespace OCA\Astrolabe\Controller;
|
||||||
|
|
||||||
use OCA\Astroglobe\AppInfo\Application;
|
use OCA\Astrolabe\AppInfo\Application;
|
||||||
use OCP\AppFramework\Controller;
|
use OCP\AppFramework\Controller;
|
||||||
use OCP\AppFramework\Http\Attribute\FrontpageRoute;
|
use OCP\AppFramework\Http\Attribute\FrontpageRoute;
|
||||||
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
|
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
|
||||||
+7
-7
@@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace OCA\Astroglobe\Search;
|
namespace OCA\Astrolabe\Search;
|
||||||
|
|
||||||
use OCA\Astroglobe\AppInfo\Application;
|
use OCA\Astrolabe\AppInfo\Application;
|
||||||
use OCA\Astroglobe\Service\McpServerClient;
|
use OCA\Astrolabe\Service\McpServerClient;
|
||||||
use OCA\Astroglobe\Service\McpTokenStorage;
|
use OCA\Astrolabe\Service\McpTokenStorage;
|
||||||
use OCA\Astroglobe\Settings\Admin as AdminSettings;
|
use OCA\Astrolabe\Settings\Admin as AdminSettings;
|
||||||
use OCP\Files\FileInfo;
|
use OCP\Files\FileInfo;
|
||||||
use OCP\Files\IMimeTypeDetector;
|
use OCP\Files\IMimeTypeDetector;
|
||||||
use OCP\IConfig;
|
use OCP\IConfig;
|
||||||
@@ -55,7 +55,7 @@ class SemanticSearchProvider implements IProvider {
|
|||||||
* Display name shown in search results grouping.
|
* Display name shown in search results grouping.
|
||||||
*/
|
*/
|
||||||
public function getName(): string {
|
public function getName(): string {
|
||||||
return $this->l10n->t('Astroglobe');
|
return $this->l10n->t('Astrolabe');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -64,7 +64,7 @@ class SemanticSearchProvider implements IProvider {
|
|||||||
*/
|
*/
|
||||||
public function getOrder(string $route, array $routeParameters): int {
|
public function getOrder(string $route, array $routeParameters): int {
|
||||||
if (str_contains($route, Application::APP_ID)) {
|
if (str_contains($route, Application::APP_ID)) {
|
||||||
return -1; // Prioritize when in Astroglobe app
|
return -1; // Prioritize when in Astrolabe app
|
||||||
}
|
}
|
||||||
return 40; // Above most apps, below files/mail
|
return 40; // Above most apps, below files/mail
|
||||||
}
|
}
|
||||||
+2
-2
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace OCA\Astroglobe\Service;
|
namespace OCA\Astrolabe\Service;
|
||||||
|
|
||||||
use OCP\Http\Client\IClientService;
|
use OCP\Http\Client\IClientService;
|
||||||
use OCP\IConfig;
|
use OCP\IConfig;
|
||||||
@@ -45,7 +45,7 @@ class IdpTokenRefresher {
|
|||||||
*/
|
*/
|
||||||
public function refreshAccessToken(string $refreshToken): ?array {
|
public function refreshAccessToken(string $refreshToken): ?array {
|
||||||
// Check if confidential client secret is configured
|
// Check if confidential client secret is configured
|
||||||
$clientSecret = $this->config->getSystemValue('astroglobe_client_secret', '');
|
$clientSecret = $this->config->getSystemValue('astrolabe_client_secret', '');
|
||||||
|
|
||||||
if (empty($clientSecret)) {
|
if (empty($clientSecret)) {
|
||||||
$this->logger->warning('Cannot refresh: no client secret configured. Confidential client required for token refresh.');
|
$this->logger->warning('Cannot refresh: no client secret configured. Confidential client required for token refresh.');
|
||||||
+4
-4
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace OCA\Astroglobe\Service;
|
namespace OCA\Astrolabe\Service;
|
||||||
|
|
||||||
use OCP\Http\Client\IClientService;
|
use OCP\Http\Client\IClientService;
|
||||||
use OCP\IConfig;
|
use OCP\IConfig;
|
||||||
@@ -355,16 +355,16 @@ class McpServerClient {
|
|||||||
/**
|
/**
|
||||||
* Get the OAuth client ID from system config.
|
* Get the OAuth client ID from system config.
|
||||||
*
|
*
|
||||||
* The Astroglobe app has its own OAuth client (separate from MCP server's client).
|
* The Astrolabe app has its own OAuth client (separate from MCP server's client).
|
||||||
* Client ID must be configured in config.php for OAuth functionality to work.
|
* Client ID must be configured in config.php for OAuth functionality to work.
|
||||||
*
|
*
|
||||||
* @return string OAuth client ID or empty string if not configured
|
* @return string OAuth client ID or empty string if not configured
|
||||||
*/
|
*/
|
||||||
public function getClientId(): string {
|
public function getClientId(): string {
|
||||||
$clientId = $this->config->getSystemValue('astroglobe_client_id', '');
|
$clientId = $this->config->getSystemValue('astrolabe_client_id', '');
|
||||||
|
|
||||||
if (empty($clientId)) {
|
if (empty($clientId)) {
|
||||||
$this->logger->warning('astroglobe_client_id is not configured in config.php - OAuth functionality will not work');
|
$this->logger->warning('astrolabe_client_id is not configured in config.php - OAuth functionality will not work');
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
+4
-4
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace OCA\Astroglobe\Service;
|
namespace OCA\Astrolabe\Service;
|
||||||
|
|
||||||
use OCP\IConfig;
|
use OCP\IConfig;
|
||||||
use OCP\Security\ICrypto;
|
use OCP\Security\ICrypto;
|
||||||
@@ -58,7 +58,7 @@ class McpTokenStorage {
|
|||||||
// Store in user preferences
|
// Store in user preferences
|
||||||
$this->config->setUserValue(
|
$this->config->setUserValue(
|
||||||
$userId,
|
$userId,
|
||||||
'astroglobe',
|
'astrolabe',
|
||||||
'oauth_tokens',
|
'oauth_tokens',
|
||||||
$encrypted
|
$encrypted
|
||||||
);
|
);
|
||||||
@@ -82,7 +82,7 @@ class McpTokenStorage {
|
|||||||
try {
|
try {
|
||||||
$encrypted = $this->config->getUserValue(
|
$encrypted = $this->config->getUserValue(
|
||||||
$userId,
|
$userId,
|
||||||
'astroglobe',
|
'astrolabe',
|
||||||
'oauth_tokens',
|
'oauth_tokens',
|
||||||
''
|
''
|
||||||
);
|
);
|
||||||
@@ -137,7 +137,7 @@ class McpTokenStorage {
|
|||||||
try {
|
try {
|
||||||
$this->config->deleteUserValue(
|
$this->config->deleteUserValue(
|
||||||
$userId,
|
$userId,
|
||||||
'astroglobe',
|
'astrolabe',
|
||||||
'oauth_tokens'
|
'oauth_tokens'
|
||||||
);
|
);
|
||||||
|
|
||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace OCA\Astroglobe\Service;
|
namespace OCA\Astrolabe\Service;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Webhook preset configurations for common sync scenarios.
|
* Webhook preset configurations for common sync scenarios.
|
||||||
Vendored
+7
-7
@@ -2,17 +2,17 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace OCA\Astroglobe\Settings;
|
namespace OCA\Astrolabe\Settings;
|
||||||
|
|
||||||
use OCA\Astroglobe\AppInfo\Application;
|
use OCA\Astrolabe\AppInfo\Application;
|
||||||
use OCA\Astroglobe\Service\McpServerClient;
|
use OCA\Astrolabe\Service\McpServerClient;
|
||||||
use OCP\AppFramework\Http\TemplateResponse;
|
use OCP\AppFramework\Http\TemplateResponse;
|
||||||
use OCP\AppFramework\Services\IInitialState;
|
use OCP\AppFramework\Services\IInitialState;
|
||||||
use OCP\IConfig;
|
use OCP\IConfig;
|
||||||
use OCP\Settings\ISettings;
|
use OCP\Settings\ISettings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Admin settings panel for Astroglobe.
|
* Admin settings panel for Astrolabe.
|
||||||
*
|
*
|
||||||
* Displays semantic search service status, indexing metrics,
|
* Displays semantic search service status, indexing metrics,
|
||||||
* configuration, and provides administrative controls.
|
* configuration, and provides administrative controls.
|
||||||
@@ -54,9 +54,9 @@ class Admin implements ISettings {
|
|||||||
// Get configuration from config.php
|
// Get configuration from config.php
|
||||||
$serverUrl = $this->config->getSystemValue('mcp_server_url', '');
|
$serverUrl = $this->config->getSystemValue('mcp_server_url', '');
|
||||||
$apiKeyConfigured = !empty($this->config->getSystemValue('mcp_server_api_key', ''));
|
$apiKeyConfigured = !empty($this->config->getSystemValue('mcp_server_api_key', ''));
|
||||||
$clientId = $this->config->getSystemValue('astroglobe_client_id', '');
|
$clientId = $this->config->getSystemValue('astrolabe_client_id', '');
|
||||||
$clientIdConfigured = !empty($clientId);
|
$clientIdConfigured = !empty($clientId);
|
||||||
$clientSecret = $this->config->getSystemValue('astroglobe_client_secret', '');
|
$clientSecret = $this->config->getSystemValue('astrolabe_client_secret', '');
|
||||||
$clientSecretConfigured = !empty($clientSecret);
|
$clientSecretConfigured = !empty($clientSecret);
|
||||||
|
|
||||||
// Check for server connection error
|
// Check for server connection error
|
||||||
@@ -132,7 +132,7 @@ class Admin implements ISettings {
|
|||||||
* @return string The section ID
|
* @return string The section ID
|
||||||
*/
|
*/
|
||||||
public function getSection(): string {
|
public function getSection(): string {
|
||||||
return 'astroglobe';
|
return 'astrolabe';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
+5
-5
@@ -2,14 +2,14 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace OCA\Astroglobe\Settings;
|
namespace OCA\Astrolabe\Settings;
|
||||||
|
|
||||||
use OCP\IL10N;
|
use OCP\IL10N;
|
||||||
use OCP\IURLGenerator;
|
use OCP\IURLGenerator;
|
||||||
use OCP\Settings\IIconSection;
|
use OCP\Settings\IIconSection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Admin settings section for Astroglobe.
|
* Admin settings section for Astrolabe.
|
||||||
*
|
*
|
||||||
* Creates a dedicated section in admin settings for semantic search administration.
|
* Creates a dedicated section in admin settings for semantic search administration.
|
||||||
*/
|
*/
|
||||||
@@ -26,14 +26,14 @@ class AdminSection implements IIconSection {
|
|||||||
* @return string The section ID
|
* @return string The section ID
|
||||||
*/
|
*/
|
||||||
public function getID(): string {
|
public function getID(): string {
|
||||||
return 'astroglobe';
|
return 'astrolabe';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string The translated section name
|
* @return string The translated section name
|
||||||
*/
|
*/
|
||||||
public function getName(): string {
|
public function getName(): string {
|
||||||
return $this->l->t('Astroglobe');
|
return $this->l->t('Astrolabe');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,6 +47,6 @@ class AdminSection implements IIconSection {
|
|||||||
* @return string Section icon (SVG or image URL)
|
* @return string Section icon (SVG or image URL)
|
||||||
*/
|
*/
|
||||||
public function getIcon(): string {
|
public function getIcon(): string {
|
||||||
return $this->urlGenerator->imagePath('astroglobe', 'app-dark.svg');
|
return $this->urlGenerator->imagePath('astrolabe', 'app-dark.svg');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Vendored
+8
-8
@@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace OCA\Astroglobe\Settings;
|
namespace OCA\Astrolabe\Settings;
|
||||||
|
|
||||||
use OCA\Astroglobe\AppInfo\Application;
|
use OCA\Astrolabe\AppInfo\Application;
|
||||||
use OCA\Astroglobe\Service\McpServerClient;
|
use OCA\Astrolabe\Service\McpServerClient;
|
||||||
use OCA\Astroglobe\Service\McpTokenStorage;
|
use OCA\Astrolabe\Service\McpTokenStorage;
|
||||||
use OCP\AppFramework\Http\TemplateResponse;
|
use OCP\AppFramework\Http\TemplateResponse;
|
||||||
use OCP\AppFramework\Services\IInitialState;
|
use OCP\AppFramework\Services\IInitialState;
|
||||||
use OCP\IURLGenerator;
|
use OCP\IURLGenerator;
|
||||||
@@ -14,7 +14,7 @@ use OCP\IUserSession;
|
|||||||
use OCP\Settings\ISettings;
|
use OCP\Settings\ISettings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Personal settings panel for Astroglobe.
|
* Personal settings panel for Astrolabe.
|
||||||
*
|
*
|
||||||
* Displays semantic search status, background indexing access,
|
* Displays semantic search status, background indexing access,
|
||||||
* and provides controls for managing content indexing.
|
* and provides controls for managing content indexing.
|
||||||
@@ -60,7 +60,7 @@ class Personal implements ISettings {
|
|||||||
|
|
||||||
// If no token or token is expired, show OAuth authorization UI
|
// If no token or token is expired, show OAuth authorization UI
|
||||||
if (!$token || $this->tokenStorage->isExpired($token)) {
|
if (!$token || $this->tokenStorage->isExpired($token)) {
|
||||||
$oauthUrl = $this->urlGenerator->linkToRoute('astroglobe.oauth.initiateOAuth');
|
$oauthUrl = $this->urlGenerator->linkToRoute('astrolabe.oauth.initiateOAuth');
|
||||||
|
|
||||||
return new TemplateResponse(
|
return new TemplateResponse(
|
||||||
Application::APP_ID,
|
Application::APP_ID,
|
||||||
@@ -102,7 +102,7 @@ class Personal implements ISettings {
|
|||||||
// Token might be invalid - delete it and show OAuth UI
|
// Token might be invalid - delete it and show OAuth UI
|
||||||
$this->tokenStorage->deleteUserToken($userId);
|
$this->tokenStorage->deleteUserToken($userId);
|
||||||
|
|
||||||
$oauthUrl = $this->urlGenerator->linkToRoute('astroglobe.oauth.initiateOAuth');
|
$oauthUrl = $this->urlGenerator->linkToRoute('astrolabe.oauth.initiateOAuth');
|
||||||
|
|
||||||
return new TemplateResponse(
|
return new TemplateResponse(
|
||||||
Application::APP_ID,
|
Application::APP_ID,
|
||||||
@@ -146,7 +146,7 @@ class Personal implements ISettings {
|
|||||||
* @return string The section ID
|
* @return string The section ID
|
||||||
*/
|
*/
|
||||||
public function getSection(): string {
|
public function getSection(): string {
|
||||||
return 'astroglobe';
|
return 'astrolabe';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
+5
-5
@@ -2,14 +2,14 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace OCA\Astroglobe\Settings;
|
namespace OCA\Astrolabe\Settings;
|
||||||
|
|
||||||
use OCP\IL10N;
|
use OCP\IL10N;
|
||||||
use OCP\IURLGenerator;
|
use OCP\IURLGenerator;
|
||||||
use OCP\Settings\IIconSection;
|
use OCP\Settings\IIconSection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Personal settings section for Astroglobe.
|
* Personal settings section for Astrolabe.
|
||||||
*
|
*
|
||||||
* Creates a dedicated section in personal settings for semantic search configuration.
|
* Creates a dedicated section in personal settings for semantic search configuration.
|
||||||
*/
|
*/
|
||||||
@@ -26,14 +26,14 @@ class PersonalSection implements IIconSection {
|
|||||||
* @return string The section ID
|
* @return string The section ID
|
||||||
*/
|
*/
|
||||||
public function getID(): string {
|
public function getID(): string {
|
||||||
return 'astroglobe';
|
return 'astrolabe';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string The translated section name
|
* @return string The translated section name
|
||||||
*/
|
*/
|
||||||
public function getName(): string {
|
public function getName(): string {
|
||||||
return $this->l->t('Astroglobe');
|
return $this->l->t('Astrolabe');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,6 +47,6 @@ class PersonalSection implements IIconSection {
|
|||||||
* @return string Section icon (SVG or image URL)
|
* @return string Section icon (SVG or image URL)
|
||||||
*/
|
*/
|
||||||
public function getIcon(): string {
|
public function getIcon(): string {
|
||||||
return $this->urlGenerator->imagePath('astroglobe', 'app-dark.svg');
|
return $this->urlGenerator->imagePath('astrolabe', 'app-dark.svg');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"openapi": "3.0.3",
|
"openapi": "3.0.3",
|
||||||
"info": {
|
"info": {
|
||||||
"title": "astroglobe",
|
"title": "astrolabe",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"description": "Manage the MCP Server from within Nextcloud UI",
|
"description": "Manage the MCP Server from within Nextcloud UI",
|
||||||
"license": {
|
"license": {
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"paths": {
|
"paths": {
|
||||||
"/ocs/v2.php/apps/astroglobe/api": {
|
"/ocs/v2.php/apps/astrolabe/api": {
|
||||||
"get": {
|
"get": {
|
||||||
"operationId": "api-index",
|
"operationId": "api-index",
|
||||||
"summary": "An example API endpoint",
|
"summary": "An example API endpoint",
|
||||||
Generated
Vendored
+2
-2
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "astroglobe",
|
"name": "astrolabe",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "astroglobe",
|
"name": "astrolabe",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "astroglobe",
|
"name": "astrolabe",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<NcContent app-name="astroglobe">
|
<NcContent app-name="astrolabe">
|
||||||
<NcAppNavigation>
|
<NcAppNavigation>
|
||||||
<template #list>
|
<template #list>
|
||||||
<NcAppNavigationItem
|
<NcAppNavigationItem
|
||||||
:name="t('astroglobe', 'Semantic Search')"
|
:name="t('astrolabe', 'Semantic Search')"
|
||||||
:active="activeSection === 'search'"
|
:active="activeSection === 'search'"
|
||||||
@click="activeSection = 'search'">
|
@click="activeSection = 'search'">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
</NcAppNavigationItem>
|
</NcAppNavigationItem>
|
||||||
|
|
||||||
<NcAppNavigationItem
|
<NcAppNavigationItem
|
||||||
:name="t('astroglobe', 'Index Status')"
|
:name="t('astrolabe', 'Index Status')"
|
||||||
:active="activeSection === 'status'"
|
:active="activeSection === 'status'"
|
||||||
@click="activeSection = 'status'; loadVectorStatus()">
|
@click="activeSection = 'status'; loadVectorStatus()">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
<template #footer>
|
<template #footer>
|
||||||
<ul class="app-navigation-entry__settings">
|
<ul class="app-navigation-entry__settings">
|
||||||
<NcAppNavigationItem
|
<NcAppNavigationItem
|
||||||
:name="t('astroglobe', 'Settings')"
|
:name="t('astrolabe', 'Settings')"
|
||||||
@click="goToSettings">
|
@click="goToSettings">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<Cog :size="20" />
|
<Cog :size="20" />
|
||||||
@@ -38,9 +38,9 @@
|
|||||||
<!-- Search Section -->
|
<!-- Search Section -->
|
||||||
<div v-show="activeSection === 'search'" class="mcp-section">
|
<div v-show="activeSection === 'search'" class="mcp-section">
|
||||||
<div class="mcp-section-header">
|
<div class="mcp-section-header">
|
||||||
<h2>{{ t('astroglobe', 'Semantic Search') }}</h2>
|
<h2>{{ t('astrolabe', 'Semantic Search') }}</h2>
|
||||||
<p class="mcp-description">
|
<p class="mcp-description">
|
||||||
{{ t('astroglobe', 'Search your indexed content using semantic similarity. Find documents by meaning, not just keywords.') }}
|
{{ t('astrolabe', 'Search your indexed content using semantic similarity. Find documents by meaning, not just keywords.') }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -49,15 +49,15 @@
|
|||||||
<div class="mcp-search-row">
|
<div class="mcp-search-row">
|
||||||
<NcTextField
|
<NcTextField
|
||||||
:value.sync="query"
|
:value.sync="query"
|
||||||
:label="t('astroglobe', 'Search query')"
|
:label="t('astrolabe', 'Search query')"
|
||||||
:placeholder="t('astroglobe', 'Enter your search query...')"
|
:placeholder="t('astrolabe', 'Enter your search query...')"
|
||||||
class="mcp-search-input"
|
class="mcp-search-input"
|
||||||
@keyup.enter="performSearch" />
|
@keyup.enter="performSearch" />
|
||||||
|
|
||||||
<NcSelect
|
<NcSelect
|
||||||
v-model="selectedAlgorithmOption"
|
v-model="selectedAlgorithmOption"
|
||||||
:options="algorithmOptions"
|
:options="algorithmOptions"
|
||||||
:placeholder="t('astroglobe', 'Algorithm')"
|
:placeholder="t('astrolabe', 'Algorithm')"
|
||||||
class="mcp-algorithm-select"
|
class="mcp-algorithm-select"
|
||||||
@input="algorithm = $event ? $event.id : 'hybrid'" />
|
@input="algorithm = $event ? $event.id : 'hybrid'" />
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
<template #icon>
|
<template #icon>
|
||||||
<Magnify :size="20" />
|
<Magnify :size="20" />
|
||||||
</template>
|
</template>
|
||||||
{{ t('astroglobe', 'Search') }}
|
{{ t('astrolabe', 'Search') }}
|
||||||
</NcButton>
|
</NcButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -81,14 +81,14 @@
|
|||||||
<ChevronDown v-if="!showAdvanced" :size="20" />
|
<ChevronDown v-if="!showAdvanced" :size="20" />
|
||||||
<ChevronUp v-else :size="20" />
|
<ChevronUp v-else :size="20" />
|
||||||
</template>
|
</template>
|
||||||
{{ showAdvanced ? t('astroglobe', 'Hide advanced') : t('astroglobe', 'Advanced options') }}
|
{{ showAdvanced ? t('astrolabe', 'Hide advanced') : t('astrolabe', 'Advanced options') }}
|
||||||
</NcButton>
|
</NcButton>
|
||||||
|
|
||||||
<!-- Advanced Options -->
|
<!-- Advanced Options -->
|
||||||
<div v-show="showAdvanced" class="mcp-advanced-options">
|
<div v-show="showAdvanced" class="mcp-advanced-options">
|
||||||
<div class="mcp-advanced-grid">
|
<div class="mcp-advanced-grid">
|
||||||
<div class="mcp-option-group">
|
<div class="mcp-option-group">
|
||||||
<label>{{ t('astroglobe', 'Document Types') }}</label>
|
<label>{{ t('astrolabe', 'Document Types') }}</label>
|
||||||
<div class="mcp-checkbox-grid">
|
<div class="mcp-checkbox-grid">
|
||||||
<NcCheckboxRadioSwitch
|
<NcCheckboxRadioSwitch
|
||||||
v-for="docType in docTypeOptions"
|
v-for="docType in docTypeOptions"
|
||||||
@@ -102,7 +102,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mcp-option-group">
|
<div class="mcp-option-group">
|
||||||
<label>{{ t('astroglobe', 'Result Limit') }}</label>
|
<label>{{ t('astrolabe', 'Result Limit') }}</label>
|
||||||
<NcTextField
|
<NcTextField
|
||||||
:value.sync="limit"
|
:value.sync="limit"
|
||||||
type="number"
|
type="number"
|
||||||
@@ -111,7 +111,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mcp-option-group">
|
<div class="mcp-option-group">
|
||||||
<label>{{ t('astroglobe', 'Minimum Score') }}: {{ scoreThreshold }}%</label>
|
<label>{{ t('astrolabe', 'Minimum Score') }}: {{ scoreThreshold }}%</label>
|
||||||
<input
|
<input
|
||||||
v-model="scoreThreshold"
|
v-model="scoreThreshold"
|
||||||
type="range"
|
type="range"
|
||||||
@@ -127,7 +127,7 @@
|
|||||||
<!-- Loading State -->
|
<!-- Loading State -->
|
||||||
<div v-if="loading" class="mcp-loading">
|
<div v-if="loading" class="mcp-loading">
|
||||||
<NcLoadingIcon :size="32" />
|
<NcLoadingIcon :size="32" />
|
||||||
<span>{{ t('astroglobe', 'Searching...') }}</span>
|
<span>{{ t('astrolabe', 'Searching...') }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Error State -->
|
<!-- Error State -->
|
||||||
@@ -139,9 +139,9 @@
|
|||||||
<div v-if="results.length > 0 && !loading" class="mcp-results">
|
<div v-if="results.length > 0 && !loading" class="mcp-results">
|
||||||
<div class="mcp-results-header">
|
<div class="mcp-results-header">
|
||||||
<span>
|
<span>
|
||||||
{{ filteredResults.length }} {{ t('astroglobe', 'results') }}
|
{{ filteredResults.length }} {{ t('astrolabe', 'results') }}
|
||||||
<span v-if="filteredResults.length !== results.length" class="mcp-filter-info">
|
<span v-if="filteredResults.length !== results.length" class="mcp-filter-info">
|
||||||
({{ results.length - filteredResults.length }} {{ t('astroglobe', 'filtered by score') }})
|
({{ results.length - filteredResults.length }} {{ t('astrolabe', 'filtered by score') }})
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<span class="mcp-algorithm-badge">{{ algorithmUsed }}</span>
|
<span class="mcp-algorithm-badge">{{ algorithmUsed }}</span>
|
||||||
@@ -150,12 +150,12 @@
|
|||||||
<!-- 3D Visualization -->
|
<!-- 3D Visualization -->
|
||||||
<div v-if="coordinates.length > 0" class="mcp-viz-container">
|
<div v-if="coordinates.length > 0" class="mcp-viz-container">
|
||||||
<div class="mcp-viz-header">
|
<div class="mcp-viz-header">
|
||||||
<h3>{{ t('astroglobe', 'Vector Space Visualization') }}</h3>
|
<h3>{{ t('astrolabe', 'Vector Space Visualization') }}</h3>
|
||||||
<NcCheckboxRadioSwitch
|
<NcCheckboxRadioSwitch
|
||||||
:checked.sync="showQueryPoint"
|
:checked.sync="showQueryPoint"
|
||||||
type="switch"
|
type="switch"
|
||||||
@update:checked="updatePlot">
|
@update:checked="updatePlot">
|
||||||
{{ t('astroglobe', 'Show query point') }}
|
{{ t('astrolabe', 'Show query point') }}
|
||||||
</NcCheckboxRadioSwitch>
|
</NcCheckboxRadioSwitch>
|
||||||
</div>
|
</div>
|
||||||
<div id="viz-plot-container" class="mcp-viz-plot-container">
|
<div id="viz-plot-container" class="mcp-viz-plot-container">
|
||||||
@@ -174,12 +174,12 @@
|
|||||||
<div class="mcp-result-actions">
|
<div class="mcp-result-actions">
|
||||||
<NcButton
|
<NcButton
|
||||||
type="tertiary"
|
type="tertiary"
|
||||||
:aria-label="t('astroglobe', 'Show Chunk')"
|
:aria-label="t('astrolabe', 'Show Chunk')"
|
||||||
@click="viewChunk(result)">
|
@click="viewChunk(result)">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<Eye :size="18" />
|
<Eye :size="18" />
|
||||||
</template>
|
</template>
|
||||||
{{ t('astroglobe', 'Show Chunk') }}
|
{{ t('astrolabe', 'Show Chunk') }}
|
||||||
</NcButton>
|
</NcButton>
|
||||||
<span class="mcp-result-score">{{ formatScore(result.score) }}%</span>
|
<span class="mcp-result-score">{{ formatScore(result.score) }}%</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -188,15 +188,15 @@
|
|||||||
:href="getDocumentUrl(result)"
|
:href="getDocumentUrl(result)"
|
||||||
class="mcp-result-title"
|
class="mcp-result-title"
|
||||||
@click.prevent="navigateToDocument(result)">
|
@click.prevent="navigateToDocument(result)">
|
||||||
{{ result.title || t('astroglobe', 'Untitled') }}
|
{{ result.title || t('astrolabe', 'Untitled') }}
|
||||||
<OpenInNew :size="14" class="mcp-external-icon" />
|
<OpenInNew :size="14" class="mcp-external-icon" />
|
||||||
</a>
|
</a>
|
||||||
<div class="mcp-result-metadata">
|
<div class="mcp-result-metadata">
|
||||||
<span v-if="result.chunk_index !== undefined && result.total_chunks">
|
<span v-if="result.chunk_index !== undefined && result.total_chunks">
|
||||||
{{ t('astroglobe', 'Chunk {chunk}/{total}', { chunk: result.chunk_index + 1, total: result.total_chunks }) }}
|
{{ t('astrolabe', 'Chunk {chunk}/{total}', { chunk: result.chunk_index + 1, total: result.total_chunks }) }}
|
||||||
</span>
|
</span>
|
||||||
<span v-if="result.page_number && result.page_count" class="mcp-metadata-separator">
|
<span v-if="result.page_number && result.page_count" class="mcp-metadata-separator">
|
||||||
· {{ t('astroglobe', 'Page {page}/{total}', { page: result.page_number, total: result.page_count }) }}
|
· {{ t('astrolabe', 'Page {page}/{total}', { page: result.page_number, total: result.page_count }) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -206,8 +206,8 @@
|
|||||||
<!-- No Results -->
|
<!-- No Results -->
|
||||||
<NcEmptyContent
|
<NcEmptyContent
|
||||||
v-if="searched && results.length === 0 && !loading && !error"
|
v-if="searched && results.length === 0 && !loading && !error"
|
||||||
:name="t('astroglobe', 'No results found')"
|
:name="t('astrolabe', 'No results found')"
|
||||||
:description="t('astroglobe', 'Try a different query or search algorithm.')">
|
:description="t('astrolabe', 'Try a different query or search algorithm.')">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<Magnify />
|
<Magnify />
|
||||||
</template>
|
</template>
|
||||||
@@ -216,8 +216,8 @@
|
|||||||
<!-- Initial State -->
|
<!-- Initial State -->
|
||||||
<NcEmptyContent
|
<NcEmptyContent
|
||||||
v-if="!searched && !loading"
|
v-if="!searched && !loading"
|
||||||
:name="t('astroglobe', 'Semantic Search')"
|
:name="t('astrolabe', 'Semantic Search')"
|
||||||
:description="t('astroglobe', 'Enter a query above to search your indexed content.')">
|
:description="t('astrolabe', 'Enter a query above to search your indexed content.')">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<Magnify />
|
<Magnify />
|
||||||
</template>
|
</template>
|
||||||
@@ -227,15 +227,15 @@
|
|||||||
<!-- Index Status Section -->
|
<!-- Index Status Section -->
|
||||||
<div v-show="activeSection === 'status'" class="mcp-section">
|
<div v-show="activeSection === 'status'" class="mcp-section">
|
||||||
<div class="mcp-section-header">
|
<div class="mcp-section-header">
|
||||||
<h2>{{ t('astroglobe', 'Index Status') }}</h2>
|
<h2>{{ t('astrolabe', 'Index Status') }}</h2>
|
||||||
<p class="mcp-description">
|
<p class="mcp-description">
|
||||||
{{ t('astroglobe', 'View the status of your vector index and sync progress.') }}
|
{{ t('astrolabe', 'View the status of your vector index and sync progress.') }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="statusLoading" class="mcp-loading">
|
<div v-if="statusLoading" class="mcp-loading">
|
||||||
<NcLoadingIcon :size="32" />
|
<NcLoadingIcon :size="32" />
|
||||||
<span>{{ t('astroglobe', 'Loading status...') }}</span>
|
<span>{{ t('astrolabe', 'Loading status...') }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<NcNoteCard v-else-if="statusError" type="error">
|
<NcNoteCard v-else-if="statusError" type="error">
|
||||||
@@ -245,7 +245,7 @@
|
|||||||
<div v-else-if="vectorStatus" class="mcp-status-cards">
|
<div v-else-if="vectorStatus" class="mcp-status-cards">
|
||||||
<div class="mcp-status-card">
|
<div class="mcp-status-card">
|
||||||
<div class="mcp-status-label">
|
<div class="mcp-status-label">
|
||||||
{{ t('astroglobe', 'Sync Status') }}
|
{{ t('astrolabe', 'Sync Status') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="mcp-status-value" :class="'status-' + vectorStatus.status">
|
<div class="mcp-status-value" :class="'status-' + vectorStatus.status">
|
||||||
{{ vectorStatus.status }}
|
{{ vectorStatus.status }}
|
||||||
@@ -254,7 +254,7 @@
|
|||||||
|
|
||||||
<div class="mcp-status-card">
|
<div class="mcp-status-card">
|
||||||
<div class="mcp-status-label">
|
<div class="mcp-status-label">
|
||||||
{{ t('astroglobe', 'Indexed Documents') }}
|
{{ t('astrolabe', 'Indexed Documents') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="mcp-status-value">
|
<div class="mcp-status-value">
|
||||||
{{ vectorStatus.indexed_documents || 0 }}
|
{{ vectorStatus.indexed_documents || 0 }}
|
||||||
@@ -263,7 +263,7 @@
|
|||||||
|
|
||||||
<div class="mcp-status-card">
|
<div class="mcp-status-card">
|
||||||
<div class="mcp-status-label">
|
<div class="mcp-status-label">
|
||||||
{{ t('astroglobe', 'Pending Documents') }}
|
{{ t('astrolabe', 'Pending Documents') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="mcp-status-value">
|
<div class="mcp-status-value">
|
||||||
{{ vectorStatus.pending_documents || 0 }}
|
{{ vectorStatus.pending_documents || 0 }}
|
||||||
@@ -272,7 +272,7 @@
|
|||||||
|
|
||||||
<div v-if="vectorStatus.last_sync_time" class="mcp-status-card">
|
<div v-if="vectorStatus.last_sync_time" class="mcp-status-card">
|
||||||
<div class="mcp-status-label">
|
<div class="mcp-status-label">
|
||||||
{{ t('astroglobe', 'Last Sync') }}
|
{{ t('astrolabe', 'Last Sync') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="mcp-status-value">
|
<div class="mcp-status-value">
|
||||||
{{ vectorStatus.last_sync_time }}
|
{{ vectorStatus.last_sync_time }}
|
||||||
@@ -284,7 +284,7 @@
|
|||||||
<template #icon>
|
<template #icon>
|
||||||
<Refresh :size="20" />
|
<Refresh :size="20" />
|
||||||
</template>
|
</template>
|
||||||
{{ t('astroglobe', 'Refresh') }}
|
{{ t('astrolabe', 'Refresh') }}
|
||||||
</NcButton>
|
</NcButton>
|
||||||
</div>
|
</div>
|
||||||
</NcAppContent>
|
</NcAppContent>
|
||||||
@@ -307,7 +307,7 @@
|
|||||||
<!-- Loading State -->
|
<!-- Loading State -->
|
||||||
<div v-if="viewerLoading" class="mcp-viewer-loading">
|
<div v-if="viewerLoading" class="mcp-viewer-loading">
|
||||||
<NcLoadingIcon :size="32" />
|
<NcLoadingIcon :size="32" />
|
||||||
<span>{{ t('astroglobe', 'Loading content...') }}</span>
|
<span>{{ t('astrolabe', 'Loading content...') }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- PDF Viewer (canvas only, controls in footer) -->
|
<!-- PDF Viewer (canvas only, controls in footer) -->
|
||||||
@@ -334,10 +334,10 @@
|
|||||||
<template #icon>
|
<template #icon>
|
||||||
<ChevronLeft :size="20" />
|
<ChevronLeft :size="20" />
|
||||||
</template>
|
</template>
|
||||||
{{ t('astroglobe', 'Previous') }}
|
{{ t('astrolabe', 'Previous') }}
|
||||||
</NcButton>
|
</NcButton>
|
||||||
<span class="mcp-page-info">
|
<span class="mcp-page-info">
|
||||||
{{ t('astroglobe', 'Page {current} of {total}', { current: viewerPage, total: pdfTotalPages }) }}
|
{{ t('astrolabe', 'Page {current} of {total}', { current: viewerPage, total: pdfTotalPages }) }}
|
||||||
</span>
|
</span>
|
||||||
<NcButton
|
<NcButton
|
||||||
:disabled="viewerPage >= pdfTotalPages"
|
:disabled="viewerPage >= pdfTotalPages"
|
||||||
@@ -345,7 +345,7 @@
|
|||||||
<template #icon>
|
<template #icon>
|
||||||
<ChevronRight :size="20" />
|
<ChevronRight :size="20" />
|
||||||
</template>
|
</template>
|
||||||
{{ t('astroglobe', 'Next') }}
|
{{ t('astrolabe', 'Next') }}
|
||||||
</NcButton>
|
</NcButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -467,19 +467,19 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
algorithmOptions() {
|
algorithmOptions() {
|
||||||
return [
|
return [
|
||||||
{ id: 'hybrid', label: this.t('astroglobe', 'Hybrid') },
|
{ id: 'hybrid', label: this.t('astrolabe', 'Hybrid') },
|
||||||
{ id: 'semantic', label: this.t('astroglobe', 'Semantic') },
|
{ id: 'semantic', label: this.t('astrolabe', 'Semantic') },
|
||||||
{ id: 'bm25', label: this.t('astroglobe', 'Keyword (BM25)') },
|
{ id: 'bm25', label: this.t('astrolabe', 'Keyword (BM25)') },
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
docTypeOptions() {
|
docTypeOptions() {
|
||||||
return [
|
return [
|
||||||
{ id: 'note', label: this.t('astroglobe', 'Notes') },
|
{ id: 'note', label: this.t('astrolabe', 'Notes') },
|
||||||
{ id: 'file', label: this.t('astroglobe', 'Files') },
|
{ id: 'file', label: this.t('astrolabe', 'Files') },
|
||||||
{ id: 'deck_card', label: this.t('astroglobe', 'Deck Cards') },
|
{ id: 'deck_card', label: this.t('astrolabe', 'Deck Cards') },
|
||||||
{ id: 'calendar', label: this.t('astroglobe', 'Calendar') },
|
{ id: 'calendar', label: this.t('astrolabe', 'Calendar') },
|
||||||
{ id: 'contact', label: this.t('astroglobe', 'Contacts') },
|
{ id: 'contact', label: this.t('astrolabe', 'Contacts') },
|
||||||
{ id: 'news_item', label: this.t('astroglobe', 'News') },
|
{ id: 'news_item', label: this.t('astrolabe', 'News') },
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
selectedAlgorithmOption() {
|
selectedAlgorithmOption() {
|
||||||
@@ -523,7 +523,7 @@ export default {
|
|||||||
this.expandedExcerpts = {}
|
this.expandedExcerpts = {}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const url = generateUrl('/apps/astroglobe/api/search')
|
const url = generateUrl('/apps/astrolabe/api/search')
|
||||||
const params = {
|
const params = {
|
||||||
query: queryText,
|
query: queryText,
|
||||||
algorithm: this.algorithm,
|
algorithm: this.algorithm,
|
||||||
@@ -550,12 +550,12 @@ export default {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.error = response.data.error || this.t('astroglobe', 'Search failed')
|
this.error = response.data.error || this.t('astrolabe', 'Search failed')
|
||||||
this.results = []
|
this.results = []
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Search error:', err)
|
console.error('Search error:', err)
|
||||||
this.error = this.t('astroglobe', 'Network error. Please try again.')
|
this.error = this.t('astrolabe', 'Network error. Please try again.')
|
||||||
this.results = []
|
this.results = []
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
@@ -567,17 +567,17 @@ export default {
|
|||||||
this.statusError = null
|
this.statusError = null
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const url = generateUrl('/apps/astroglobe/api/vector-status')
|
const url = generateUrl('/apps/astrolabe/api/vector-status')
|
||||||
const response = await axios.get(url)
|
const response = await axios.get(url)
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
this.vectorStatus = response.data.status
|
this.vectorStatus = response.data.status
|
||||||
} else {
|
} else {
|
||||||
this.statusError = response.data.error || this.t('astroglobe', 'Failed to load status')
|
this.statusError = response.data.error || this.t('astrolabe', 'Failed to load status')
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Status error:', err)
|
console.error('Status error:', err)
|
||||||
this.statusError = this.t('astroglobe', 'Network error. Please try again.')
|
this.statusError = this.t('astrolabe', 'Network error. Please try again.')
|
||||||
} finally {
|
} finally {
|
||||||
this.statusLoading = false
|
this.statusLoading = false
|
||||||
}
|
}
|
||||||
@@ -621,7 +621,7 @@ export default {
|
|||||||
case 'contact':
|
case 'contact':
|
||||||
return generateUrl('/apps/contacts/')
|
return generateUrl('/apps/contacts/')
|
||||||
default:
|
default:
|
||||||
return generateUrl('/apps/astroglobe/')
|
return generateUrl('/apps/astrolabe/')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -631,7 +631,7 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
goToSettings() {
|
goToSettings() {
|
||||||
window.location.href = generateUrl('/settings/user/astroglobe')
|
window.location.href = generateUrl('/settings/user/astrolabe')
|
||||||
},
|
},
|
||||||
|
|
||||||
renderPlot() {
|
renderPlot() {
|
||||||
@@ -783,7 +783,7 @@ export default {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Fetch chunk context
|
// Fetch chunk context
|
||||||
const url = generateUrl('/apps/astroglobe/api/chunk-context')
|
const url = generateUrl('/apps/astrolabe/api/chunk-context')
|
||||||
const params = {
|
const params = {
|
||||||
doc_type: result.doc_type,
|
doc_type: result.doc_type,
|
||||||
doc_id: result.id,
|
doc_id: result.id,
|
||||||
+5
-5
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Admin settings page JavaScript for Astroglobe.
|
* Admin settings page JavaScript for Astrolabe.
|
||||||
*
|
*
|
||||||
* Handles:
|
* Handles:
|
||||||
* - Loading webhook presets
|
* - Loading webhook presets
|
||||||
@@ -24,7 +24,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
* Initialize search settings form handling.
|
* Initialize search settings form handling.
|
||||||
*/
|
*/
|
||||||
function initSearchSettingsForm() {
|
function initSearchSettingsForm() {
|
||||||
const form = document.getElementById('astroglobe-search-settings-form')
|
const form = document.getElementById('astrolabe-search-settings-form')
|
||||||
if (!form) return
|
if (!form) return
|
||||||
|
|
||||||
const scoreThresholdInput = document.getElementById('search-score-threshold')
|
const scoreThresholdInput = document.getElementById('search-score-threshold')
|
||||||
@@ -57,7 +57,7 @@ function initSearchSettingsForm() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await axios.post(
|
const response = await axios.post(
|
||||||
generateUrl('/apps/astroglobe/api/admin/search-settings'),
|
generateUrl('/apps/astrolabe/api/admin/search-settings'),
|
||||||
data,
|
data,
|
||||||
{ headers: { 'Content-Type': 'application/json' } },
|
{ headers: { 'Content-Type': 'application/json' } },
|
||||||
)
|
)
|
||||||
@@ -91,7 +91,7 @@ async function initWebhookManagement() {
|
|||||||
try {
|
try {
|
||||||
// Load webhook presets from API
|
// Load webhook presets from API
|
||||||
const response = await axios.get(
|
const response = await axios.get(
|
||||||
generateUrl('/apps/astroglobe/api/admin/webhooks/presets'),
|
generateUrl('/apps/astrolabe/api/admin/webhooks/presets'),
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!response.data.success) {
|
if (!response.data.success) {
|
||||||
@@ -203,7 +203,7 @@ async function togglePreset(presetId, currentlyEnabled) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const action = currentlyEnabled ? 'disable' : 'enable'
|
const action = currentlyEnabled ? 'disable' : 'enable'
|
||||||
const url = generateUrl(`/apps/astroglobe/api/admin/webhooks/presets/${presetId}/${action}`)
|
const url = generateUrl(`/apps/astrolabe/api/admin/webhooks/presets/${presetId}/${action}`)
|
||||||
|
|
||||||
const response = await axios.post(url)
|
const response = await axios.post(url)
|
||||||
|
|
||||||
+8
-8
@@ -2,7 +2,7 @@
|
|||||||
<div class="pdf-viewer">
|
<div class="pdf-viewer">
|
||||||
<div v-if="loading" class="loading-indicator">
|
<div v-if="loading" class="loading-indicator">
|
||||||
<NcLoadingIcon :size="64" />
|
<NcLoadingIcon :size="64" />
|
||||||
<p>{{ t('astroglobe', 'Loading PDF...') }}</p>
|
<p>{{ t('astrolabe', 'Loading PDF...') }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="error" class="error-message">
|
<div v-else-if="error" class="error-message">
|
||||||
<AlertCircle :size="48" />
|
<AlertCircle :size="48" />
|
||||||
@@ -112,15 +112,15 @@ export default {
|
|||||||
|
|
||||||
// Provide user-friendly error messages
|
// Provide user-friendly error messages
|
||||||
if (err.name === 'MissingPDFException') {
|
if (err.name === 'MissingPDFException') {
|
||||||
this.error = t('astroglobe', 'PDF file not found')
|
this.error = t('astrolabe', 'PDF file not found')
|
||||||
} else if (err.name === 'InvalidPDFException') {
|
} else if (err.name === 'InvalidPDFException') {
|
||||||
this.error = t('astroglobe', 'Invalid or corrupted PDF file')
|
this.error = t('astrolabe', 'Invalid or corrupted PDF file')
|
||||||
} else if (err.message?.includes('NetworkError') || err.message?.includes('Network')) {
|
} else if (err.message?.includes('NetworkError') || err.message?.includes('Network')) {
|
||||||
this.error = t('astroglobe', 'Network error loading PDF')
|
this.error = t('astrolabe', 'Network error loading PDF')
|
||||||
} else if (err.message?.includes('404')) {
|
} else if (err.message?.includes('404')) {
|
||||||
this.error = t('astroglobe', 'PDF file not found')
|
this.error = t('astrolabe', 'PDF file not found')
|
||||||
} else {
|
} else {
|
||||||
this.error = t('astroglobe', 'Unable to load PDF file')
|
this.error = t('astrolabe', 'Unable to load PDF file')
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$emit('error', err)
|
this.$emit('error', err)
|
||||||
@@ -138,7 +138,7 @@ export default {
|
|||||||
|
|
||||||
if (!canvas) {
|
if (!canvas) {
|
||||||
console.error('PDF canvas ref not found')
|
console.error('PDF canvas ref not found')
|
||||||
this.error = t('astroglobe', 'Canvas element not available')
|
this.error = t('astrolabe', 'Canvas element not available')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,7 +161,7 @@ export default {
|
|||||||
this.$emit('page-rendered', { pageNumber: pageNum })
|
this.$emit('page-rendered', { pageNumber: pageNum })
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('PDF render error:', err)
|
console.error('PDF render error:', err)
|
||||||
this.error = t('astroglobe', 'Error rendering PDF page')
|
this.error = t('astrolabe', 'Error rendering PDF page')
|
||||||
this.$emit('error', err)
|
this.$emit('error', err)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -5,4 +5,4 @@ import App from './App.vue'
|
|||||||
Vue.mixin({ methods: { t, n } })
|
Vue.mixin({ methods: { t, n } })
|
||||||
|
|
||||||
const View = Vue.extend(App)
|
const View = Vue.extend(App)
|
||||||
new View().$mount('#astroglobe')
|
new View().$mount('#astrolabe')
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use OCP\Util;
|
||||||
|
|
||||||
|
Util::addScript(OCA\Astrolabe\AppInfo\Application::APP_ID, OCA\Astrolabe\AppInfo\Application::APP_ID . '-main');
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div id="astrolabe"></div>
|
||||||
+9
-9
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Admin settings template for Astroglobe.
|
* Admin settings template for Astrolabe.
|
||||||
*
|
*
|
||||||
* Displays semantic search service status, indexing metrics, configuration,
|
* Displays semantic search service status, indexing metrics, configuration,
|
||||||
* and provides administrative controls.
|
* and provides administrative controls.
|
||||||
@@ -8,17 +8,17 @@
|
|||||||
* @var array $_ Template parameters
|
* @var array $_ Template parameters
|
||||||
* @var array $_['serverStatus'] Server status from API
|
* @var array $_['serverStatus'] Server status from API
|
||||||
* @var array $_['vectorSyncStatus'] Vector sync metrics from API
|
* @var array $_['vectorSyncStatus'] Vector sync metrics from API
|
||||||
* @var string $_['serverUrl'] Configured Astroglobe service URL
|
* @var string $_['serverUrl'] Configured Astrolabe service URL
|
||||||
* @var bool $_['apiKeyConfigured'] Whether API key is set in config.php
|
* @var bool $_['apiKeyConfigured'] Whether API key is set in config.php
|
||||||
* @var bool $_['vectorSyncEnabled'] Whether vector sync is enabled
|
* @var bool $_['vectorSyncEnabled'] Whether vector sync is enabled
|
||||||
*/
|
*/
|
||||||
|
|
||||||
script('astroglobe', 'astroglobe-adminSettings');
|
script('astrolabe', 'astrolabe-adminSettings');
|
||||||
style('astroglobe', 'astroglobe-settings');
|
style('astrolabe', 'astrolabe-settings');
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div id="mcp-admin-settings" class="section">
|
<div id="mcp-admin-settings" class="section">
|
||||||
<h2><?php p($l->t('Astroglobe Administration')); ?></h2>
|
<h2><?php p($l->t('Astrolabe Administration')); ?></h2>
|
||||||
|
|
||||||
<div class="mcp-settings-info">
|
<div class="mcp-settings-info">
|
||||||
<p><?php p($l->t('Monitor and configure the semantic search service for your Nextcloud instance.')); ?></p>
|
<p><?php p($l->t('Monitor and configure the semantic search service for your Nextcloud instance.')); ?></p>
|
||||||
@@ -93,7 +93,7 @@ style('astroglobe', 'astroglobe-settings');
|
|||||||
<p><?php p($l->t('Add the following to your config.php:')); ?></p>
|
<p><?php p($l->t('Add the following to your config.php:')); ?></p>
|
||||||
<pre><code>'mcp_server_url' => 'http://localhost:8000',
|
<pre><code>'mcp_server_url' => 'http://localhost:8000',
|
||||||
'mcp_server_api_key' => 'your-secret-api-key',
|
'mcp_server_api_key' => 'your-secret-api-key',
|
||||||
'astroglobe_client_id' => 'your-oauth-client-id',</code></pre>
|
'astrolabe_client_id' => 'your-oauth-client-id',</code></pre>
|
||||||
<p class="mcp-help-text">
|
<p class="mcp-help-text">
|
||||||
<a href="https://github.com/cbcoutinho/nextcloud-mcp-server" target="_blank">
|
<a href="https://github.com/cbcoutinho/nextcloud-mcp-server" target="_blank">
|
||||||
<?php p($l->t('See documentation for details')); ?>
|
<?php p($l->t('See documentation for details')); ?>
|
||||||
@@ -108,7 +108,7 @@ style('astroglobe', 'astroglobe-settings');
|
|||||||
<p><?php p($l->t('To use refresh tokens for long-lived sessions, generate a client secret:')); ?></p>
|
<p><?php p($l->t('To use refresh tokens for long-lived sessions, generate a client secret:')); ?></p>
|
||||||
<pre><code>openssl rand -hex 32</code></pre>
|
<pre><code>openssl rand -hex 32</code></pre>
|
||||||
<p><?php p($l->t('Then add it to your config.php:')); ?></p>
|
<p><?php p($l->t('Then add it to your config.php:')); ?></p>
|
||||||
<pre><code>'astroglobe_client_secret' => 'your-generated-secret',</code></pre>
|
<pre><code>'astrolabe_client_secret' => 'your-generated-secret',</code></pre>
|
||||||
<p class="mcp-help-text">
|
<p class="mcp-help-text">
|
||||||
<?php p($l->t('Without a client secret, the system will use PKCE (public client) authentication. Both methods work, but confidential clients provide better security for long-lived sessions.')); ?>
|
<?php p($l->t('Without a client secret, the system will use PKCE (public client) authentication. Both methods work, but confidential clients provide better security for long-lived sessions.')); ?>
|
||||||
</p>
|
</p>
|
||||||
@@ -226,7 +226,7 @@ style('astroglobe', 'astroglobe-settings');
|
|||||||
<?php p($l->t('Configure the default search parameters for the AI Search provider in Nextcloud unified search.')); ?>
|
<?php p($l->t('Configure the default search parameters for the AI Search provider in Nextcloud unified search.')); ?>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<form id="astroglobe-search-settings-form" class="mcp-settings-form">
|
<form id="astrolabe-search-settings-form" class="mcp-settings-form">
|
||||||
<div class="mcp-form-group">
|
<div class="mcp-form-group">
|
||||||
<label for="search-algorithm"><?php p($l->t('Search Algorithm')); ?></label>
|
<label for="search-algorithm"><?php p($l->t('Search Algorithm')); ?></label>
|
||||||
<select id="search-algorithm" name="algorithm" class="mcp-select">
|
<select id="search-algorithm" name="algorithm" class="mcp-select">
|
||||||
@@ -343,7 +343,7 @@ style('astroglobe', 'astroglobe-settings');
|
|||||||
<ul>
|
<ul>
|
||||||
<li><?php p($l->t('The webhook_listeners app must be installed and enabled in Nextcloud')); ?></li>
|
<li><?php p($l->t('The webhook_listeners app must be installed and enabled in Nextcloud')); ?></li>
|
||||||
<li><?php p($l->t('The MCP server must be reachable from your Nextcloud instance')); ?></li>
|
<li><?php p($l->t('The MCP server must be reachable from your Nextcloud instance')); ?></li>
|
||||||
<li><?php p($l->t('You must have authorized Astroglobe with the MCP server (see Personal Settings)')); ?></li>
|
<li><?php p($l->t('You must have authorized Astrolabe with the MCP server (see Personal Settings)')); ?></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
+1
-1
@@ -11,7 +11,7 @@
|
|||||||
* @var string $_['help_text'] Additional help text (optional)
|
* @var string $_['help_text'] Additional help text (optional)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
style('astroglobe', 'astroglobe-settings');
|
style('astrolabe', 'astrolabe-settings');
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div class="mcp-settings-error">
|
<div class="mcp-settings-error">
|
||||||
+6
-6
@@ -2,19 +2,19 @@
|
|||||||
/**
|
/**
|
||||||
* OAuth authorization required template.
|
* OAuth authorization required template.
|
||||||
*
|
*
|
||||||
* Shown when user needs to authorize Astroglobe for semantic search.
|
* Shown when user needs to authorize Astrolabe for semantic search.
|
||||||
* Implements OAuth 2.0 Authorization Code flow with PKCE.
|
* Implements OAuth 2.0 Authorization Code flow with PKCE.
|
||||||
*
|
*
|
||||||
* @var array $_ Template parameters
|
* @var array $_ Template parameters
|
||||||
* @var string $_['oauth_url'] URL to initiate OAuth flow
|
* @var string $_['oauth_url'] URL to initiate OAuth flow
|
||||||
* @var string $_['server_url'] Astroglobe service URL
|
* @var string $_['server_url'] Astrolabe service URL
|
||||||
* @var bool $_['has_expired'] Whether token exists but is expired
|
* @var bool $_['has_expired'] Whether token exists but is expired
|
||||||
* @var string|null $_['error_message'] Optional error message to display
|
* @var string|null $_['error_message'] Optional error message to display
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use OCP\Util;
|
use OCP\Util;
|
||||||
|
|
||||||
Util::addStyle('astroglobe', 'astroglobe-settings');
|
Util::addStyle('astrolabe', 'astrolabe-settings');
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div id="mcp-personal-settings">
|
<div id="mcp-personal-settings">
|
||||||
@@ -44,7 +44,7 @@ Util::addStyle('astroglobe', 'astroglobe-settings');
|
|||||||
</p>
|
</p>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<p>
|
<p>
|
||||||
<?php p($l->t('To search your content by meaning, Astroglobe needs permission to index your Nextcloud data.')); ?>
|
<?php p($l->t('To search your content by meaning, Astrolabe needs permission to index your Nextcloud data.')); ?>
|
||||||
</p>
|
</p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
@@ -104,11 +104,11 @@ Util::addStyle('astroglobe', 'astroglobe-settings');
|
|||||||
<div class="mcp-status-card">
|
<div class="mcp-status-card">
|
||||||
<h3>
|
<h3>
|
||||||
<span class="icon icon-info"></span>
|
<span class="icon icon-info"></span>
|
||||||
<?php p($l->t('About Astroglobe')); ?>
|
<?php p($l->t('About Astrolabe')); ?>
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<?php p($l->t('Astroglobe enables semantic search - finding content by meaning rather than exact keywords. Ask questions like "meeting notes from last week" or "recipes with chicken" to find relevant documents.')); ?>
|
<?php p($l->t('Astrolabe enables semantic search - finding content by meaning rather than exact keywords. Ask questions like "meeting notes from last week" or "recipes with chicken" to find relevant documents.')); ?>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="mcp-help-text">
|
<p class="mcp-help-text">
|
||||||
+13
-13
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Personal settings template for Astroglobe.
|
* Personal settings template for Astrolabe.
|
||||||
*
|
*
|
||||||
* Displays semantic search status, background indexing access,
|
* Displays semantic search status, background indexing access,
|
||||||
* and provides controls for managing content indexing.
|
* and provides controls for managing content indexing.
|
||||||
@@ -11,18 +11,18 @@
|
|||||||
* @var array $_['session'] User session details from API
|
* @var array $_['session'] User session details from API
|
||||||
* @var bool $_['vectorSyncEnabled'] Whether vector sync is enabled
|
* @var bool $_['vectorSyncEnabled'] Whether vector sync is enabled
|
||||||
* @var bool $_['backgroundAccessGranted'] Whether user has granted background access
|
* @var bool $_['backgroundAccessGranted'] Whether user has granted background access
|
||||||
* @var string $_['serverUrl'] Astroglobe service URL
|
* @var string $_['serverUrl'] Astrolabe service URL
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Get URL generator from Nextcloud's service container
|
// Get URL generator from Nextcloud's service container
|
||||||
$urlGenerator = \OC::$server->getURLGenerator();
|
$urlGenerator = \OC::$server->getURLGenerator();
|
||||||
|
|
||||||
script('astroglobe', 'astroglobe-personalSettings');
|
script('astrolabe', 'astrolabe-personalSettings');
|
||||||
style('astroglobe', 'astroglobe-settings');
|
style('astrolabe', 'astrolabe-settings');
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div id="mcp-personal-settings" class="section">
|
<div id="mcp-personal-settings" class="section">
|
||||||
<h2><?php p($l->t('Astroglobe')); ?></h2>
|
<h2><?php p($l->t('Astrolabe')); ?></h2>
|
||||||
|
|
||||||
<div class="mcp-settings-info">
|
<div class="mcp-settings-info">
|
||||||
<p><?php p($l->t('AI-powered semantic search across your Nextcloud content. Find documents by meaning, not just keywords.')); ?></p>
|
<p><?php p($l->t('AI-powered semantic search across your Nextcloud content. Find documents by meaning, not just keywords.')); ?></p>
|
||||||
@@ -69,7 +69,7 @@ style('astroglobe', 'astroglobe-settings');
|
|||||||
<p class="mcp-help-text">
|
<p class="mcp-help-text">
|
||||||
<?php p($l->t('Enable background indexing to use semantic search. Your Notes, Files, Calendar events, and Deck cards will be indexed so you can search by meaning.')); ?>
|
<?php p($l->t('Enable background indexing to use semantic search. Your Notes, Files, Calendar events, and Deck cards will be indexed so you can search by meaning.')); ?>
|
||||||
</p>
|
</p>
|
||||||
<a href="<?php p($_['serverUrl']); ?>/oauth/login?next=<?php p(urlencode($urlGenerator->getAbsoluteURL($urlGenerator->linkToRoute('settings.PersonalSettings.index', ['section' => 'astroglobe'])))); ?>" class="button primary" id="mcp-grant-button">
|
<a href="<?php p($_['serverUrl']); ?>/oauth/login?next=<?php p(urlencode($urlGenerator->getAbsoluteURL($urlGenerator->linkToRoute('settings.PersonalSettings.index', ['section' => 'astrolabe'])))); ?>" class="button primary" id="mcp-grant-button">
|
||||||
<span class="icon icon-confirm"></span>
|
<span class="icon icon-confirm"></span>
|
||||||
<?php p($l->t('Enable Semantic Search')); ?>
|
<?php p($l->t('Enable Semantic Search')); ?>
|
||||||
</a>
|
</a>
|
||||||
@@ -91,7 +91,7 @@ style('astroglobe', 'astroglobe-settings');
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
<div class="mcp-revoke-section">
|
<div class="mcp-revoke-section">
|
||||||
<form method="post" action="<?php p($urlGenerator->linkToRoute('astroglobe.api.revokeAccess')); ?>" id="mcp-revoke-form">
|
<form method="post" action="<?php p($urlGenerator->linkToRoute('astrolabe.api.revokeAccess')); ?>" id="mcp-revoke-form">
|
||||||
<input type="hidden" name="requesttoken" value="<?php p($_['requesttoken']); ?>">
|
<input type="hidden" name="requesttoken" value="<?php p($_['requesttoken']); ?>">
|
||||||
<button type="submit" class="button warning" id="mcp-revoke-button">
|
<button type="submit" class="button warning" id="mcp-revoke-button">
|
||||||
<span class="icon icon-delete"></span>
|
<span class="icon icon-delete"></span>
|
||||||
@@ -132,9 +132,9 @@ style('astroglobe', 'astroglobe-settings');
|
|||||||
<div class="mcp-status-card">
|
<div class="mcp-status-card">
|
||||||
<h3><?php p($l->t('Search Your Content')); ?></h3>
|
<h3><?php p($l->t('Search Your Content')); ?></h3>
|
||||||
<p><?php p($l->t('Use natural language to search across your Notes, Files, Calendar, and Deck cards. Ask questions like "meeting notes from last week" or "recipes with chicken".')); ?></p>
|
<p><?php p($l->t('Use natural language to search across your Notes, Files, Calendar, and Deck cards. Ask questions like "meeting notes from last week" or "recipes with chicken".')); ?></p>
|
||||||
<a href="<?php p($urlGenerator->linkToRoute('astroglobe.page.index')); ?>" class="button primary">
|
<a href="<?php p($urlGenerator->linkToRoute('astrolabe.page.index')); ?>" class="button primary">
|
||||||
<span class="icon icon-search"></span>
|
<span class="icon icon-search"></span>
|
||||||
<?php p($l->t('Open Astroglobe')); ?>
|
<?php p($l->t('Open Astrolabe')); ?>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
@@ -149,17 +149,17 @@ style('astroglobe', 'astroglobe-settings');
|
|||||||
<!-- Connection Management -->
|
<!-- Connection Management -->
|
||||||
<div class="mcp-status-card">
|
<div class="mcp-status-card">
|
||||||
<h3><?php p($l->t('Manage Connection')); ?></h3>
|
<h3><?php p($l->t('Manage Connection')); ?></h3>
|
||||||
<p><?php p($l->t('You are connected to the Astroglobe service.')); ?></p>
|
<p><?php p($l->t('You are connected to the Astrolabe service.')); ?></p>
|
||||||
|
|
||||||
<div class="mcp-revoke-section">
|
<div class="mcp-revoke-section">
|
||||||
<form method="post" action="<?php p($urlGenerator->linkToRoute('astroglobe.oauth.disconnect')); ?>" id="mcp-disconnect-form">
|
<form method="post" action="<?php p($urlGenerator->linkToRoute('astrolabe.oauth.disconnect')); ?>" id="mcp-disconnect-form">
|
||||||
<input type="hidden" name="requesttoken" value="<?php p($_['requesttoken']); ?>">
|
<input type="hidden" name="requesttoken" value="<?php p($_['requesttoken']); ?>">
|
||||||
<button type="submit" class="button warning" id="mcp-disconnect-button">
|
<button type="submit" class="button warning" id="mcp-disconnect-button">
|
||||||
<span class="icon icon-close"></span>
|
<span class="icon icon-close"></span>
|
||||||
<?php p($l->t('Disconnect')); ?>
|
<?php p($l->t('Disconnect')); ?>
|
||||||
</button>
|
</button>
|
||||||
<p class="mcp-help-text">
|
<p class="mcp-help-text">
|
||||||
<?php p($l->t('This will disconnect from the Astroglobe service. You will need to re-authorize to use semantic search features.')); ?>
|
<?php p($l->t('This will disconnect from the Astrolabe service. You will need to re-authorize to use semantic search features.')); ?>
|
||||||
</p>
|
</p>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -181,7 +181,7 @@ style('astroglobe', 'astroglobe-settings');
|
|||||||
const disconnectForm = document.getElementById('mcp-disconnect-form');
|
const disconnectForm = document.getElementById('mcp-disconnect-form');
|
||||||
if (disconnectForm) {
|
if (disconnectForm) {
|
||||||
disconnectForm.addEventListener('submit', function(e) {
|
disconnectForm.addEventListener('submit', function(e) {
|
||||||
if (!confirm('<?php p($l->t('Are you sure you want to disconnect from Astroglobe? You will need to re-authorize to use semantic search.')); ?>')) {
|
if (!confirm('<?php p($l->t('Are you sure you want to disconnect from Astrolabe? You will need to re-authorize to use semantic search.')); ?>')) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
+1
-1
@@ -5,5 +5,5 @@ declare(strict_types=1);
|
|||||||
require_once __DIR__ . '/../../../tests/bootstrap.php';
|
require_once __DIR__ . '/../../../tests/bootstrap.php';
|
||||||
require_once __DIR__ . '/../vendor/autoload.php';
|
require_once __DIR__ . '/../vendor/autoload.php';
|
||||||
|
|
||||||
\OC_App::loadApp(OCA\Astroglobe\AppInfo\Application::APP_ID);
|
\OC_App::loadApp(OCA\Astrolabe\AppInfo\Application::APP_ID);
|
||||||
OC_Hook::clear();
|
OC_Hook::clear();
|
||||||
+2
-2
@@ -4,8 +4,8 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Controller;
|
namespace Controller;
|
||||||
|
|
||||||
use OCA\Astroglobe\AppInfo\Application;
|
use OCA\Astrolabe\AppInfo\Application;
|
||||||
use OCA\Astroglobe\Controller\ApiController;
|
use OCA\Astrolabe\Controller\ApiController;
|
||||||
use OCP\IRequest;
|
use OCP\IRequest;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Reference in New Issue
Block a user