Files
svc-api-x/v1/taffy/dashboard/dashboard.cfm

567 lines
29 KiB
Plaintext

<!DOCTYPE HTML>
<html>
<head>
<title>Taffy Dashboard</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="https://fav.farm/🍬" />
<cfif application._taffy.settings.allowGoogleFonts>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible:wght@400;500;600;700&family=Atkinson+Hyperlegible+Mono:wght@400;600;700&display=swap" rel="stylesheet">
</cfif>
<style>
<cfinclude template="dashboard.css" />
<cfinclude template="highlight-github.min.css" />
</style>
</head>
<body>
<cfoutput>
<script>
window.taffy = {
resources: {},
config: {
scriptName: '#jsStringFormat(cgi.script_name)#',
reloadKey: '#jsStringFormat(application._taffy.settings.reloadKey)#',
reloadPassword: '#jsStringFormat(application._taffy.settings.reloadPassword)#',
endpointURLParam: '#jsStringFormat(application._taffy.settings.endpointURLParam)#',
<cfif Len(application._taffy.settings.csrfToken.cookieName) AND Len(application._taffy.settings.csrfToken.headerName)>
<cfif structKeyExists(GetFunctionList(), "encodeForJavascript")>
csrfCookieName: '#encodeForJavascript(application._taffy.settings.csrfToken.cookieName)#',
csrfHeaderName: '#encodeForJavascript(application._taffy.settings.csrfToken.headerName)#'
<cfelse>
csrfCookieName: '#jsStringFormat(application._taffy.settings.csrfToken.cookieName)#',
csrfHeaderName: '#jsStringFormat(application._taffy.settings.csrfToken.headerName)#'
</cfif>
<cfelse>
csrfCookieName: '',
csrfHeaderName: ''
</cfif>
}
};
</script>
</cfoutput>
<div style="max-width: 1200px; margin: 0 auto; padding: 1.5rem;">
<header class="dashboard-header">
<div>
<h1 class="dashboard-title">API Dashboard</h1>
<span class="dashboard-version">Taffy <cfoutput>#application._taffy.version#</cfoutput></span>
</div>
<div style="display: flex; gap: 0.5rem;">
<button class="btn btn-secondary" data-modal-target="config">Config</button>
<button class="btn btn-warning" id="reload">Reload API Cache</button>
<button class="btn btn-success" id="docs" onclick="window.location.href = '<cfoutput>#CGI.SCRIPT_NAME#</cfoutput>?docs'">Documentation</button>
<button class="btn btn-icon has-tooltip" id="openapi" data-tooltip="OpenAPI/Swagger" aria-label="OpenAPI/Swagger" onclick="window.location.href = '<cfoutput>#CGI.SCRIPT_NAME#</cfoutput>?openapi'"><cfinclude template="swagger.svg" /></button>
</div>
</header>
<!--- config modal --->
<dialog id="config" class="modal" aria-labelledby="frameworkConfig">
<div class="modal-header">
<h3 class="modal-title" id="frameworkConfig">Framework Configuration</h3>
<button type="button" class="modal-close" autofocus>&times;</button>
</div>
<div class="modal-body">
<cfoutput>
<table class="config-table">
<tbody>
<tr>
<td>Reload on every request:</td>
<td>
<a class="help-link" target="_blank" rel="noreferrer noopener" href="#getDocUrl('reloadOnEveryRequest')#">?</a>
#yesNoFormat(application._taffy.settings.reloadOnEveryRequest)#
</td>
</tr>
<tr>
<td>Return Exceptions as JSON:</td>
<td>
<a class="help-link" target="_blank" rel="noreferrer noopener" href="#getDocUrl('returnExceptionsAsJson')#">?</a>
#yesNoFormat(application._taffy.settings.returnExceptionsAsJson)#
</td>
</tr>
<tr>
<td>CORS:</td>
<td>
<a class="help-link" target="_blank" rel="noreferrer noopener" href="#getDocUrl('allowCrossDomain')#">?</a>
<cfif application._taffy.settings.allowCrossDomain EQ 'false'>No<cfelse>Yes</cfif>
</td>
</tr>
<tr>
<td>E-Tags:</td>
<td>
<a class="help-link" target="_blank" rel="noreferrer noopener" href="#getDocUrl('useEtags')#">?</a>
#yesNoFormat(application._taffy.settings.useEtags)#
</td>
</tr>
<tr>
<td>JSONP:</td>
<td>
<a class="help-link" target="_blank" rel="noreferrer noopener" href="#getDocUrl('jsonp')#">?</a>
<cfif application._taffy.settings.jsonp eq false>No<cfelse>?<strong>#application._taffy.settings.jsonp#=</strong>...</cfif>
</td>
</tr>
<tr>
<td>Endpoint URL Param:</td>
<td>
<a class="help-link" target="_blank" rel="noreferrer noopener" href="#getDocUrl('endpointURLParam')#">?</a>
#application._taffy.settings.endpointURLParam#
</td>
</tr>
<tr>
<td>Serializer:</td>
<td>
<a class="help-link" target="_blank" rel="noreferrer noopener" href="#getDocUrl('serializer')#">?</a>
#application._taffy.settings.serializer#
</td>
</tr>
<tr>
<td>Return Formats:</td>
<td>
<cfloop list="#structKeyList(application._taffy.settings.mimeTypes)#" index="local.m">
#local.m#<cfif local.m NEQ listLast(structKeyList(application._taffy.settings.mimeTypes))>, </cfif>
</cfloop>
</td>
</tr>
<tr>
<td>Global Headers:</td>
<td>
<a class="help-link" target="_blank" rel="noreferrer noopener" href="#getDocUrl('globalHeaders')#">?</a>
<cfif structIsEmpty(application._taffy.settings.globalHeaders)>
None
<cfelse>
<cfloop list="#structKeyList(application._taffy.settings.globalHeaders)#" index="local.h">
<strong>#local.h#:</strong> #application._taffy.settings.globalHeaders[local.h]#<br/>
</cfloop>
</cfif>
</td>
</tr>
<tr>
<td>Exception Log Adapter:</td>
<td>
<a class="help-link" target="_blank" rel="noreferrer noopener" href="#getDocUrl('exceptionLogAdapter')#">?</a>
#application._taffy.settings.exceptionLogAdapter#
</td>
</tr>
<tr>
<td>Exception Log Adapter Config:</td>
<td>
<a class="help-link" target="_blank" rel="noreferrer noopener" href="#getDocUrl('exceptionLogAdapterConfig')#">?</a>
<cfif isSimpleValue(application._taffy.settings.exceptionLogAdapterConfig) AND len(trim(application._taffy.settings.exceptionLogAdapterConfig)) EQ 0>
empty
<cfelseif isSimpleValue(application._taffy.settings.exceptionLogAdapterConfig)>
redacted
<cfelse>
redacted
</cfif>
</td>
</tr>
<tr>
<td>Unhandled Paths:</td>
<td>
<cfloop list="#application._taffy.settings.unhandledPaths#" index="local.p">
#local.p#<cfif local.p NEQ listLast(application._taffy.settings.unhandledPaths)>, </cfif>
</cfloop>
</td>
</tr>
</tbody>
</table>
</cfoutput>
</div>
</dialog>
<!--- alerts --->
<div id="alerts">
<cfif structKeyExists(application._taffy, "status")
and structKeyExists(application._taffy.status, "skippedResources")
and arrayLen(application._taffy.status.skippedResources) gt 0>
<cfoutput>
<cfloop from="1" to="#arrayLen(application._taffy.status.skippedResources)#" index="local.i">
<cfset local.err = application._taffy.status.skippedResources[local.i] />
<cfset local.exceptionHasErrorCode = structKeyExists(local.err, "Exception") AND structKeyExists(local.err.Exception, "ErrorCode")>
<cfset local.errorCode = "" />
<cfif local.exceptionHasErrorCode>
<cfset local.errorCode = local.err.Exception.ErrorCode>
</cfif>
<div class="alert alert-warning">
<cfif local.errorCode EQ "taffy.resources.DuplicateUriPattern">
<strong>#local.err.resource#</strong> contains a conflicting URI.
<cfelseif local.errorcode EQ "taffy.resources.URIDoesntBeginWithForwardSlash">
<strong>#local.err.resource#</strong> should have a URI that begins with a forward slash.
<cfelse>
<strong>#local.err.resource#</strong> contains a syntax error.
<cfif structKeyExists(local.err.exception, 'tagContext')>
<strong>Error on line #local.err.exception.tagcontext[1].line#:</strong>
</cfif>
</cfif>
<hr style="border-color: inherit; opacity: 0.3; margin: 0.75rem 0;"/>
<code style="display: block; padding: 0.5rem; background: rgba(0,0,0,0.05); border-radius: 0.25rem;">
<cfif structKeyExists(local.err.exception, 'message')>#local.err.exception.message#</cfif>
<cfif structKeyExists(local.err.exception, 'detail')><br/><br/>#local.err.exception.detail#</cfif>
</code>
<hr style="border-color: inherit; opacity: 0.3; margin: 0.75rem 0;"/>
<cfset local.stack_id = createUUID() />
<a href="javascript:toggleStackTrace('#local.stack_id#');" style="color: inherit;">Toggle Stack Trace</a>
<div class="stackTrace" id="#local.stack_id#">
<cfdump var="#local.err.exception.tagcontext#" />
</div>
<p style="margin-top: 0.5rem; font-size: 0.875rem;">Reload the API Cache after resolving this error.</p>
</div>
</cfloop>
</cfoutput>
</cfif>
</div>
<section id="resources">
<div style="display: flex; flex-wrap: wrap; align-items: center; gap: 1rem; margin-bottom: 1rem;">
<h2 style="font-size: 1.25rem; font-weight: 600; margin: 0;">Resources:</h2>
<input type="text" id="resourceSearch" placeholder="Filter... (ESC to clear)" autocomplete="off" class="form-input" style="flex: 1; max-width: 400px;" />
<div class="sort-picker" data-store-key="taffyDashboardSort">
<button type="button" class="sort-btn active" data-sort="name">Name</button>
<button type="button" class="sort-btn" data-sort="uri">URI</button>
<button type="button" class="sort-btn" data-sort="match">Match Order</button>
</div>
</div>
<div id="resourcesAccordion">
<cfoutput>
<cfloop from="1" to="#arrayLen(application._taffy.uriMatchOrder)#" index="local.resource">
<cfset local.currentResource = application._taffy.endpoints[application._taffy.uriMatchOrder[local.resource]] />
<cfset local.resourceHTTPID = rereplace(local.currentResource.beanName & "_" & hash(local.currentResource.srcURI), "[^0-9a-zA-Z_]", "_", "all") />
<cfset local.bean = application._taffy.factory.getBean(local.currentResource.beanName) />
<cfset local.md = getMetaData(local.bean) />
<cfif structKeyExists(local.md, "taffy_dashboard_hide") OR structKeyExists(local.md, "taffy:dashboard:hide")>
<cfscript>continue;</cfscript>
</cfif>
<cfset local.displayName = local.currentResource.beanName />
<cfif structKeyExists(local.md, "taffy:dashboard:name")>
<cfset local.displayName = local.md['taffy:dashboard:name'] />
<cfelseif structKeyExists(local.md, "taffy_dashboard_name")>
<cfset local.displayName = local.md['taffy_dashboard_name'] />
<cfelseif structKeyExists(local.md, "taffy:docs:name")>
<cfset local.displayName = local.md['taffy:docs:name'] />
<cfelseif structKeyExists(local.md, "taffy_docs_name")>
<cfset local.displayName = local.md['taffy_docs_name'] />
</cfif>
<div class="resource-panel" data-sort-name="#lCase(local.displayName)#" data-sort-uri="#lCase(local.currentResource.srcUri)#">
<div class="resource-header" data-target="#local.resourceHTTPID#">
<span class="resource-name">#local.displayName#</span>
<span class="resource-meta">
<code class="resource-uri">#local.currentResource.srcUri#</code>
<cfloop list="GET,POST,PUT,PATCH,DELETE" index="local.verb">
<cfif structKeyExists(local.currentResource.methods, local.verb)>
<span class="verb verb-#lcase(local.verb)#">#local.verb#</span>
<cfelse>
<span class="verb verb-disabled">#local.verb#</span>
</cfif>
</cfloop>
</span>
</div>
<div class="resource-content" id="#local.resourceHTTPID#">
<div class="tabs">
<div class="tabs-nav">
<button type="button" class="tab-btn active" data-tab="#local.resourceHTTPID#_run">Run it</button>
<button type="button" class="tab-btn" data-tab="#local.resourceHTTPID#_docs">Documentation</button>
</div>
<div class="tab-pane active" id="#local.resourceHTTPID#_run">
<div class="runner-form resource" data-uri="#local.currentResource.srcUri#" data-bean-name="#local.resourceHTTPID#">
<div class="runner-row">
<select class="form-select reqMethod">
<cfloop list="GET,POST,PUT,PATCH,DELETE" index="local.verb">
<cfif structKeyExists(local.currentResource.methods, local.verb)>
<option value="#local.verb#">#local.verb#</option>
</cfif>
</cfloop>
<cfif application._taffy.settings.allowCrossDomain NEQ 'false'>
<option value="OPTIONS">OPTIONS</option>
</cfif>
</select>
<input type="text" class="form-input runner-uri resourceUri" value="#local.currentResource.srcUri#" onclick="this.select()" />
<button class="btn btn-primary submitRequest">Send</button>
<button class="btn btn-ghost resetRequest">Reset</button>
</div>
<div class="toggles">
<a class="expander" data-target="##qp_#local.resourceHTTPID#">+Query Params</a>
<a class="expander" data-target="##accept_#local.resourceHTTPID#">+Accept</a>
<a class="expander" data-target="##head_#local.resourceHTTPID#">+Headers</a>
<a class="expander" data-target="##auth_#local.resourceHTTPID#">+Basic Auth</a>
</div>
<div class="expandable queryParams" id="qp_#local.resourceHTTPID#">
<h4 class="section-title">Query String Parameters: <span class="section-subtitle">(optional)</span></h4>
<div class="qparam">
<input class="form-input paramName" placeholder="name" />
<span class="text-muted">=</span>
<input class="form-input paramValue" placeholder="value" />
<button class="btn btn-ghost addParam" tabindex="-1">+</button>
</div>
</div>
<div class="expandable" id="accept_#local.resourceHTTPID#">
<h4 class="section-title">Accept:</h4>
<select class="form-select reqFormat" style="width: 100%;">
<cfloop list="#structKeyList(application._taffy.settings.mimeTypes)#" index="local.mime">
<option value="#local.mime#"
<cfif application._taffy.settings.defaultMime eq application._taffy.settings.mimeTypes[local.mime]>selected="selected"</cfif>
>#application._taffy.settings.mimeTypes[local.mime]#</option>
</cfloop>
</select>
</div>
<cfif arrayLen(local.currentResource.tokens) gt 0>
<div class="expandable open reqTokens">
<h4 class="section-title">URI Tokens: <span class="section-subtitle">(required)</span></h4>
<div class="tokenErrors" style="color: ##dc2626; font-size: 0.875rem; margin-bottom: 0.5rem;"></div>
<form onsubmit="return false;">
<cfloop from="1" to="#arrayLen(local.currentResource.tokens)#" index="local.token">
<div class="token-row">
<label class="token-label" for="token_#local.resourceHTTPID#_#local.currentResource.tokens[local.token]#">#local.currentResource.tokens[local.token]#:</label>
<input id="token_#local.resourceHTTPID#_#local.currentResource.tokens[local.token]#" name="#local.currentResource.tokens[local.token]#" type="text" class="form-input token-input" />
</div>
</cfloop>
</form>
</div>
</cfif>
<div class="expandable reqHeaders" id="head_#local.resourceHTTPID#">
<h4 class="section-title">Request Headers:</h4>
<textarea
rows="#listLen(structKeyList(application._taffy.settings.dashboardHeaders, '|'), '|')+1#"
class="form-input requestHeaders"
placeholder="X-MY-HEADER: VALUE"
><cfloop list="#structKeyList(application._taffy.settings.dashboardHeaders, '|')#" delimiters="|" index="k">#k#: #application._taffy.settings.dashboardHeaders[k]##chr(13)##chr(10)#</cfloop></textarea>
</div>
<div class="expandable basicAuth" id="auth_#local.resourceHTTPID#">
<h4 class="section-title">Basic Auth:</h4>
<div class="auth-row">
<input type="text" name="username" class="form-input" placeholder="Username" value="" />
<input type="password" name="password" class="form-input" placeholder="Password" value="" />
</div>
</div>
<div class="reqBody">
<h4 class="section-title">Request Body:</h4>
<textarea id="#local.resourceHTTPID#_RequestBody" class="form-input" rows="5"></textarea>
<cfif structKeyExists(local.md,"functions")>
<cfset local.functions = local.md.functions />
<cfelse>
<cfset local.functions = arrayNew(1) />
</cfif>
<!--- only save body templates for POST & PUT --->
<cfloop from="1" to="#arrayLen(local.functions)#" index="local.f">
<cfif local.functions[local.f].name eq "POST" or local.functions[local.f].name eq "PUT" or local.functions[local.f].name eq "PATCH">
<cfset local.args = {} />
<!--- get a list of all function arguments --->
<cfloop from="1" to="#arrayLen(local.functions[local.f].parameters)#" index="local.parm">
<cfset local.paramAttributes = local.functions[local.f].parameters[local.parm]>
<cfif structKeyExists(local.paramAttributes, "taffy_docs_hide") OR structKeyExists(local.paramAttributes, "taffy:docs:hide") OR structKeyExists(local.paramAttributes, "taffy_dashboard_hide") OR structKeyExists(local.paramAttributes, "taffy:dashboard:hide")>
<cfscript>continue;</cfscript>
</cfif>
<cfif not structKeyExists(local.paramAttributes,"type")>
<cfset local.args[local.paramAttributes.name] = '' />
<cfelseif local.paramAttributes.type eq 'struct'>
<cfset local.args[local.paramAttributes.name] = structNew() />
<cfelseif local.paramAttributes.type eq 'array'>
<cfset local.args[local.paramAttributes.name] = arrayNew(1) />
<cfelseif local.paramAttributes.type eq 'numeric'>
<cfset local.args[local.paramAttributes.name] = 0 />
<cfelseif local.paramAttributes.type eq 'boolean'>
<cfset local.args[local.paramAttributes.name] = true />
<cfelse>
<cfset local.args[local.paramAttributes.name] = '' />
</cfif>
</cfloop>
<!--- omit uri tokens --->
<cfloop from="1" to="#arrayLen(local.currentResource.tokens)#" index="local.token">
<cfset structDelete(local.args, local.currentResource.tokens[local.token]) />
</cfloop>
<!--- save to page JS for runtime reference --->
<script>
taffy.resources['#local.resourceHTTPID#'] = taffy.resources['#local.resourceHTTPID#'] || {};
taffy.resources['#local.resourceHTTPID#']['#lcase(local.functions[local.f].name)#'] = #serializeJson(local.args)#;
</script>
</cfif>
</cfloop>
</div>
<div class="progress">
<div class="progress-bar"></div>
</div>
<div class="response">
<h4 class="section-title">Response:</h4>
<div class="response-headers"></div>
<p class="response-time"></p>
<span class="response-status"></span>
<pre class="response-body"><code class="responseBody"></code></pre>
</div>
</div>
</div>
<div class="tab-pane" id="#local.resourceHTTPID#_docs">
<cfset local.metadata = getMetaData(application._taffy.factory.getBean(local.currentResource.beanName)) />
<cfset local.docData = getHintsFromMetadata(local.metadata) />
<cfif structKeyExists(local.docData, 'hint')>
<p class="doc-hint">#local.docData.hint#</p>
</cfif>
<cfset local.found = { get=false, post=false, put=false, patch=false, delete=false } />
<cfloop from="1" to="#arrayLen(local.docData.functions)#" index="local.f">
<cfset local.func = local.docData.functions[local.f] />
<cfset local.found[local.func.name] = true />
<!--- skip methods that are hidden --->
<cfif structKeyExists(local.func, "taffy_docs_hide") OR structKeyExists(local.func, "taffy:docs:hide") OR structKeyExists(local.func, "taffy_dashboard_hide") OR structKeyExists(local.func, "taffy:dashboard:hide")>
<cfscript>continue;</cfscript>
</cfif>
<!--- exclude methods that are not exposed as REST verbs --->
<cfif listFindNoCase('get,post,put,delete,patch',local.func.name) OR structKeyExists(local.func,'taffy_verb') OR structKeyExists(local.func,'taffy:verb')>
<div class="doc-section">
<h5 class="doc-verb-title">
<cfif listFindNoCase('get,post,put,delete,patch',local.func.name)>
#local.func.name#
<cfelseif structKeyExists(local.func,'taffy_verb')>
#local.func.taffy_verb#
<cfelseif structKeyExists(local.func,'taffy:verb')>
#local.func['taffy:verb']#
</cfif>
</h5>
<cfif structKeyExists(local.func, "hint")>
<p class="doc-hint">#local.func.hint#</p>
</cfif>
<cfset local.visibleParams = [] />
<cfloop from="1" to="#arrayLen(local.func.parameters)#" index="local.p">
<cfset local.param = local.func.parameters[local.p] />
<cfif NOT (structKeyExists(local.param, "taffy_docs_hide") OR structKeyExists(local.param, "taffy:docs:hide") OR structKeyExists(local.param, "taffy_dashboard_hide") OR structKeyExists(local.param, "taffy:dashboard:hide"))>
<cfset arrayAppend(local.visibleParams, local.param) />
</cfif>
</cfloop>
<cfif arrayLen(local.visibleParams) gt 0>
<div class="doc-accordion">
<button type="button" class="doc-accordion-trigger" data-target="#local.resourceHTTPID#_#local.func.name#_inputs">
Inputs
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>
</button>
<div class="doc-accordion-content" id="#local.resourceHTTPID#_#local.func.name#_inputs">
<cfloop array="#local.visibleParams#" index="local.param">
<div class="param-item">
<cfif not structKeyExists(local.param, 'required') or not local.param.required>
<span class="param-badge param-optional">optional</span>
<cfelse>
<span class="param-badge param-required">required</span>
</cfif>
<cfif structKeyExists(local.param, "type")>
<span class="param-type">#local.param.type#</span>
</cfif>
<span class="param-name">#local.param.name#</span>
<cfif structKeyExists(local.param, "taffy_minlength")>
<span class="param-constraint">min length: #local.param["taffy_minlength"]#</span>
</cfif>
<cfif structKeyExists(local.param, "taffy_maxlength")>
<span class="param-constraint">max length: #local.param["taffy_maxlength"]#</span>
</cfif>
<cfif structKeyExists(local.param, "taffy_min")>
<span class="param-constraint">min: #local.param["taffy_min"]#</span>
</cfif>
<cfif structKeyExists(local.param, "taffy_max")>
<span class="param-constraint">max: #local.param["taffy_max"]#</span>
</cfif>
<cfif structKeyExists(local.param, "taffy_pattern")>
<span class="param-constraint">pattern: #local.param["taffy_pattern"]#</span>
</cfif>
<cfif structKeyExists(local.param, "default")>
<span class="param-default">
<cfif local.param.default eq "">(default: "")<cfelse>(default: #local.param.default#)</cfif>
</span>
</cfif>
<cfif structKeyExists(local.param, "hint")>
<p class="param-hint">#local.param.hint#</p>
</cfif>
</div>
</cfloop>
</div>
</div>
</cfif>
<!--- begin sample response --->
<cfset hasSample = false />
<cfset sample = '' />
<cfloop from="1" to="#arrayLen(local.md.functions)#" index="functionIndex">
<cfif local.md.functions[functionIndex].name eq 'sample#local.func.name#Response'>
<cfset hasSample = true />
<cfinvoke
component="#local.bean#"
method="#local.md.functions[functionIndex].name#"
returnvariable="sample"
/>
<cfbreak />
</cfif>
</cfloop>
<cfif hasSample>
<div class="doc-accordion">
<button type="button" class="doc-accordion-trigger" data-target="#local.resourceHTTPID#_#local.func.name#_sample">
Sample Response
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>
</button>
<div class="doc-accordion-content sample-response-content" id="#local.resourceHTTPID#_#local.func.name#_sample">
<pre class="response-body"><code class="json-format">#serializeJson(sample)#</code></pre>
</div>
</div>
</cfif>
<!--- end sample response --->
</div>
</cfif>
</cfloop>
</div>
</div>
</div>
</div>
</cfloop>
</cfoutput>
</div>
<cfif arrayLen(application._taffy.uriMatchOrder) eq 0>
<div class="empty-state">
<div class="empty-state-header">Taffy is running but you haven't defined any resources yet.</div>
<div class="empty-state-body">
<p>
It looks like you don't have any resources defined. Get started by creating the folder
<code><cfoutput>#guessResourcesFullPath()#</cfoutput></code>, in which you should place your
Resource CFC's.
</p>
<p>
Or you could set up a bean factory, like <a href="http://www.coldspringframework.org/">ColdSpring</a>
or <a href="https://github.com/seancorfield/di1">DI/1</a>. Want to know more about using bean factories with Taffy?
<a href="https://github.com/atuttle/Taffy/wiki/So-you-want-to:-use-an-external-bean-factory-like-coldspring-to-completely-manage-resources">Check out the wiki!</a>
</p>
<p>
If all else fails, I recommend starting with <a href="https://github.com/atuttle/Taffy/wiki/Getting-Started">Getting Started</a>.
</p>
</div>
</div>
</cfif>
<cfif application._taffy.settings.reloadKey eq "reload" and application._taffy.settings.reloadPassword eq "true">
<div class="alert alert-warning mt-4">
<strong>Warning:</strong> Your reload key and password are using the framework default settings.
It's advised that you <a target="_blank" rel="noreferrer noopener" href="<cfoutput>#getDocUrl('reloadKey')#</cfoutput>" style="color: inherit;">change these in production</a>.
</div>
</cfif>
<div class="alert alert-info mt-4 match-order-hint" style="display: none;">
Resources are listed in matching order. From top to bottom, the first URI to match the request is used.
</div>
</section>
</div>
<script type="text/javascript">
<cfinclude template="highlight.min.js" />
<cfinclude template="dash.js" />
</script>
</body>
</html>
<cffunction name="getDocUrl">
<cfargument name="item" />
<cfreturn "https://docs.taffy.io/##/#listFirst(application._taffy.version,'-')#?id=#lCase(item)#" />
</cffunction>