endpoint.blade.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. @php
  2. /** @var Knuckles\Camel\Output\OutputEndpointData $endpoint */
  3. @endphp
  4. <div class="sl-stack sl-stack--vertical sl-stack--8 HttpOperation sl-flex sl-flex-col sl-items-stretch sl-w-full">
  5. <div class="sl-stack sl-stack--vertical sl-stack--5 sl-flex sl-flex-col sl-items-stretch">
  6. <div class="sl-relative">
  7. <div class="sl-stack sl-stack--horizontal sl-stack--5 sl-flex sl-flex-row sl-items-center">
  8. <h2 class="sl-text-3xl sl-leading-tight sl-font-prose sl-text-heading sl-mt-5 sl-mb-1"
  9. id="{!! $endpoint->fullSlug() !!}">
  10. {{ $endpoint->name() }}
  11. </h2>
  12. </div>
  13. </div>
  14. <div class="sl-relative">
  15. <div title="{{ rtrim($baseUrl, '/') . '/'. ltrim($endpoint->uri, '/') }}"
  16. class="sl-stack sl-stack--horizontal sl-stack--3 sl-inline-flex sl-flex-row sl-items-center sl-max-w-full sl-font-mono sl-py-2 sl-pr-4 sl-bg-canvas-50 sl-rounded-lg"
  17. >
  18. @foreach($endpoint->httpMethods as $method)
  19. <div class="sl-text-lg sl-font-semibold sl-px-2.5 sl-py-1 sl-text-on-primary sl-rounded-lg"
  20. style="background-color: {{ \Knuckles\Scribe\Tools\WritingUtils::$httpMethodToCssColour[$method] }};"
  21. >
  22. {{ $method }}
  23. </div>
  24. @endforeach
  25. <div class="sl-flex sl-overflow-x-hidden sl-text-lg sl-select-all">
  26. <div dir="rtl"
  27. class="sl-overflow-x-hidden sl-truncate sl-text-muted">{{ rtrim($baseUrl, '/') }}</div>
  28. <div class="sl-flex-1 sl-font-semibold">/{{ ltrim($endpoint->uri, '/') }}</div>
  29. </div>
  30. @if($endpoint->metadata->authenticated)
  31. <div class="sl-font-prose sl-font-semibold sl-px-1.5 sl-py-0.5 sl-text-on-primary sl-rounded-lg"
  32. style="background-color: darkred"
  33. >requires authentication
  34. </div>
  35. @endif
  36. </div>
  37. </div>
  38. {!! Parsedown::instance()->text($endpoint->metadata->description ?: '') !!}
  39. </div>
  40. <div class="sl-flex">
  41. <div data-testid="two-column-left" class="sl-flex-1 sl-w-0">
  42. <div class="sl-stack sl-stack--vertical sl-stack--10 sl-flex sl-flex-col sl-items-stretch">
  43. <div class="sl-stack sl-stack--vertical sl-stack--8 sl-flex sl-flex-col sl-items-stretch">
  44. @if(count($endpoint->headers))
  45. <div class="sl-stack sl-stack--vertical sl-stack--5 sl-flex sl-flex-col sl-items-stretch">
  46. <h3 class="sl-text-2xl sl-leading-snug sl-font-prose">
  47. {{ __("scribe::endpoint.headers") }}
  48. </h3>
  49. <div class="sl-text-sm">
  50. @foreach($endpoint->headers as $header => $value)
  51. @component('scribe::themes.elements.components.field-details', [
  52. 'name' => $header,
  53. 'type' => null,
  54. 'required' => false,
  55. 'description' => null,
  56. 'example' => $value,
  57. 'endpointId' => $endpoint->endpointId(),
  58. 'component' => 'header',
  59. 'isInput' => true,
  60. ])
  61. @endcomponent
  62. @endforeach
  63. </div>
  64. </div>
  65. @endif
  66. @if(count($endpoint->urlParameters))
  67. <div class="sl-stack sl-stack--vertical sl-stack--6 sl-flex sl-flex-col sl-items-stretch">
  68. <h3 class="sl-text-2xl sl-leading-snug sl-font-prose">{{ __("scribe::endpoint.url_parameters") }}</h3>
  69. <div class="sl-text-sm">
  70. @foreach($endpoint->urlParameters as $attribute => $parameter)
  71. @component('scribe::themes.elements.components.field-details', [
  72. 'name' => $parameter->name,
  73. 'type' => $parameter->type ?? 'string',
  74. 'required' => $parameter->required,
  75. 'description' => $parameter->description,
  76. 'example' => $parameter->example ?? '',
  77. 'endpointId' => $endpoint->endpointId(),
  78. 'component' => 'url',
  79. 'isInput' => true,
  80. ])
  81. @endcomponent
  82. @endforeach
  83. </div>
  84. </div>
  85. @endif
  86. @if(count($endpoint->queryParameters))
  87. <div class="sl-stack sl-stack--vertical sl-stack--6 sl-flex sl-flex-col sl-items-stretch">
  88. <h3 class="sl-text-2xl sl-leading-snug sl-font-prose">{{ __("scribe::endpoint.query_parameters") }}</h3>
  89. <div class="sl-text-sm">
  90. @foreach($endpoint->queryParameters as $attribute => $parameter)
  91. @component('scribe::themes.elements.components.field-details', [
  92. 'name' => $parameter->name,
  93. 'type' => $parameter->type,
  94. 'required' => $parameter->required,
  95. 'description' => $parameter->description,
  96. 'example' => $parameter->example ?? '',
  97. 'endpointId' => $endpoint->endpointId(),
  98. 'component' => 'query',
  99. 'isInput' => true,
  100. ])
  101. @endcomponent
  102. @endforeach
  103. </div>
  104. </div>
  105. @endif
  106. @if(count($endpoint->nestedBodyParameters))
  107. <div class="sl-stack sl-stack--vertical sl-stack--6 sl-flex sl-flex-col sl-items-stretch">
  108. <h3 class="sl-text-2xl sl-leading-snug sl-font-prose">{{ __("scribe::endpoint.body_parameters") }}</h3>
  109. <div class="sl-text-sm">
  110. @component('scribe::themes.elements.components.nested-fields', [
  111. 'fields' => $endpoint->nestedBodyParameters,
  112. 'endpointId' => $endpoint->endpointId(),
  113. ])
  114. @endcomponent
  115. </div>
  116. </div>
  117. @endif
  118. @if(count($endpoint->responseFields))
  119. <div class="sl-stack sl-stack--vertical sl-stack--6 sl-flex sl-flex-col sl-items-stretch">
  120. <h3 class="sl-text-2xl sl-leading-snug sl-font-prose">{{ __("scribe::endpoint.response_fields") }}</h3>
  121. <div class="sl-text-sm">
  122. @component('scribe::themes.elements.components.nested-fields', [
  123. 'fields' => $endpoint->nestedResponseFields,
  124. 'endpointId' => $endpoint->endpointId(),
  125. 'isInput' => false,
  126. ])
  127. @endcomponent
  128. </div>
  129. </div>
  130. @endif
  131. </div>
  132. </div>
  133. </div>
  134. <div data-testid="two-column-right" class="sl-relative sl-w-2/5 sl-ml-16" style="max-width: 500px;">
  135. <div class="sl-stack sl-stack--vertical sl-stack--6 sl-flex sl-flex-col sl-items-stretch">
  136. @if($metadata['try_it_out']['enabled'] ?? false)
  137. @include("scribe::themes.elements.try_it_out")
  138. @endif
  139. @if($metadata['example_languages'])
  140. <div class="sl-panel sl-outline-none sl-w-full sl-rounded-lg">
  141. <div class="sl-panel__titlebar sl-flex sl-items-center sl-relative focus:sl-z-10 sl-text-base sl-leading-none sl-pr-3 sl-pl-4 sl-bg-canvas-200 sl-text-body sl-border-input focus:sl-border-primary sl-select-none">
  142. <div class="sl-flex sl-flex-1 sl-items-center sl-h-lg">
  143. <div class="sl--ml-2">
  144. {{ __("scribe::example_request") }}:
  145. <select class="example-request-lang-toggle sl-text-base"
  146. aria-label="Request Sample Language"
  147. onchange="switchExampleLanguage(event.target.value);">
  148. @foreach($metadata['example_languages'] as $language)
  149. <option>{{ $language }}</option>
  150. @endforeach
  151. </select>
  152. </div>
  153. </div>
  154. </div>
  155. @foreach($metadata['example_languages'] as $index => $language)
  156. <div class="sl-bg-canvas-100 example-request example-request-{{ $language }}"
  157. style="{{ $index == 0 ? '' : 'display: none;' }}">
  158. <div class="sl-px-0 sl-py-1">
  159. <div style="max-height: 400px;" class="sl-rounded">
  160. @include("scribe::partials.example-requests.$language")
  161. </div>
  162. </div>
  163. </div>
  164. @endforeach
  165. </div>
  166. @endif
  167. @if($endpoint->isGet() || $endpoint->hasResponses())
  168. <div class="sl-panel sl-outline-none sl-w-full sl-rounded-lg">
  169. <div class="sl-panel__titlebar sl-flex sl-items-center sl-relative focus:sl-z-10 sl-text-base sl-leading-none sl-pr-3 sl-pl-4 sl-bg-canvas-200 sl-text-body sl-border-input focus:sl-border-primary sl-select-none">
  170. <div class="sl-flex sl-flex-1 sl-items-center sl-py-2">
  171. <div class="sl--ml-2">
  172. <div class="sl-h-sm sl-text-base sl-font-medium sl-px-1.5 sl-text-muted sl-rounded sl-border-transparent sl-border">
  173. <div class="sl-mb-2 sl-inline-block">{{ __("scribe::example_response") }}:</div>
  174. <div class="sl-mb-2 sl-inline-block">
  175. <select
  176. class="example-response-{{ $endpoint->endpointId() }}-toggle sl-text-base"
  177. aria-label="Response sample"
  178. onchange="switchExampleResponse('{{ $endpoint->endpointId() }}', event.target.value);">
  179. @foreach($endpoint->responses as $index => $response)
  180. <option value="{{ $index }}">{{ $response->fullDescription() }}</option>
  181. @endforeach
  182. </select></div>
  183. </div>
  184. </div>
  185. </div>
  186. <button type="button"
  187. class="sl-button sl-h-sm sl-text-base sl-font-medium sl-px-1.5 hover:sl-bg-canvas-50 active:sl-bg-canvas-100 sl-text-muted hover:sl-text-body focus:sl-text-body sl-rounded sl-border-transparent sl-border disabled:sl-opacity-70">
  188. <div class="sl-mx-0">
  189. <svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="copy"
  190. class="svg-inline--fa fa-copy fa-fw fa-sm sl-icon" role="img"
  191. xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
  192. <path fill="currentColor"
  193. d="M384 96L384 0h-112c-26.51 0-48 21.49-48 48v288c0 26.51 21.49 48 48 48H464c26.51 0 48-21.49 48-48V128h-95.1C398.4 128 384 113.6 384 96zM416 0v96h96L416 0zM192 352V128h-144c-26.51 0-48 21.49-48 48v288c0 26.51 21.49 48 48 48h192c26.51 0 48-21.49 48-48L288 416h-32C220.7 416 192 387.3 192 352z"></path>
  194. </svg>
  195. </div>
  196. </button>
  197. </div>
  198. @foreach($endpoint->responses as $index => $response)
  199. <div class="sl-panel__content-wrapper sl-bg-canvas-100 example-response-{{ $endpoint->endpointId() }} example-response-{{ $endpoint->endpointId() }}-{{ $index }}"
  200. style=" {{ $index == 0 ? '' : 'display: none;' }}"
  201. >
  202. <div class="sl-panel__content sl-p-0">@if(count($response->headers))
  203. <details class="sl-pl-2">
  204. <summary style="cursor: pointer; list-style: none;">
  205. <small>
  206. <span class="expansion-chevrons">
  207. <svg aria-hidden="true" focusable="false" data-prefix="fas"
  208. data-icon="chevron-right"
  209. class="svg-inline--fa fa-chevron-right fa-fw sl-icon sl-text-muted"
  210. xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
  211. <path fill="currentColor"
  212. d="M96 480c-8.188 0-16.38-3.125-22.62-9.375c-12.5-12.5-12.5-32.75 0-45.25L242.8 256L73.38 86.63c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0l192 192c12.5 12.5 12.5 32.75 0 45.25l-192 192C112.4 476.9 104.2 480 96 480z"></path>
  213. </svg>
  214. </span>
  215. Headers
  216. </small>
  217. </summary>
  218. <pre><code class="language-http">@foreach($response->headers as $header => $value)
  219. {{ $header }}
  220. : {{ is_array($value) ? implode('; ', $value) : $value }}
  221. @endforeach </code></pre>
  222. </details>
  223. @endif
  224. @if(is_string($response->content) && Str::startsWith($response->content, "<<binary>>"))
  225. <pre><code>[{{ __("scribe::example_response.binary") }}] - {{ htmlentities(str_replace("<<binary>>", "", $response->content)) }}</code></pre>
  226. @elseif($response->status == 204)
  227. <pre><code>[{{ __("scribe::example_response.empty") }}]</code></pre>
  228. @else
  229. @php($parsed = json_decode($response->content))
  230. {{-- If response is a JSON string, prettify it. Otherwise, just print it --}}
  231. <pre><code style="max-height: 300px;"
  232. class="language-json sl-overflow-x-auto sl-overflow-y-auto">{!! htmlentities($parsed != null ? json_encode($parsed, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) : $response->content) !!}</code></pre>
  233. @endif
  234. </div>
  235. </div>
  236. @endforeach
  237. </div>
  238. @endif
  239. </div>
  240. </div>
  241. </div>