fix: resolve CI linting issues for Astroglobe
Fix all ESLint, Stylelint, PHP CS Fixer, and Psalm workflow errors. Changes: - ESLint fixes: - Remove unused APP_NAME constant - Remove unused TextBoxOutline and TextBoxRemoveOutline components - Remove unused container variable in adminSettings.js - Auto-fix trailing commas, line breaks, attribute ordering - PHP CS Fixer: - Add trailing commas after last function parameters - Convert double quotes to single quotes in log messages - Remove unused NoCSRFRequired import - Fix arrow function formatting - Stylelint: - Update config to use @nextcloud/stylelint-config - Fix extends directive (was using non-existent package) - Psalm workflow: - Fix jq object indexing (.include[0] instead of .[0]) - Correctly extract OCP version from matrix output All checks now pass locally. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -247,7 +247,7 @@ jobs:
|
||||
- name: Install OCP for static analysis
|
||||
run: |
|
||||
# Get first OCP version from matrix
|
||||
OCP_VERSION=$(echo '${{ steps.ocp-versions.outputs.ocp-matrix }}' | jq -r '.[0]."ocp-version"')
|
||||
OCP_VERSION=$(echo '${{ steps.ocp-versions.outputs.ocp-matrix }}' | jq -r '.include[0]."ocp-version"')
|
||||
composer require --dev "nextcloud/ocp:$OCP_VERSION" --ignore-platform-reqs --with-dependencies
|
||||
|
||||
- name: Run Psalm
|
||||
|
||||
+4
-5
@@ -12,7 +12,6 @@ use OCA\Astroglobe\Settings\Admin as AdminSettings;
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
|
||||
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
|
||||
use OCP\AppFramework\Http\JSONResponse;
|
||||
use OCP\AppFramework\Http\RedirectResponse;
|
||||
use OCP\IConfig;
|
||||
@@ -44,7 +43,7 @@ class ApiController extends Controller {
|
||||
LoggerInterface $logger,
|
||||
McpTokenStorage $tokenStorage,
|
||||
IConfig $config,
|
||||
IdpTokenRefresher $tokenRefresher
|
||||
IdpTokenRefresher $tokenRefresher,
|
||||
) {
|
||||
parent::__construct($appName, $request);
|
||||
$this->client = $client;
|
||||
@@ -126,7 +125,7 @@ class ApiController extends Controller {
|
||||
string $algorithm = 'hybrid',
|
||||
int $limit = 10,
|
||||
string $doc_types = '',
|
||||
string $include_pca = 'true'
|
||||
string $include_pca = 'true',
|
||||
): JSONResponse {
|
||||
if (empty($query)) {
|
||||
return new JSONResponse([
|
||||
@@ -185,7 +184,7 @@ class ApiController extends Controller {
|
||||
$validDocTypes = ['note', 'file', 'deck_card', 'calendar', 'contact', 'news_item'];
|
||||
$docTypesArray = array_filter(
|
||||
explode(',', $doc_types),
|
||||
fn($t) => in_array(trim($t), $validDocTypes)
|
||||
fn ($t) => in_array(trim($t), $validDocTypes)
|
||||
);
|
||||
$docTypesArray = array_map('trim', $docTypesArray);
|
||||
if (empty($docTypesArray)) {
|
||||
@@ -678,7 +677,7 @@ class ApiController extends Controller {
|
||||
string $doc_type,
|
||||
string $doc_id,
|
||||
int $start,
|
||||
int $end
|
||||
int $end,
|
||||
): JSONResponse {
|
||||
$user = $this->userSession->getUser();
|
||||
if (!$user) {
|
||||
|
||||
+12
-12
@@ -47,7 +47,7 @@ class OAuthController extends Controller {
|
||||
McpTokenStorage $tokenStorage,
|
||||
LoggerInterface $logger,
|
||||
IL10N $l,
|
||||
IClientService $clientService
|
||||
IClientService $clientService,
|
||||
) {
|
||||
parent::__construct($appName, $request);
|
||||
$this->config = $config;
|
||||
@@ -73,11 +73,11 @@ class OAuthController extends Controller {
|
||||
#[NoAdminRequired]
|
||||
#[NoCSRFRequired]
|
||||
public function initiateOAuth() {
|
||||
$this->logger->info("initiateOAuth called");
|
||||
$this->logger->info('initiateOAuth called');
|
||||
|
||||
$user = $this->userSession->getUser();
|
||||
if (!$user) {
|
||||
$this->logger->error("initiateOAuth: User not authenticated");
|
||||
$this->logger->error('initiateOAuth: User not authenticated');
|
||||
return new TemplateResponse(
|
||||
'astroglobe',
|
||||
'settings/error',
|
||||
@@ -85,7 +85,7 @@ class OAuthController extends Controller {
|
||||
);
|
||||
}
|
||||
|
||||
$this->logger->info("initiateOAuth: User authenticated: " . $user->getUID());
|
||||
$this->logger->info('initiateOAuth: User authenticated: ' . $user->getUID());
|
||||
|
||||
try {
|
||||
// Get MCP server configuration
|
||||
@@ -107,9 +107,9 @@ class OAuthController extends Controller {
|
||||
$codeVerifier = bin2hex(random_bytes(32));
|
||||
$codeChallenge = $this->base64UrlEncode(hash('sha256', $codeVerifier, true));
|
||||
|
||||
$this->logger->info("Using public client mode with PKCE");
|
||||
$this->logger->info('Using public client mode with PKCE');
|
||||
} else {
|
||||
$this->logger->info("Using confidential client mode with client secret");
|
||||
$this->logger->info('Using confidential client mode with client secret');
|
||||
}
|
||||
|
||||
// Generate state for CSRF protection
|
||||
@@ -129,7 +129,7 @@ class OAuthController extends Controller {
|
||||
$codeChallenge
|
||||
);
|
||||
|
||||
$this->logger->info("Initiating OAuth flow for user: " . $user->getUID());
|
||||
$this->logger->info('Initiating OAuth flow for user: ' . $user->getUID());
|
||||
|
||||
return new RedirectResponse($authUrl);
|
||||
} catch (\Exception $e) {
|
||||
@@ -163,7 +163,7 @@ class OAuthController extends Controller {
|
||||
string $code = '',
|
||||
string $state = '',
|
||||
?string $error = null,
|
||||
?string $error_description = null
|
||||
?string $error_description = null,
|
||||
): RedirectResponse {
|
||||
try {
|
||||
// Check for errors from IdP
|
||||
@@ -292,7 +292,7 @@ class OAuthController extends Controller {
|
||||
private function buildAuthorizationUrl(
|
||||
string $mcpServerUrl,
|
||||
string $state,
|
||||
?string $codeChallenge
|
||||
?string $codeChallenge,
|
||||
): string {
|
||||
// First, query MCP server to discover which IdP it's configured to use
|
||||
$this->logger->info('buildAuthorizationUrl: Starting', [
|
||||
@@ -430,7 +430,7 @@ class OAuthController extends Controller {
|
||||
private function exchangeCodeForToken(
|
||||
string $mcpServerUrl,
|
||||
string $code,
|
||||
?string $codeVerifier
|
||||
?string $codeVerifier,
|
||||
): array {
|
||||
// Query MCP server to discover which IdP it's configured to use
|
||||
try {
|
||||
@@ -496,11 +496,11 @@ class OAuthController extends Controller {
|
||||
if (!empty($clientSecret)) {
|
||||
// Confidential client: use client secret for authentication
|
||||
$postData['client_secret'] = $clientSecret;
|
||||
$this->logger->info("Using client secret for token exchange");
|
||||
$this->logger->info('Using client secret for token exchange');
|
||||
} elseif ($codeVerifier !== null) {
|
||||
// Public client: use PKCE proof for authentication
|
||||
$postData['code_verifier'] = $codeVerifier;
|
||||
$this->logger->info("Using PKCE code verifier for token exchange");
|
||||
$this->logger->info('Using PKCE code verifier for token exchange');
|
||||
} else {
|
||||
throw new \Exception('Neither client_secret nor code_verifier available for token exchange');
|
||||
}
|
||||
|
||||
@@ -247,8 +247,8 @@ class SemanticSearchProvider implements IProvider {
|
||||
: $this->urlGenerator->linkToRouteAbsolute('files.view.index'),
|
||||
|
||||
'deck_card' => isset($result['board_id']) && $id
|
||||
? $this->urlGenerator->linkToRoute('deck.page.index') .
|
||||
"board/{$result['board_id']}/card/{$id}"
|
||||
? $this->urlGenerator->linkToRoute('deck.page.index')
|
||||
. "board/{$result['board_id']}/card/{$id}"
|
||||
: $this->urlGenerator->linkToRoute('deck.page.index'),
|
||||
|
||||
'calendar', 'calendar_event' => $this->urlGenerator->linkToRoute('calendar.view.index'),
|
||||
|
||||
@@ -25,7 +25,7 @@ class IdpTokenRefresher {
|
||||
public function __construct(
|
||||
IConfig $config,
|
||||
IClientService $clientService,
|
||||
LoggerInterface $logger
|
||||
LoggerInterface $logger,
|
||||
) {
|
||||
$this->config = $config;
|
||||
$this->httpClient = $clientService->newClient();
|
||||
|
||||
+7
-7
@@ -24,7 +24,7 @@ class McpServerClient {
|
||||
public function __construct(
|
||||
IClientService $clientService,
|
||||
IConfig $config,
|
||||
LoggerInterface $logger
|
||||
LoggerInterface $logger,
|
||||
) {
|
||||
$this->httpClient = $clientService->newClient();
|
||||
$this->config = $config;
|
||||
@@ -85,7 +85,7 @@ class McpServerClient {
|
||||
public function getUserSession(string $userId, string $token): array {
|
||||
try {
|
||||
$response = $this->httpClient->get(
|
||||
$this->baseUrl . "/api/v1/users/" . urlencode($userId) . "/session",
|
||||
$this->baseUrl . '/api/v1/users/' . urlencode($userId) . '/session',
|
||||
[
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer ' . $token
|
||||
@@ -120,7 +120,7 @@ class McpServerClient {
|
||||
public function revokeUserAccess(string $userId, string $token): array {
|
||||
try {
|
||||
$response = $this->httpClient->post(
|
||||
$this->baseUrl . "/api/v1/users/" . urlencode($userId) . "/revoke",
|
||||
$this->baseUrl . '/api/v1/users/' . urlencode($userId) . '/revoke',
|
||||
[
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer ' . $token
|
||||
@@ -203,7 +203,7 @@ class McpServerClient {
|
||||
int $limit = 10,
|
||||
bool $includePca = true,
|
||||
?array $docTypes = null,
|
||||
?string $token = null
|
||||
?string $token = null,
|
||||
): array {
|
||||
try {
|
||||
$requestBody = [
|
||||
@@ -284,7 +284,7 @@ class McpServerClient {
|
||||
int $offset = 0,
|
||||
string $algorithm = 'hybrid',
|
||||
string $fusion = 'rrf',
|
||||
float $scoreThreshold = 0.0
|
||||
float $scoreThreshold = 0.0,
|
||||
): array {
|
||||
try {
|
||||
$response = $this->httpClient->post(
|
||||
@@ -416,7 +416,7 @@ class McpServerClient {
|
||||
string $event,
|
||||
string $uri,
|
||||
?array $eventFilter,
|
||||
string $token
|
||||
string $token,
|
||||
): array {
|
||||
try {
|
||||
$requestBody = [
|
||||
@@ -549,7 +549,7 @@ class McpServerClient {
|
||||
string $docId,
|
||||
int $start,
|
||||
int $end,
|
||||
string $token
|
||||
string $token,
|
||||
): array {
|
||||
try {
|
||||
$response = $this->httpClient->get(
|
||||
|
||||
+3
-3
@@ -22,7 +22,7 @@ class McpTokenStorage {
|
||||
public function __construct(
|
||||
IConfig $config,
|
||||
ICrypto $crypto,
|
||||
LoggerInterface $logger
|
||||
LoggerInterface $logger,
|
||||
) {
|
||||
$this->config = $config;
|
||||
$this->crypto = $crypto;
|
||||
@@ -43,7 +43,7 @@ class McpTokenStorage {
|
||||
string $userId,
|
||||
string $accessToken,
|
||||
string $refreshToken,
|
||||
int $expiresAt
|
||||
int $expiresAt,
|
||||
): void {
|
||||
try {
|
||||
$tokenData = [
|
||||
@@ -158,7 +158,7 @@ class McpTokenStorage {
|
||||
*
|
||||
* @param string $userId User ID
|
||||
* @param callable|null $refreshCallback Callback to refresh token if expired
|
||||
* Should accept (refreshToken) and return new token data
|
||||
* Should accept (refreshToken) and return new token data
|
||||
* @return string|null Access token, or null if not available
|
||||
*/
|
||||
public function getAccessToken(string $userId, ?callable $refreshCallback = null): ?string {
|
||||
|
||||
+11
-11
@@ -12,24 +12,24 @@ namespace OCA\Astroglobe\Service;
|
||||
*/
|
||||
class WebhookPresets {
|
||||
// File/Notes webhook events
|
||||
public const FILE_EVENT_CREATED = "OCP\\Files\\Events\\Node\\NodeCreatedEvent";
|
||||
public const FILE_EVENT_WRITTEN = "OCP\\Files\\Events\\Node\\NodeWrittenEvent";
|
||||
public const FILE_EVENT_CREATED = 'OCP\\Files\\Events\\Node\\NodeCreatedEvent';
|
||||
public const FILE_EVENT_WRITTEN = 'OCP\\Files\\Events\\Node\\NodeWrittenEvent';
|
||||
// Use BeforeNodeDeletedEvent instead of NodeDeletedEvent to get node.id
|
||||
// See: https://github.com/nextcloud/server/issues/56371
|
||||
public const FILE_EVENT_DELETED = "OCP\\Files\\Events\\Node\\BeforeNodeDeletedEvent";
|
||||
public const FILE_EVENT_DELETED = 'OCP\\Files\\Events\\Node\\BeforeNodeDeletedEvent';
|
||||
|
||||
// Calendar webhook events
|
||||
public const CALENDAR_EVENT_CREATED = "OCP\\Calendar\\Events\\CalendarObjectCreatedEvent";
|
||||
public const CALENDAR_EVENT_UPDATED = "OCP\\Calendar\\Events\\CalendarObjectUpdatedEvent";
|
||||
public const CALENDAR_EVENT_DELETED = "OCP\\Calendar\\Events\\CalendarObjectDeletedEvent";
|
||||
public const CALENDAR_EVENT_CREATED = 'OCP\\Calendar\\Events\\CalendarObjectCreatedEvent';
|
||||
public const CALENDAR_EVENT_UPDATED = 'OCP\\Calendar\\Events\\CalendarObjectUpdatedEvent';
|
||||
public const CALENDAR_EVENT_DELETED = 'OCP\\Calendar\\Events\\CalendarObjectDeletedEvent';
|
||||
|
||||
// Tables webhook events (Nextcloud 30+)
|
||||
public const TABLES_EVENT_ROW_ADDED = "OCA\\Tables\\Event\\RowAddedEvent";
|
||||
public const TABLES_EVENT_ROW_UPDATED = "OCA\\Tables\\Event\\RowUpdatedEvent";
|
||||
public const TABLES_EVENT_ROW_DELETED = "OCA\\Tables\\Event\\RowDeletedEvent";
|
||||
public const TABLES_EVENT_ROW_ADDED = 'OCA\\Tables\\Event\\RowAddedEvent';
|
||||
public const TABLES_EVENT_ROW_UPDATED = 'OCA\\Tables\\Event\\RowUpdatedEvent';
|
||||
public const TABLES_EVENT_ROW_DELETED = 'OCA\\Tables\\Event\\RowDeletedEvent';
|
||||
|
||||
// Forms webhook events (Nextcloud 30+)
|
||||
public const FORMS_EVENT_FORM_SUBMITTED = "OCA\\Forms\\Events\\FormSubmittedEvent";
|
||||
public const FORMS_EVENT_FORM_SUBMITTED = 'OCA\\Forms\\Events\\FormSubmittedEvent';
|
||||
|
||||
// NOTE: Deck and Contacts do NOT support webhooks
|
||||
// Their event classes do not implement IWebhookCompatibleEvent interface.
|
||||
@@ -163,7 +163,7 @@ class WebhookPresets {
|
||||
}
|
||||
|
||||
return array_map(
|
||||
fn($eventConfig) => $eventConfig['event'],
|
||||
fn ($eventConfig) => $eventConfig['event'],
|
||||
$preset['events']
|
||||
);
|
||||
}
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ class Admin implements ISettings {
|
||||
public function __construct(
|
||||
McpServerClient $client,
|
||||
IConfig $config,
|
||||
IInitialState $initialState
|
||||
IInitialState $initialState,
|
||||
) {
|
||||
$this->client = $client;
|
||||
$this->config = $config;
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ class Personal implements ISettings {
|
||||
IUserSession $userSession,
|
||||
IInitialState $initialState,
|
||||
McpTokenStorage $tokenStorage,
|
||||
IURLGenerator $urlGenerator
|
||||
IURLGenerator $urlGenerator,
|
||||
) {
|
||||
$this->client = $client;
|
||||
$this->userSession = $userSession;
|
||||
|
||||
Vendored
+35
-22
@@ -118,7 +118,7 @@
|
||||
min="0"
|
||||
max="100"
|
||||
step="5"
|
||||
class="mcp-score-slider" />
|
||||
class="mcp-score-slider">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -248,29 +248,43 @@
|
||||
|
||||
<div v-else-if="vectorStatus" class="mcp-status-cards">
|
||||
<div class="mcp-status-card">
|
||||
<div class="mcp-status-label">{{ t('astroglobe', 'Sync Status') }}</div>
|
||||
<div class="mcp-status-label">
|
||||
{{ t('astroglobe', 'Sync Status') }}
|
||||
</div>
|
||||
<div class="mcp-status-value" :class="'status-' + vectorStatus.status">
|
||||
{{ vectorStatus.status }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mcp-status-card">
|
||||
<div class="mcp-status-label">{{ t('astroglobe', 'Indexed Documents') }}</div>
|
||||
<div class="mcp-status-value">{{ vectorStatus.indexed_documents || 0 }}</div>
|
||||
<div class="mcp-status-label">
|
||||
{{ t('astroglobe', 'Indexed Documents') }}
|
||||
</div>
|
||||
<div class="mcp-status-value">
|
||||
{{ vectorStatus.indexed_documents || 0 }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mcp-status-card">
|
||||
<div class="mcp-status-label">{{ t('astroglobe', 'Pending Documents') }}</div>
|
||||
<div class="mcp-status-value">{{ vectorStatus.pending_documents || 0 }}</div>
|
||||
<div class="mcp-status-label">
|
||||
{{ t('astroglobe', 'Pending Documents') }}
|
||||
</div>
|
||||
<div class="mcp-status-value">
|
||||
{{ vectorStatus.pending_documents || 0 }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="vectorStatus.last_sync_time" class="mcp-status-card">
|
||||
<div class="mcp-status-label">{{ t('astroglobe', 'Last Sync') }}</div>
|
||||
<div class="mcp-status-value">{{ vectorStatus.last_sync_time }}</div>
|
||||
<div class="mcp-status-label">
|
||||
{{ t('astroglobe', 'Last Sync') }}
|
||||
</div>
|
||||
<div class="mcp-status-value">
|
||||
{{ vectorStatus.last_sync_time }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<NcButton type="secondary" @click="loadVectorStatus" :disabled="statusLoading">
|
||||
<NcButton type="secondary" :disabled="statusLoading" @click="loadVectorStatus">
|
||||
<template #icon>
|
||||
<Refresh :size="20" />
|
||||
</template>
|
||||
@@ -308,9 +322,15 @@
|
||||
|
||||
<!-- Text Viewer (for non-PDFs) -->
|
||||
<div v-else class="mcp-text-viewer">
|
||||
<div v-if="viewerContext.before" class="mcp-context-text">{{ viewerContext.before }}</div>
|
||||
<div class="mcp-highlighted-chunk">{{ viewerContext.chunk }}</div>
|
||||
<div v-if="viewerContext.after" class="mcp-context-text">{{ viewerContext.after }}</div>
|
||||
<div v-if="viewerContext.before" class="mcp-context-text">
|
||||
{{ viewerContext.before }}
|
||||
</div>
|
||||
<div class="mcp-highlighted-chunk">
|
||||
{{ viewerContext.chunk }}
|
||||
</div>
|
||||
<div v-if="viewerContext.after" class="mcp-context-text">
|
||||
{{ viewerContext.after }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -337,8 +357,6 @@ import Cog from 'vue-material-design-icons/Cog.vue'
|
||||
import ChevronDown from 'vue-material-design-icons/ChevronDown.vue'
|
||||
import ChevronUp from 'vue-material-design-icons/ChevronUp.vue'
|
||||
import Refresh from 'vue-material-design-icons/Refresh.vue'
|
||||
import TextBoxOutline from 'vue-material-design-icons/TextBoxOutline.vue'
|
||||
import TextBoxRemoveOutline from 'vue-material-design-icons/TextBoxRemoveOutline.vue'
|
||||
import OpenInNew from 'vue-material-design-icons/OpenInNew.vue'
|
||||
import Eye from 'vue-material-design-icons/Eye.vue'
|
||||
import Close from 'vue-material-design-icons/Close.vue'
|
||||
@@ -354,16 +372,13 @@ import * as pdfjsLib from 'pdfjs-dist'
|
||||
try {
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = new URL(
|
||||
'pdfjs-dist/build/pdf.worker.mjs',
|
||||
import.meta.url
|
||||
import.meta.url,
|
||||
).toString()
|
||||
} catch (e) {
|
||||
console.warn('Failed to set PDF.js worker, will use fallback', e)
|
||||
// PDF.js will use fake worker automatically
|
||||
}
|
||||
|
||||
// App name for translations
|
||||
const APP_NAME = 'astroglobe'
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
@@ -385,8 +400,6 @@ export default {
|
||||
ChevronDown,
|
||||
ChevronUp,
|
||||
Refresh,
|
||||
TextBoxOutline,
|
||||
TextBoxRemoveOutline,
|
||||
OpenInNew,
|
||||
Eye,
|
||||
Close,
|
||||
@@ -754,7 +767,7 @@ export default {
|
||||
|
||||
closeViewer() {
|
||||
this.showViewer = false
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1177,7 +1190,7 @@ a.mcp-result-title {
|
||||
.mcp-checkbox-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
|
||||
.mcp-modal {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
+5
-6
@@ -59,7 +59,7 @@ function initSearchSettingsForm() {
|
||||
const response = await axios.post(
|
||||
generateUrl('/apps/astroglobe/api/admin/search-settings'),
|
||||
data,
|
||||
{ headers: { 'Content-Type': 'application/json' } }
|
||||
{ headers: { 'Content-Type': 'application/json' } },
|
||||
)
|
||||
|
||||
if (response.data.success) {
|
||||
@@ -91,7 +91,7 @@ async function initWebhookManagement() {
|
||||
try {
|
||||
// Load webhook presets from API
|
||||
const response = await axios.get(
|
||||
generateUrl('/apps/astroglobe/api/admin/webhooks/presets')
|
||||
generateUrl('/apps/astroglobe/api/admin/webhooks/presets'),
|
||||
)
|
||||
|
||||
if (!response.data.success) {
|
||||
@@ -115,7 +115,7 @@ async function initWebhookManagement() {
|
||||
* Render webhook preset cards.
|
||||
*
|
||||
* @param {HTMLElement} container Container element
|
||||
* @param {Object} presets Preset configurations
|
||||
* @param {object} presets Preset configurations
|
||||
*/
|
||||
function renderWebhookPresets(container, presets) {
|
||||
const presetIds = Object.keys(presets)
|
||||
@@ -147,7 +147,7 @@ function renderWebhookPresets(container, presets) {
|
||||
* Create a webhook preset card.
|
||||
*
|
||||
* @param {string} presetId Preset ID
|
||||
* @param {Object} preset Preset configuration
|
||||
* @param {object} preset Preset configuration
|
||||
* @return {HTMLElement} Card element
|
||||
*/
|
||||
function createPresetCard(presetId, preset) {
|
||||
@@ -212,7 +212,6 @@ async function togglePreset(presetId, currentlyEnabled) {
|
||||
}
|
||||
|
||||
// Reload presets to update UI
|
||||
const container = document.getElementById('webhook-presets-container')
|
||||
await initWebhookManagement()
|
||||
|
||||
// Show success notification
|
||||
@@ -227,7 +226,7 @@ async function togglePreset(presetId, currentlyEnabled) {
|
||||
// Show error notification
|
||||
OC.Notification.showTemporary(
|
||||
error.message || 'Failed to toggle webhook preset',
|
||||
{ type: 'error' }
|
||||
{ type: 'error' },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -8,8 +8,8 @@
|
||||
<AlertCircle :size="48" />
|
||||
<p>{{ error }}</p>
|
||||
</div>
|
||||
<div v-else class="pdf-canvas-container" ref="container">
|
||||
<canvas ref="canvas"></canvas>
|
||||
<div v-else ref="container" class="pdf-canvas-container">
|
||||
<canvas ref="canvas" />
|
||||
</div>
|
||||
<div v-if="!loading && !error && totalPages > 0" class="pdf-controls">
|
||||
<NcButton
|
||||
@@ -178,7 +178,7 @@ export default {
|
||||
// Render page to canvas
|
||||
const renderContext = {
|
||||
canvasContext: context,
|
||||
viewport: viewport,
|
||||
viewport,
|
||||
}
|
||||
|
||||
await page.render(renderContext).promise
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
module.exports = {
|
||||
extends: 'stylelint-config-recommended-vue',
|
||||
extends: '@nextcloud/stylelint-config',
|
||||
}
|
||||
|
||||
+22
-12
@@ -113,9 +113,9 @@ style('astroglobe', 'astroglobe-settings');
|
||||
<?php if (isset($_['serverStatus']['uptime_seconds'])): ?>
|
||||
<?php
|
||||
$uptime = $_['serverStatus']['uptime_seconds'];
|
||||
$hours = floor($uptime / 3600);
|
||||
$minutes = floor(($uptime % 3600) / 60);
|
||||
p(sprintf('%d hours, %d minutes', $hours, $minutes));
|
||||
$hours = floor($uptime / 3600);
|
||||
$minutes = floor(($uptime % 3600) / 60);
|
||||
p(sprintf('%d hours, %d minutes', $hours, $minutes));
|
||||
?>
|
||||
<?php else: ?>
|
||||
<?php p($l->t('Unknown')); ?>
|
||||
@@ -150,8 +150,8 @@ style('astroglobe', 'astroglobe-settings');
|
||||
<td>
|
||||
<?php
|
||||
$status = $_['vectorSyncStatus']['status'] ?? 'unknown';
|
||||
$statusClass = $status === 'idle' ? 'success' : ($status === 'syncing' ? 'info' : 'neutral');
|
||||
?>
|
||||
$statusClass = $status === 'idle' ? 'success' : ($status === 'syncing' ? 'info' : 'neutral');
|
||||
?>
|
||||
<span class="badge badge-<?php p($statusClass); ?>">
|
||||
<?php p(ucfirst($status)); ?>
|
||||
</span>
|
||||
@@ -177,8 +177,8 @@ style('astroglobe', 'astroglobe-settings');
|
||||
<td><strong><?php p($l->t('Errors (24h)')); ?></strong></td>
|
||||
<td>
|
||||
<?php
|
||||
$errors = $_['vectorSyncStatus']['errors_24h'] ?? 0;
|
||||
if ($errors > 0): ?>
|
||||
$errors = $_['vectorSyncStatus']['errors_24h'] ?? 0;
|
||||
if ($errors > 0): ?>
|
||||
<span class="error"><?php p($errors); ?></span>
|
||||
<?php else: ?>
|
||||
<?php p('0'); ?>
|
||||
@@ -213,13 +213,19 @@ style('astroglobe', 'astroglobe-settings');
|
||||
<div class="mcp-form-group">
|
||||
<label for="search-algorithm"><?php p($l->t('Search Algorithm')); ?></label>
|
||||
<select id="search-algorithm" name="algorithm" class="mcp-select">
|
||||
<option value="hybrid" <?php if ($_['searchSettings']['algorithm'] === 'hybrid') echo 'selected'; ?>>
|
||||
<option value="hybrid" <?php if ($_['searchSettings']['algorithm'] === 'hybrid') {
|
||||
echo 'selected';
|
||||
} ?>>
|
||||
<?php p($l->t('Hybrid (Recommended)')); ?>
|
||||
</option>
|
||||
<option value="semantic" <?php if ($_['searchSettings']['algorithm'] === 'semantic') echo 'selected'; ?>>
|
||||
<option value="semantic" <?php if ($_['searchSettings']['algorithm'] === 'semantic') {
|
||||
echo 'selected';
|
||||
} ?>>
|
||||
<?php p($l->t('Semantic Only')); ?>
|
||||
</option>
|
||||
<option value="bm25" <?php if ($_['searchSettings']['algorithm'] === 'bm25') echo 'selected'; ?>>
|
||||
<option value="bm25" <?php if ($_['searchSettings']['algorithm'] === 'bm25') {
|
||||
echo 'selected';
|
||||
} ?>>
|
||||
<?php p($l->t('Keyword (BM25) Only')); ?>
|
||||
</option>
|
||||
</select>
|
||||
@@ -231,10 +237,14 @@ style('astroglobe', 'astroglobe-settings');
|
||||
<div class="mcp-form-group">
|
||||
<label for="search-fusion"><?php p($l->t('Fusion Method')); ?></label>
|
||||
<select id="search-fusion" name="fusion" class="mcp-select">
|
||||
<option value="rrf" <?php if ($_['searchSettings']['fusion'] === 'rrf') echo 'selected'; ?>>
|
||||
<option value="rrf" <?php if ($_['searchSettings']['fusion'] === 'rrf') {
|
||||
echo 'selected';
|
||||
} ?>>
|
||||
<?php p($l->t('RRF - Reciprocal Rank Fusion (Recommended)')); ?>
|
||||
</option>
|
||||
<option value="dbsf" <?php if ($_['searchSettings']['fusion'] === 'dbsf') echo 'selected'; ?>>
|
||||
<option value="dbsf" <?php if ($_['searchSettings']['fusion'] === 'dbsf') {
|
||||
echo 'selected';
|
||||
} ?>>
|
||||
<?php p($l->t('DBSF - Distribution-Based Score Fusion')); ?>
|
||||
</option>
|
||||
</select>
|
||||
|
||||
Reference in New Issue
Block a user