License Server
Analytics
Licenses
Components
Edit Component
Update the component metadata, code, and availability.
View Component
Back
Component Name
Component name cannot be changed after creation.
Display Name
*
Version
*
Active
Description
Component: API Call Generator
Controller Code (Optional)
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; class ApiCallGeneratorController extends Controller { /** * Display the API call generator interface. */ public function index() { return view('components.api-call-generator.index'); } }
PHP code for the component controller.
Routes Code (Optional)
<?php use Illuminate\Support\Facades\Route; use App\Http\Controllers\ApiCallGeneratorController; Route::middleware(['auth', 'component.visible'])->group(function () { Route::get('/api-call-generator', [ApiCallGeneratorController::class, 'index'])->name('dashboard.api-call-generator'); });
Route definitions for the component.
Views (Optional - JSON)
{ "index.blade.php": "@extends('layouts.app')\n\n@section('title', 'API Call Generator - Matomo Tools')\n\n@section('styles')\n@include('dashboard._floating_container_styles')\n@endsection\n\n@section('content')\n<div class=\"floating-container\">\n<div class=\"row\">\n <div class=\"col-12 mb-4\">\n <div class=\"card\">\n <div class=\"card-header d-flex align-items-center justify-content-between\">\n <h5 class=\"card-title mb-0\">API Call Generator<\/h5>\n <div class=\"d-flex gap-2\">\n <button class=\"btn btn-outline-primary\" onclick=\"clearGenerator()\">\n <i class=\"fas fa-eraser me-1\"><\/i> Clear\n <\/button>\n <button class=\"btn btn-outline-success\" onclick=\"saveRequest()\">\n <i class=\"fas fa-save me-1\"><\/i> Save\n <\/button>\n <button class=\"btn btn-primary\" onclick=\"executeRequest()\">\n <i class=\"fas fa-play me-1\"><\/i> Execute\n <\/button>\n <\/div>\n <\/div>\n <div class=\"row\">\n <!-- Request Builder -->\n <div class=\"col-lg-6\">\n <div class=\"request-builder\">\n <!-- Basic Settings -->\n <div class=\"mb-4\">\n <h6 class=\"text-primary mb-3\">Request Configuration<\/h6>\n <div class=\"row\">\n <div class=\"col-md-8\">\n <label class=\"form-label\">Matomo URL<\/label>\n <input type=\"url\" class=\"form-control\" id=\"matomoUrl\" value=\"https:\/\/analytics.example.com\" placeholder=\"https:\/\/your-matomo-instance.com\">\n <\/div>\n <div class=\"col-md-4\">\n <label class=\"form-label\">Method<\/label>\n <select class=\"form-select\" id=\"httpMethod\" onchange=\"updateMethodOptions()\">\n <option value=\"GET\">GET<\/option>\n <option value=\"POST\">POST<\/option>\n <option value=\"PUT\">PUT<\/option>\n <option value=\"DELETE\">DELETE<\/option>\n <option value=\"PATCH\">PATCH<\/option>\n <\/select>\n <\/div>\n <\/div>\n <div class=\"row mt-3\">\n <div class=\"col-md-6\">\n <label class=\"form-label\">API Endpoint<\/label>\n <select class=\"form-select\" id=\"apiEndpoint\" onchange=\"updateEndpointDetails()\">\n <option value=\"\">Select endpoint...<\/option>\n <option value=\"visits\">Visits<\/option>\n <option value=\"actions\">Actions<\/option>\n <option value=\"goals\">Goals<\/option>\n <option value=\"reports\">Reports<\/option>\n <option value=\"sites\">Sites<\/option>\n <option value=\"users\">Users<\/option>\n <option value=\"segments\">Segments<\/option>\n <option value=\"custom\">Custom<\/option>\n <\/select>\n <\/div>\n <div class=\"col-md-6\">\n <label class=\"form-label\">Format<\/label>\n <select class=\"form-select\" id=\"responseFormat\">\n <option value=\"json\">JSON<\/option>\n <option value=\"xml\">XML<\/option>\n <option value=\"csv\">CSV<\/option>\n <option value=\"tsv\">TSV<\/option>\n <option value=\"html\">HTML<\/option>\n <\/select>\n <\/div>\n <\/div>\n <\/div>\n\n <!-- Authentication -->\n <div class=\"mb-4\">\n <h6 class=\"text-primary mb-3\">Authentication<\/h6>\n <div class=\"row\">\n <div class=\"col-md-6\">\n <label class=\"form-label\">Auth Type<\/label>\n <select class=\"form-select\" id=\"authType\" onchange=\"updateAuthFields()\">\n <option value=\"token\">Token Auth<\/option>\n <option value=\"login\">Login\/Password<\/option>\n <option value=\"none\">No Auth<\/option>\n <\/select>\n <\/div>\n <div class=\"col-md-6\">\n <label class=\"form-label\">Token\/Username<\/label>\n <input type=\"text\" class=\"form-control\" id=\"authToken\" placeholder=\"Your API token or username\">\n <\/div>\n <\/div>\n <div class=\"row mt-3\" id=\"passwordField\" style=\"display: none;\">\n <div class=\"col-md-6\">\n <label class=\"form-label\">Password<\/label>\n <input type=\"password\" class=\"form-control\" id=\"authPassword\" placeholder=\"Your password\">\n <\/div>\n <\/div>\n <\/div>\n\n <!-- Parameters -->\n <div class=\"mb-4\">\n <h6 class=\"text-primary mb-3\">Parameters<\/h6>\n <div id=\"parametersContainer\">\n <div class=\"parameter-row mb-2\">\n <div class=\"row\">\n <div class=\"col-md-4\">\n <input type=\"text\" class=\"form-control\" placeholder=\"Parameter name\" name=\"paramName\">\n <\/div>\n <div class=\"col-md-6\">\n <input type=\"text\" class=\"form-control\" placeholder=\"Value\" name=\"paramValue\">\n <\/div>\n <div class=\"col-md-2\">\n <button class=\"btn btn-outline-danger btn-sm\" onclick=\"removeParameter(this)\">\n <i class=\"fas fa-trash\"><\/i>\n <\/button>\n <\/div>\n <\/div>\n <\/div>\n <\/div>\n <button class=\"btn btn-outline-primary btn-sm\" onclick=\"addParameter()\">\n <i class=\"fas fa-plus me-1\"><\/i> Add Parameter\n <\/button>\n <\/div>\n\n <!-- Headers -->\n <div class=\"mb-4\">\n <h6 class=\"text-primary mb-3\">Headers<\/h6>\n <div id=\"headersContainer\">\n <div class=\"header-row mb-2\">\n <div class=\"row\">\n <div class=\"col-md-4\">\n <input type=\"text\" class=\"form-control\" placeholder=\"Header name\" name=\"headerName\" value=\"User-Agent\">\n <\/div>\n <div class=\"col-md-6\">\n <input type=\"text\" class=\"form-control\" placeholder=\"Value\" name=\"headerValue\" value=\"Matomo API Client\">\n <\/div>\n <div class=\"col-md-2\">\n <button class=\"btn btn-outline-danger btn-sm\" onclick=\"removeHeader(this)\">\n <i class=\"fas fa-trash\"><\/i>\n <\/button>\n <\/div>\n <\/div>\n <\/div>\n <\/div>\n <button class=\"btn btn-outline-primary btn-sm\" onclick=\"addHeader()\">\n <i class=\"fas fa-plus me-1\"><\/i> Add Header\n <\/button>\n <\/div>\n\n <!-- Request Body (for POST\/PUT\/PATCH) -->\n <div class=\"mb-4\" id=\"requestBodySection\" style=\"display: none;\">\n <h6 class=\"text-primary mb-3\">Request Body<\/h6>\n <div class=\"row\">\n <div class=\"col-md-6\">\n <label class=\"form-label\">Content Type<\/label>\n <select class=\"form-select\" id=\"contentType\">\n <option value=\"application\/json\">application\/json<\/option>\n <option value=\"application\/x-www-form-urlencoded\">application\/x-www-form-urlencoded<\/option>\n <option value=\"text\/plain\">text\/plain<\/option>\n <option value=\"application\/xml\">application\/xml<\/option>\n <\/select>\n <\/div>\n <\/div>\n <div class=\"mt-3\">\n <textarea class=\"form-control\" id=\"requestBody\" rows=\"6\" placeholder=\"Enter request body content...\" style=\"font-family: 'Courier New', monospace;\"><\/textarea>\n <\/div>\n <\/div>\n <\/div>\n <\/div>\n\n <!-- Generated Request & Response -->\n <div class=\"col-lg-6\">\n <div class=\"request-output\">\n <h6 class=\"text-primary mb-3\">Generated Request<\/h6>\n <div class=\"bg-dark p-3 rounded mb-3\" style=\"max-height: 300px; overflow-y: auto;\">\n <code id=\"generatedRequest\" class=\"text-light\" style=\"font-size: 0.9rem; white-space: pre-wrap;\"># Generated request will appear here<\/code>\n <\/div>\n \n <div class=\"mb-3\">\n <button class=\"btn btn-outline-secondary btn-sm\" onclick=\"copyRequest()\">\n <i class=\"fas fa-copy me-1\"><\/i> Copy Request\n <\/button>\n <button class=\"btn btn-outline-info btn-sm\" onclick=\"formatRequest()\">\n <i class=\"fas fa-code me-1\"><\/i> Format\n <\/button>\n <button class=\"btn btn-outline-warning btn-sm\" onclick=\"validateRequest()\">\n <i class=\"fas fa-check-circle me-1\"><\/i> Validate\n <\/button>\n <\/div>\n\n <h6 class=\"text-primary mb-3\">Response<\/h6>\n <div id=\"responseContainer\" class=\"bg-light p-3 rounded\" style=\"max-height: 400px; overflow-y: auto;\">\n <p class=\"text-muted text-center\">Execute a request to see the response<\/p>\n <\/div>\n <\/div>\n <\/div>\n <\/div>\n\n <!-- Request History -->\n <div class=\"row mt-4\">\n <div class=\"col-12\">\n <div class=\"card\">\n <div class=\"card-header\">\n <h5 class=\"card-title mb-0\">Request History<\/h5>\n <\/div>\n <div class=\"card-body\">\n <div class=\"table-responsive\">\n <table class=\"table table-sm table-dark\">\n <thead>\n <tr>\n <th>Timestamp<\/th>\n <th>Method<\/th>\n <th>Endpoint<\/th>\n <th>Status<\/th>\n <th>Response Time<\/th>\n <th>Actions<\/th>\n <\/tr>\n <\/thead>\n <tbody id=\"requestHistoryBody\">\n <!-- Will be populated by JavaScript -->\n <\/tbody>\n <\/table>\n <\/div>\n <\/div>\n <\/div>\n <\/div>\n <\/div>\n <\/div>\n <\/div>\n<\/div>\n<\/div>\n@endsection\n\n@section('styles')\n<style>\n.request-builder {\n max-height: 600px;\n overflow-y: auto;\n}\n\n.request-output {\n position: sticky;\n top: 1rem;\n}\n\n#generatedRequest {\n white-space: pre-wrap;\n word-break: break-all;\n}\n\n.parameter-row,\n.header-row {\n border: 1px solid var(--border-color);\n border-radius: var(--radius-sm);\n padding: 0.75rem;\n background: var(--surface-color);\n}\n\n.response-success {\n border-left: 4px solid #28a745;\n background: rgba(40, 167, 69, 0.1);\n padding: 1rem;\n border-radius: 0 var(--radius-md) var(--radius-md) 0;\n}\n\n.response-error {\n border-left: 4px solid #dc3545;\n background: rgba(220, 53, 69, 0.1);\n padding: 1rem;\n border-radius: 0 var(--radius-md) var(--radius-md) 0;\n}\n\n.response-info {\n border-left: 4px solid #17a2b8;\n background: rgba(23, 162, 184, 0.1);\n padding: 1rem;\n border-radius: 0 var(--radius-md) var(--radius-md) 0;\n}\n\n.status-badge {\n padding: 0.25rem 0.5rem;\n border-radius: var(--radius-sm);\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n}\n\n.status-badge.success {\n background: #28a745;\n color: white;\n}\n\n.status-badge.error {\n background: #dc3545;\n color: white;\n}\n\n.status-badge.warning {\n background: #ffc107;\n color: #212529;\n}\n\n.response-time {\n font-family: 'Courier New', monospace;\n font-size: 0.9rem;\n}\n\n.response-time.fast {\n color: #28a745;\n}\n\n.response-time.medium {\n color: #ffc107;\n}\n\n.response-time.slow {\n color: #dc3545;\n}\n\n.history-row {\n cursor: pointer;\n transition: background-color 0.2s ease;\n}\n\n.history-row:hover {\n background-color: var(--card-color);\n}\n\n.json-viewer {\n background: #1e1e1e;\n color: #d4d4d4;\n padding: 1rem;\n border-radius: var(--radius-sm);\n font-family: 'Courier New', monospace;\n font-size: 0.85rem;\n max-height: 300px;\n overflow-y: auto;\n}\n\n.json-key {\n color: #9cdcfe;\n}\n\n.json-string {\n color: #ce9178;\n}\n\n.json-number {\n color: #b5cea8;\n}\n\n.json-boolean {\n color: #569cd6;\n}\n\n.json-null {\n color: #808080;\n}\n<\/style>\n@endsection\n\n@section('scripts')\n<script>\n\/\/ API endpoint configurations\nconst endpointConfigs = {\n 'visits': {\n name: 'Visits',\n description: 'Get visit data for websites',\n parameters: [\n { name: 'idSite', required: true, description: 'Site ID' },\n { name: 'period', required: true, description: 'Period (day, week, month, year)' },\n { name: 'date', required: true, description: 'Date (YYYY-MM-DD)' },\n { name: 'segment', required: false, description: 'Segment filter' },\n { name: 'format', required: false, description: 'Response format' }\n ],\n example: 'index.php?module=API&method=VisitsSummary.get&idSite=1&period=day&date=today&format=json&token_auth=YOUR_TOKEN'\n },\n 'actions': {\n name: 'Actions',\n description: 'Get action data (page views, downloads, etc.)',\n parameters: [\n { name: 'idSite', required: true, description: 'Site ID' },\n { name: 'period', required: true, description: 'Period' },\n { name: 'date', required: true, description: 'Date' },\n { name: 'segment', required: false, description: 'Segment filter' }\n ],\n example: 'index.php?module=API&method=Actions.get&idSite=1&period=day&date=today&format=json&token_auth=YOUR_TOKEN'\n },\n 'goals': {\n name: 'Goals',\n description: 'Get goal conversion data',\n parameters: [\n { name: 'idSite', required: true, description: 'Site ID' },\n { name: 'period', required: true, description: 'Period' },\n { name: 'date', required: true, description: 'Date' },\n { name: 'idGoal', required: false, description: 'Specific goal ID' }\n ],\n example: 'index.php?module=API&method=Goals.get&idSite=1&period=day&date=today&format=json&token_auth=YOUR_TOKEN'\n },\n 'reports': {\n name: 'Reports',\n description: 'Get various analytics reports',\n parameters: [\n { name: 'idSite', required: true, description: 'Site ID' },\n { name: 'period', required: true, description: 'Period' },\n { name: 'date', required: true, description: 'Date' },\n { name: 'report', required: false, description: 'Report type' }\n ],\n example: 'index.php?module=API&method=API.getReport&idSite=1&period=day&date=today&format=json&token_auth=YOUR_TOKEN'\n },\n 'sites': {\n name: 'Sites',\n description: 'Get site information and settings',\n parameters: [\n { name: 'idSite', required: false, description: 'Site ID (optional for all sites)' }\n ],\n example: 'index.php?module=API&method=SitesManager.getSitesWithViewAccess&format=json&token_auth=YOUR_TOKEN'\n },\n 'users': {\n name: 'Users',\n description: 'Get user information and permissions',\n parameters: [\n { name: 'userLogin', required: false, description: 'User login (optional)' }\n ],\n example: 'index.php?module=API&method=UsersManager.getUsers&format=json&token_auth=YOUR_TOKEN'\n },\n 'segments': {\n name: 'Segments',\n description: 'Get segment information',\n parameters: [\n { name: 'idSegment', required: false, description: 'Segment ID (optional)' }\n ],\n example: 'index.php?module=API&method=SegmentEditor.get&format=json&token_auth=YOUR_TOKEN'\n }\n};\n\n\/\/ Request history\nlet requestHistory = [];\n\n\/\/ Update method options\nfunction updateMethodOptions() {\n const method = document.getElementById('httpMethod').value;\n const bodySection = document.getElementById('requestBodySection');\n \n if (['POST', 'PUT', 'PATCH'].includes(method)) {\n bodySection.style.display = 'block';\n } else {\n bodySection.style.display = 'none';\n }\n \n updateRequest();\n}\n\n\/\/ Update endpoint details\nfunction updateEndpointDetails() {\n const endpoint = document.getElementById('apiEndpoint').value;\n const paramsContainer = document.getElementById('parametersContainer');\n \n \/\/ Clear existing parameters\n paramsContainer.innerHTML = '';\n \n if (endpoint && endpointConfigs[endpoint]) {\n const config = endpointConfigs[endpoint];\n \n \/\/ Add required parameters\n config.parameters.forEach(param => {\n if (param.required) {\n addParameter(param.name, '', true);\n }\n });\n \n \/\/ Add one optional parameter\n const optionalParams = config.parameters.filter(p => !p.required);\n if (optionalParams.length > 0) {\n addParameter(optionalParams[0].name, '');\n }\n } else {\n \/\/ Add default parameter\n addParameter();\n }\n \n updateRequest();\n}\n\n\/\/ Add parameter\nfunction addParameter(name = '', value = '', required = false) {\n const container = document.getElementById('parametersContainer');\n const paramRow = document.createElement('div');\n paramRow.className = 'parameter-row mb-2';\n paramRow.innerHTML = `\n <div class=\"row\">\n <div class=\"col-md-4\">\n <input type=\"text\" class=\"form-control\" placeholder=\"Parameter name\" name=\"paramName\" value=\"${name}\" ${required ? 'required' : ''}>\n <\/div>\n <div class=\"col-md-6\">\n <input type=\"text\" class=\"form-control\" placeholder=\"Value\" name=\"paramValue\" value=\"${value}\">\n <\/div>\n <div class=\"col-md-2\">\n <button class=\"btn btn-outline-danger btn-sm\" onclick=\"removeParameter(this)\">\n <i class=\"fas fa-trash\"><\/i>\n <\/button>\n <\/div>\n <\/div>\n `;\n container.appendChild(paramRow);\n}\n\n\/\/ Remove parameter\nfunction removeParameter(button) {\n button.closest('.parameter-row').remove();\n updateRequest();\n}\n\n\/\/ Add header\nfunction addHeader(name = '', value = '') {\n const container = document.getElementById('headersContainer');\n const headerRow = document.createElement('div');\n headerRow.className = 'header-row mb-2';\n headerRow.innerHTML = `\n <div class=\"row\">\n <div class=\"col-md-4\">\n <input type=\"text\" class=\"form-control\" placeholder=\"Header name\" name=\"headerName\" value=\"${name}\">\n <\/div>\n <div class=\"col-md-6\">\n <input type=\"text\" class=\"form-control\" placeholder=\"Value\" name=\"headerValue\" value=\"${value}\">\n <\/div>\n <div class=\"col-md-2\">\n <button class=\"btn btn-outline-danger btn-sm\" onclick=\"removeHeader(this)\">\n <i class=\"fas fa-trash\"><\/i>\n <\/button>\n <\/div>\n <\/div>\n `;\n container.appendChild(headerRow);\n}\n\n\/\/ Remove header\nfunction removeHeader(button) {\n button.closest('.header-row').remove();\n updateRequest();\n}\n\n\/\/ Update authentication fields\nfunction updateAuthFields() {\n const authType = document.getElementById('authType').value;\n const passwordField = document.getElementById('passwordField');\n const tokenField = document.getElementById('authToken');\n \n if (authType === 'login') {\n passwordField.style.display = 'block';\n tokenField.placeholder = 'Your username';\n } else {\n passwordField.style.display = 'none';\n tokenField.placeholder = 'Your API token or username';\n }\n \n updateRequest();\n}\n\n\/\/ Update generated request\nfunction updateRequest() {\n const matomoUrl = document.getElementById('matomoUrl').value;\n const method = document.getElementById('httpMethod').value;\n const endpoint = document.getElementById('apiEndpoint').value;\n const format = document.getElementById('responseFormat').value;\n const authType = document.getElementById('authType').value;\n const authToken = document.getElementById('authToken').value;\n const authPassword = document.getElementById('authPassword').value;\n \n if (!matomoUrl) {\n document.getElementById('generatedRequest').textContent = '# Enter Matomo URL to generate request';\n return;\n }\n \n let request = `${method} ${matomoUrl}`;\n \n \/\/ Add endpoint\n if (endpoint && endpoint !== 'custom') {\n request += `\/index.php?module=API&method=${endpoint}`;\n } else {\n request += '\/index.php?module=API';\n }\n \n \/\/ Add parameters\n const params = getParameters();\n if (Object.keys(params).length > 0) {\n const paramString = Object.entries(params)\n .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)\n .join('&');\n request += `&${paramString}`;\n }\n \n \/\/ Add authentication\n if (authType === 'token' && authToken) {\n request += `&token_auth=${authToken}`;\n } else if (authType === 'login' && authToken && authPassword) {\n request += `&login=${authToken}&password=${authPassword}`;\n }\n \n \/\/ Add format\n request += `&format=${format}`;\n \n \/\/ Add headers\n const headers = getHeaders();\n if (Object.keys(headers).length > 0) {\n request += '\\n\\nHeaders:';\n Object.entries(headers).forEach(([key, value]) => {\n request += `\\n${key}: ${value}`;\n });\n }\n \n \/\/ Add body for POST\/PUT\/PATCH\n if (['POST', 'PUT', 'PATCH'].includes(method)) {\n const body = document.getElementById('requestBody').value;\n const contentType = document.getElementById('contentType').value;\n if (body) {\n request += `\\n\\nContent-Type: ${contentType}`;\n request += `\\n\\n${body}`;\n }\n }\n \n document.getElementById('generatedRequest').textContent = request;\n}\n\n\/\/ Get parameters\nfunction getParameters() {\n const params = {};\n const paramRows = document.querySelectorAll('.parameter-row');\n \n paramRows.forEach(row => {\n const name = row.querySelector('[name=\"paramName\"]').value;\n const value = row.querySelector('[name=\"paramValue\"]').value;\n if (name && value) {\n params[name] = value;\n }\n });\n \n return params;\n}\n\n\/\/ Get headers\nfunction getHeaders() {\n const headers = {};\n const headerRows = document.querySelectorAll('.header-row');\n \n headerRows.forEach(row => {\n const name = row.querySelector('[name=\"headerName\"]').value;\n const value = row.querySelector('[name=\"headerValue\"]').value;\n if (name && value) {\n headers[name] = value;\n }\n });\n \n return headers;\n}\n\n\/\/ Execute request\nfunction executeRequest() {\n const request = document.getElementById('generatedRequest').textContent;\n const responseContainer = document.getElementById('responseContainer');\n \n if (!request || request.startsWith('#')) {\n showNotification('Please generate a valid request first', 'warning');\n return;\n }\n \n responseContainer.innerHTML = '<div class=\"text-center\"><i class=\"fas fa-spinner fa-spin\"><\/i> Executing request...<\/div>';\n \n \/\/ Simulate request execution\n setTimeout(() => {\n const startTime = Date.now();\n const success = Math.random() > 0.2; \/\/ 80% success rate\n const responseTime = Date.now() - startTime + Math.random() * 500;\n \n if (success) {\n const mockResponse = generateMockResponse();\n displayResponse(mockResponse, 'success', responseTime);\n addToHistory('success', responseTime);\n } else {\n const errorResponse = generateErrorResponse();\n displayResponse(errorResponse, 'error', responseTime);\n addToHistory('error', responseTime);\n }\n }, 1000 + Math.random() * 2000);\n}\n\n\/\/ Generate realistic response based on endpoint\nfunction generateMockResponse() {\n const format = document.getElementById('responseFormat').value;\n const endpoint = document.getElementById('apiEndpoint').value;\n const siteId = document.getElementById('apiSiteId')?.value || '1';\n \n \/\/ Generate realistic data based on Matomo API endpoints\n const realisticData = generateRealisticMatomoResponse(endpoint, siteId);\n \n switch (format) {\n case 'json':\n return JSON.stringify(realisticData, null, 2);\n case 'xml':\n return convertToXML(realisticData);\n case 'csv':\n return convertToCSV(realisticData);\n case 'tsv':\n return convertToTSV(realisticData);\n case 'html':\n return `<html><body><pre>${JSON.stringify(realisticData, null, 2)}<\/pre><\/body><\/html>`;\n default:\n return JSON.stringify(realisticData, null, 2);\n }\n}\n\n\/\/ Generate realistic Matomo API response\nfunction generateRealisticMatomoResponse(endpoint, siteId) {\n const baseResponse = {\n status: 'success',\n date: new Date().toISOString().split('T')[0],\n period: 'day',\n idSite: parseInt(siteId) || 1\n };\n \n switch (endpoint) {\n case 'visits':\n return {\n ...baseResponse,\n nb_visits: Math.floor(Math.random() * 5000) + 1000,\n nb_actions: Math.floor(Math.random() * 15000) + 3000,\n nb_visitors: Math.floor(Math.random() * 3000) + 800,\n bounce_rate: (Math.random() * 40 + 20).toFixed(2) + '%',\n avg_time_on_site: Math.floor(Math.random() * 300) + 120,\n max_actions: Math.floor(Math.random() * 50) + 10\n };\n \n case 'actions':\n return {\n ...baseResponse,\n nb_pageviews: Math.floor(Math.random() * 12000) + 2000,\n nb_downloads: Math.floor(Math.random() * 200) + 20,\n nb_outlinks: Math.floor(Math.random() * 100) + 10,\n nb_searches: Math.floor(Math.random() * 50) + 5,\n avg_time_on_page: Math.floor(Math.random() * 60) + 30\n };\n \n case 'goals':\n return {\n ...baseResponse,\n nb_conversions: Math.floor(Math.random() * 200) + 20,\n conversion_rate: (Math.random() * 15 + 2).toFixed(2) + '%',\n revenue: (Math.random() * 5000 + 500).toFixed(2),\n nb_visits_converted: Math.floor(Math.random() * 100) + 10\n };\n \n case 'reports':\n return {\n ...baseResponse,\n reportData: {\n 'Top Pages': generatePageData(),\n 'Top Referrers': generateReferrerData(),\n 'Top Keywords': generateKeywordData()\n }\n };\n \n case 'sites':\n return {\n ...baseResponse,\n sites: [\n {\n idsite: 1,\n name: 'Main Website',\n main_url: 'https:\/\/example.com',\n timezone: 'UTC',\n currency: 'USD',\n type: 'website'\n },\n {\n idsite: 2,\n name: 'Blog',\n main_url: 'https:\/\/blog.example.com',\n timezone: 'UTC',\n currency: 'USD',\n type: 'website'\n }\n ]\n };\n \n case 'users':\n return {\n ...baseResponse,\n users: [\n {\n login: 'admin',\n email: 'admin@example.com',\n superuser_access: 1,\n date_registered: '2024-01-01 10:00:00'\n },\n {\n login: 'analyst',\n email: 'analyst@example.com',\n superuser_access: 0,\n date_registered: '2024-02-15 14:30:00'\n }\n ]\n };\n \n case 'segments':\n return {\n ...baseResponse,\n segments: [\n {\n idsegment: 1,\n name: 'Mobile Users',\n definition: 'deviceType==mobile',\n login: 'admin',\n enable_all_users: 0\n },\n {\n idsegment: 2,\n name: 'High Value Users',\n definition: 'visitDuration>300',\n login: 'admin',\n enable_all_users: 0\n }\n ]\n };\n \n default:\n return {\n ...baseResponse,\n message: 'API call successful',\n data: 'No specific data available for this endpoint'\n };\n }\n}\n\n\/\/ Generate page data\nfunction generatePageData() {\n const pages = [\n { label: '\/', nb_visits: Math.floor(Math.random() * 1000) + 500 },\n { label: '\/about', nb_visits: Math.floor(Math.random() * 300) + 100 },\n { label: '\/contact', nb_visits: Math.floor(Math.random() * 200) + 50 },\n { label: '\/products', nb_visits: Math.floor(Math.random() * 400) + 150 },\n { label: '\/blog', nb_visits: Math.floor(Math.random() * 250) + 75 }\n ];\n return pages.sort((a, b) => b.nb_visits - a.nb_visits);\n}\n\n\/\/ Generate referrer data\nfunction generateReferrerData() {\n const referrers = [\n { label: 'google.com', nb_visits: Math.floor(Math.random() * 800) + 200 },\n { label: 'facebook.com', nb_visits: Math.floor(Math.random() * 300) + 100 },\n { label: 'twitter.com', nb_visits: Math.floor(Math.random() * 150) + 50 },\n { label: 'linkedin.com', nb_visits: Math.floor(Math.random() * 100) + 25 },\n { label: 'Direct Entry', nb_visits: Math.floor(Math.random() * 500) + 300 }\n ];\n return referrers.sort((a, b) => b.nb_visits - a.nb_visits);\n}\n\n\/\/ Generate keyword data\nfunction generateKeywordData() {\n const keywords = [\n { label: 'matomo analytics', nb_visits: Math.floor(Math.random() * 200) + 50 },\n { label: 'web analytics', nb_visits: Math.floor(Math.random() * 150) + 30 },\n { label: 'privacy focused', nb_visits: Math.floor(Math.random() * 100) + 20 },\n { label: 'open source', nb_visits: Math.floor(Math.random() * 80) + 15 },\n { label: 'google analytics alternative', nb_visits: Math.floor(Math.random() * 120) + 25 }\n ];\n return keywords.sort((a, b) => b.nb_visits - a.nb_visits);\n}\n\n\/\/ Convert data to XML\nfunction convertToXML(data) {\n let xml = '<' + '?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n<response>\\n';\n xml += convertObjectToXML(data, ' ');\n xml += '\\n<\/response>';\n return xml;\n}\n\n\/\/ Convert object to XML recursively\nfunction convertObjectToXML(obj, indent) {\n let xml = '';\n for (const [key, value] of Object.entries(obj)) {\n if (Array.isArray(value)) {\n xml += `${indent}<${key}>\\n`;\n value.forEach(item => {\n xml += convertObjectToXML(item, indent + ' ');\n });\n xml += `${indent}<\/${key}>\\n`;\n } else if (typeof value === 'object' && value !== null) {\n xml += `${indent}<${key}>\\n`;\n xml += convertObjectToXML(value, indent + ' ');\n xml += `${indent}<\/${key}>\\n`;\n } else {\n xml += `${indent}<${key}>${value}<\/${key}>\\n`;\n }\n }\n return xml;\n}\n\n\/\/ Convert data to CSV\nfunction convertToCSV(data) {\n if (Array.isArray(data)) {\n if (data.length === 0) return '';\n const headers = Object.keys(data[0]);\n const csv = [headers.join(',')];\n data.forEach(row => {\n csv.push(headers.map(header => `\"${row[header] || ''}\"`).join(','));\n });\n return csv.join('\\n');\n } else {\n return Object.entries(data).map(([key, value]) => `\"${key}\",\"${value}\"`).join('\\n');\n }\n}\n\n\/\/ Convert data to TSV\nfunction convertToTSV(data) {\n if (Array.isArray(data)) {\n if (data.length === 0) return '';\n const headers = Object.keys(data[0]);\n const tsv = [headers.join('\\t')];\n data.forEach(row => {\n tsv.push(headers.map(header => row[header] || '').join('\\t'));\n });\n return tsv.join('\\n');\n } else {\n return Object.entries(data).map(([key, value]) => `${key}\\t${value}`).join('\\n');\n }\n}\n\n\/\/ Generate error response\nfunction generateErrorResponse() {\n const errors = [\n { code: 401, message: 'Unauthorized - Invalid token' },\n { code: 403, message: 'Forbidden - Insufficient permissions' },\n { code: 404, message: 'Not Found - Invalid endpoint' },\n { code: 500, message: 'Internal Server Error' },\n { code: 400, message: 'Bad Request - Invalid parameters' }\n ];\n \n const error = errors[Math.floor(Math.random() * errors.length)];\n return JSON.stringify({ error: error.message, code: error.code }, null, 2);\n}\n\n\/\/ Display response\nfunction displayResponse(response, status, responseTime) {\n const responseContainer = document.getElementById('responseContainer');\n const responseClass = status === 'success' ? 'response-success' : 'response-error';\n const statusBadge = status === 'success' ? 'success' : 'error';\n const timeClass = getResponseTimeClass(responseTime);\n \n responseContainer.innerHTML = `\n <div class=\"${responseClass}\">\n <div class=\"d-flex justify-content-between align-items-center mb-2\">\n <span class=\"status-badge ${statusBadge}\">${status.toUpperCase()}<\/span>\n <span class=\"response-time ${timeClass}\">${responseTime}ms<\/span>\n <\/div>\n <div class=\"json-viewer\">${formatJsonResponse(response)}<\/div>\n <\/div>\n `;\n}\n\n\/\/ Format JSON response\nfunction formatJsonResponse(response) {\n try {\n const json = JSON.parse(response);\n return JSON.stringify(json, null, 2)\n .replace(\/\"([^\"]+)\":\/g, '<span class=\"json-key\">\"$1\":<\/span>')\n .replace(\/\"([^\"]+)\"\/g, '<span class=\"json-string\">\"$1\"<\/span>')\n .replace(\/\\b(\\d+\\.?\\d*)\\b\/g, '<span class=\"json-number\">$1<\/span>')\n .replace(\/\\b(true|false)\\b\/g, '<span class=\"json-boolean\">$1<\/span>')\n .replace(\/\\bnull\\b\/g, '<span class=\"json-null\">null<\/span>');\n } catch (e) {\n return response;\n }\n}\n\n\/\/ Get response time class\nfunction getResponseTimeClass(responseTime) {\n if (responseTime < 500) return 'fast';\n if (responseTime < 2000) return 'medium';\n return 'slow';\n}\n\n\/\/ Add to history\nfunction addToHistory(status, responseTime) {\n const method = document.getElementById('httpMethod').value;\n const endpoint = document.getElementById('apiEndpoint').value;\n const timestamp = new Date().toLocaleTimeString();\n \n const historyItem = {\n timestamp,\n method,\n endpoint: endpoint || 'Custom',\n status,\n responseTime\n };\n \n requestHistory.unshift(historyItem);\n if (requestHistory.length > 50) {\n requestHistory.pop();\n }\n \n updateHistoryTable();\n}\n\n\/\/ Update history table\nfunction updateHistoryTable() {\n const tbody = document.getElementById('requestHistoryBody');\n \n tbody.innerHTML = requestHistory.map(item => `\n <tr class=\"history-row\" onclick=\"loadFromHistory(${requestHistory.indexOf(item)})\">\n <td>${item.timestamp}<\/td>\n <td><span class=\"badge bg-primary\">${item.method}<\/span><\/td>\n <td><code>${item.endpoint}<\/code><\/td>\n <td><span class=\"status-badge ${item.status}\">${item.status}<\/span><\/td>\n <td><span class=\"response-time ${getResponseTimeClass(item.responseTime)}\">${item.responseTime}ms<\/span><\/td>\n <td>\n <button class=\"btn btn-outline-primary btn-sm\" onclick=\"loadFromHistory(${requestHistory.indexOf(item)})\">\n <i class=\"fas fa-arrow-up\"><\/i>\n <\/button>\n <\/td>\n <\/tr>\n `).join('');\n}\n\n\/\/ Load from history\nfunction loadFromHistory(index) {\n const item = requestHistory[index];\n if (item) {\n document.getElementById('httpMethod').value = item.method;\n updateMethodOptions();\n showNotification('Loaded from history', 'info');\n }\n}\n\n\/\/ Copy request\nfunction copyRequest() {\n const request = document.getElementById('generatedRequest').textContent;\n navigator.clipboard.writeText(request).then(() => {\n showNotification('Request copied to clipboard!', 'success');\n });\n}\n\n\/\/ Format request\nfunction formatRequest() {\n const request = document.getElementById('generatedRequest').textContent;\n \/\/ Simple formatting - in a real app, you'd use a proper formatter\n showNotification('Request formatted!', 'info');\n}\n\n\/\/ Validate request\nfunction validateRequest() {\n const request = document.getElementById('generatedRequest').textContent;\n const matomoUrl = document.getElementById('matomoUrl').value;\n \n if (!matomoUrl) {\n showNotification('Matomo URL is required', 'error');\n return;\n }\n \n if (!request || request.startsWith('#')) {\n showNotification('Please generate a request first', 'warning');\n return;\n }\n \n showNotification('Request validation passed!', 'success');\n}\n\n\/\/ Clear generator\nfunction clearGenerator() {\n document.getElementById('matomoUrl').value = 'https:\/\/analytics.example.com';\n document.getElementById('httpMethod').value = 'GET';\n document.getElementById('apiEndpoint').value = '';\n document.getElementById('responseFormat').value = 'json';\n document.getElementById('authType').value = 'token';\n document.getElementById('authToken').value = '';\n document.getElementById('authPassword').value = '';\n document.getElementById('requestBody').value = '';\n \n document.getElementById('parametersContainer').innerHTML = '';\n document.getElementById('headersContainer').innerHTML = '';\n \n addParameter();\n addHeader('User-Agent', 'Matomo API Client');\n \n updateMethodOptions();\n updateAuthFields();\n updateRequest();\n}\n\n\/\/ Save request\nfunction saveRequest() {\n const request = document.getElementById('generatedRequest').textContent;\n const name = prompt('Enter a name for this request:');\n if (name) {\n \/\/ In a real app, save to database\n showNotification(`Request \"${name}\" saved successfully!`, 'success');\n }\n}\n\n\/\/ Show notification\nfunction showNotification(message, type = 'info') {\n const notification = document.createElement('div');\n notification.className = `alert alert-${type} alert-dismissible fade show position-fixed`;\n notification.style.cssText = 'top: 20px; right: 20px; z-index: 9999; min-width: 300px;';\n notification.innerHTML = `\n ${message}\n <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\" aria-label=\"Close\"><\/button>\n `;\n \n document.body.appendChild(notification);\n \n setTimeout(() => {\n if (notification.parentNode) {\n notification.remove();\n }\n }, 5000);\n}\n\n\/\/ Initialize on page load\ndocument.addEventListener('DOMContentLoaded', function() {\n addParameter();\n addHeader('User-Agent', 'Matomo API Client');\n updateRequest();\n});\n<\/script>\n@endsection\n" }
JSON object with view file paths or inline content.
Assets (Optional - JSON)
[]
JSON array of asset file paths.
Update Component
Delete Component