Files
crank/apps/ui/js/openapi-import.js
T

881 lines
31 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
(function() {
var MAX_FILE_BYTES = 256 * 1024;
var state = {
workspaceId: null,
onImported: null,
file: null,
jobId: null,
preview: null,
filterQuery: '',
filterMethod: '',
revision: 0,
previewController: null,
applyController: null,
applyInFlight: false,
restoreFocus: null,
};
function qs(id) {
return document.getElementById(id);
}
function tKey(key) {
return window.t ? window.t(key) : key;
}
function tfKey(key, vars) {
return window.tf ? window.tf(key, vars) : tKey(key);
}
function locale() {
return localStorage.getItem('crank_lang') === 'ru' ? 'ru' : 'en';
}
function isCurrent(revision, workspaceId, language) {
return revision === state.revision
&& workspaceId === state.workspaceId
&& language === locale()
&& !qs('openapi-import-modal').hidden;
}
function setStatus(message, isError, focus) {
var node = qs('openapi-import-status');
if (!node) return;
node.textContent = message || '';
node.classList.toggle('error', !!isError);
if (focus && message) {
node.focus();
}
}
function boundedFileName(file) {
var name = String(file && file.name || '');
return name.length > 128 ? name.slice(0, 127) + '…' : name;
}
function formatSize(bytes) {
var language = locale() === 'ru' ? 'ru-RU' : 'en-US';
return new Intl.NumberFormat(language).format(bytes) + ' B';
}
function renderFileName() {
var node = qs('openapi-import-file-name');
if (!node) return;
node.textContent = state.file
? boundedFileName(state.file) + ' · ' + formatSize(state.file.size)
: tKey('openapi.file.none');
}
function selectedKeys() {
return Array.from(document.querySelectorAll('[data-openapi-operation]:checked'))
.map(function(input) {
return input.value;
});
}
function operationRows() {
return Array.from(document.querySelectorAll('.openapi-import-operation'));
}
function visibleOperationRows() {
return operationRows().filter(function(row) {
return !row.hidden;
});
}
function updateSelection() {
var node = qs('openapi-import-selection');
var selectedCount = selectedKeys().length;
var totalCount = document.querySelectorAll('[data-openapi-operation]').length;
var visibleCount = visibleOperationRows().length;
if (node) {
node.textContent = tfKey('openapi.selection', {
selected: selectedCount,
total: totalCount,
visible: visibleCount,
});
}
document.querySelectorAll('.openapi-import-group').forEach(function(groupNode) {
var rows = Array.from(groupNode.querySelectorAll('.openapi-import-operation'));
var visibleInputs = rows
.filter(function(row) { return !row.hidden; })
.map(function(row) { return row.querySelector('[data-openapi-operation]'); })
.filter(Boolean);
var selectedVisible = visibleInputs.filter(function(input) {
return input.checked;
}).length;
var selectedTotal = rows.filter(function(row) {
var input = row.querySelector('[data-openapi-operation]');
return input && input.checked;
}).length;
var checkbox = groupNode.querySelector('[data-openapi-group]');
var counter = groupNode.querySelector('[data-openapi-group-count]');
if (checkbox) {
checkbox.indeterminate = selectedVisible > 0 && selectedVisible < visibleInputs.length;
checkbox.checked = visibleInputs.length > 0 && selectedVisible === visibleInputs.length;
}
if (counter) {
counter.textContent = tfKey('openapi.group.selection', {
selected: selectedTotal,
total: rows.length,
visible: visibleInputs.length,
});
}
});
}
function applyFilters() {
var query = state.filterQuery.toLowerCase();
var method = state.filterMethod.toLowerCase();
document.querySelectorAll('.openapi-import-group').forEach(function(groupNode) {
var visibleInGroup = 0;
groupNode.querySelectorAll('.openapi-import-operation').forEach(function(row) {
var matchesMethod = !method || String(row.dataset.openapiMethod).toLowerCase() === method;
var matchesQuery = !query || String(row.dataset.openapiSearch).toLowerCase().indexOf(query) >= 0;
var visible = matchesMethod && matchesQuery;
row.hidden = !visible;
if (visible) visibleInGroup += 1;
});
groupNode.hidden = visibleInGroup === 0;
});
updateSelection();
}
function setVisibleSelection(checked) {
visibleOperationRows().forEach(function(row) {
var input = row.querySelector('[data-openapi-operation]');
if (input) input.checked = checked;
});
updateSelection();
}
function escapeHtml(value) {
return String(value || '')
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;');
}
function renderFinding(finding) {
var severity = String(finding && finding.severity || 'warning').toLowerCase();
var label = severity === 'info' ? 'i' : severity === 'error' ? '×' : '!';
return '<span class="openapi-import-finding openapi-import-finding-' + escapeHtml(severity) + '">'
+ '<strong>' + label + '</strong> '
+ escapeHtml(findingMessage(finding))
+ '</span>';
}
function findingMessage(finding) {
var code = String(finding && finding.code || '').replace(/^.*\./, '');
var known = {
missing_servers: 'openapi.finding.missing_servers',
multiple_servers: 'openapi.finding.multiple_servers',
unsupported_request_body: 'openapi.finding.unsupported_request_body',
operation_name_renamed: 'openapi.finding.operation_name_renamed',
operation_name_conflict: 'openapi.finding.operation_name_conflict',
weak_tool_description: 'openapi.finding.weak_tool_description',
};
return tKey(known[code] || 'openapi.finding.generic');
}
function appendMappingGroup(root, label, values) {
if (!values || !values.length) return;
var group = document.createElement('div');
group.className = 'openapi-import-mapping-group';
var title = document.createElement('span');
title.className = 'openapi-import-mapping-label';
title.textContent = label;
group.appendChild(title);
values.slice(0, 8).forEach(function(value) {
var chip = document.createElement('code');
chip.className = 'openapi-import-mapping-chip';
chip.textContent = value;
group.appendChild(chip);
});
if (values.length > 8) {
var more = document.createElement('span');
more.className = 'openapi-import-mapping-more';
more.textContent = '+' + (values.length - 8);
group.appendChild(more);
}
root.appendChild(group);
}
function renderOperationMappingPreview(operation) {
var details = document.createElement('div');
var request = { path: [], query: [], headers: [], body: [] };
var inputRules = operation
&& operation.draft
&& operation.draft.input_mapping
&& Array.isArray(operation.draft.input_mapping.rules)
? operation.draft.input_mapping.rules
: [];
var outputRules = operation
&& operation.draft
&& operation.draft.output_mapping
&& Array.isArray(operation.draft.output_mapping.rules)
? operation.draft.output_mapping.rules
: [];
details.className = 'openapi-import-mapping-preview';
inputRules.forEach(function(rule) {
var target = String(rule.target || '');
if (target.indexOf('$.request.path.') === 0) {
request.path.push(target.slice(15));
} else if (target.indexOf('$.request.query.') === 0) {
request.query.push(target.slice(16));
} else if (target.indexOf('$.request.headers.') === 0) {
request.headers.push(target.slice(18));
} else if (target.indexOf('$.request.body.') === 0) {
request.body.push(target.slice(15));
} else if (target === '$.request.body') {
request.body.push('body');
}
});
appendMappingGroup(details, tKey('openapi.mapping.path'), request.path);
appendMappingGroup(details, tKey('openapi.mapping.query'), request.query);
appendMappingGroup(details, tKey('openapi.mapping.header'), request.headers);
appendMappingGroup(details, tKey('openapi.mapping.body'), request.body);
appendMappingGroup(details, tKey('openapi.mapping.response'), outputRules.map(function(rule) {
var target = String(rule.target || '').replace('$.output.', '').replace('$.output', 'result');
var source = String(rule.source || '').replace('$.response.body.', '').replace('$.response.body', 'body');
return target + ' ← ' + source;
}));
return details;
}
function populateServers(preview) {
var serverSelect = qs('openapi-import-server');
var servers = preview.source && preview.source.servers && preview.source.servers.length
? preview.source.servers
: [''];
serverSelect.replaceChildren();
servers.forEach(function(server) {
var option = document.createElement('option');
option.value = server;
option.textContent = server || tKey('openapi.server.later');
serverSelect.appendChild(option);
});
}
function populateMethodFilter(preview) {
var methodFilter = qs('openapi-import-method-filter');
var all = document.createElement('option');
var methods = Array.from(new Set((preview.groups || []).flatMap(function(group) {
return (group.operations || []).map(function(operation) {
return operation.method;
});
}))).sort();
methodFilter.replaceChildren();
all.value = '';
all.textContent = tKey('openapi.method.all');
methodFilter.appendChild(all);
methods.forEach(function(method) {
var option = document.createElement('option');
option.value = method;
option.textContent = method;
methodFilter.appendChild(option);
});
}
function renderPreview(response) {
var preview = response.preview;
var count = (preview.groups || []).reduce(function(sum, group) {
return sum + (group.operations || []).length;
}, 0);
var source = qs('openapi-import-source');
var groupsNode = qs('openapi-import-groups');
state.jobId = response.job_id;
state.preview = preview;
state.filterQuery = '';
state.filterMethod = '';
qs('openapi-import-preview-panel').hidden = false;
qs('openapi-import-result').hidden = true;
qs('openapi-import-result').replaceChildren();
source.textContent = tfKey('openapi.source.summary', {
name: boundedFileName(state.file),
size: formatSize(state.file.size),
count: count,
});
qs('openapi-import-search').value = '';
populateServers(preview);
populateMethodFilter(preview);
groupsNode.replaceChildren();
if (preview.findings && preview.findings.length) {
var documentFindings = document.createElement('div');
documentFindings.className = 'openapi-import-document-findings';
documentFindings.innerHTML = preview.findings.map(renderFinding).join('');
groupsNode.appendChild(documentFindings);
}
(preview.groups || []).forEach(function(group) {
var groupNode = document.createElement('section');
var header = document.createElement('div');
groupNode.className = 'openapi-import-group';
header.className = 'openapi-import-group-header';
header.innerHTML = '<span>' + escapeHtml(group.title) + ' · ' + group.operations.length + '</span>'
+ '<span class="openapi-import-group-count" data-openapi-group-count></span>'
+ '<label class="openapi-import-group-toggle"><input type="checkbox" data-openapi-group checked> '
+ escapeHtml(tKey('openapi.group.select'))
+ '</label>';
groupNode.appendChild(header);
group.operations.forEach(function(operation) {
var row = document.createElement('label');
row.className = 'openapi-import-operation';
row.dataset.openapiMethod = operation.method;
row.dataset.openapiSearch = [
group.title,
operation.key,
operation.suggested_name,
operation.suggested_display_name,
operation.path,
operation.method,
].join(' ');
row.innerHTML = '<input type="checkbox" data-openapi-operation value="' + escapeHtml(operation.key) + '" checked>'
+ '<div><div class="openapi-import-operation-title">' + escapeHtml(operation.suggested_display_name) + '</div>'
+ '<div class="openapi-import-operation-meta"><code>' + escapeHtml(operation.suggested_name) + '</code> · '
+ escapeHtml(operation.path) + ' · '
+ escapeHtml(tfKey('openapi.operation.fields', { input: operation.input_fields, output: operation.output_fields }))
+ '</div></div><span class="openapi-import-method">' + escapeHtml(operation.method) + '</span>';
row.appendChild(renderOperationMappingPreview(operation));
if (operation.findings && operation.findings.length) {
var findings = document.createElement('div');
findings.className = 'openapi-import-findings';
findings.innerHTML = operation.findings.map(renderFinding).join('');
row.appendChild(findings);
}
groupNode.appendChild(row);
});
groupNode.querySelector('[data-openapi-group]').addEventListener('change', function(event) {
groupNode.querySelectorAll('.openapi-import-operation').forEach(function(row) {
var input = row.querySelector('[data-openapi-operation]');
if (!row.hidden && input) input.checked = event.target.checked;
});
updateSelection();
});
groupsNode.appendChild(groupNode);
});
groupsNode.querySelectorAll('[data-openapi-operation]').forEach(function(input) {
input.addEventListener('change', updateSelection);
});
applyFilters();
}
function validateFile(file) {
if (!file) return 'openapi.error.file_required';
var name = String(file.name || '').toLowerCase();
var yaml = /\.(yaml|yml)$/.test(name);
var json = /\.json$/.test(name);
if (!yaml && !json) return 'openapi.error.file_type';
if (!file.size) return 'openapi.error.file_empty';
if (file.size > MAX_FILE_BYTES) return 'openapi.error.file_large';
var type = String(file.type || '').toLowerCase();
if (!type || type === 'application/octet-stream') return null;
var allowed = yaml
? ['application/yaml', 'application/x-yaml', 'text/yaml', 'text/x-yaml']
: ['application/json', 'application/openapi+json'];
return allowed.indexOf(type) >= 0 ? null : 'openapi.error.file_type';
}
function abort(controller) {
if (controller) controller.abort();
}
function clearPreview() {
state.jobId = null;
state.preview = null;
state.filterQuery = '';
state.filterMethod = '';
qs('openapi-import-preview-panel').hidden = true;
qs('openapi-import-groups').replaceChildren();
qs('openapi-import-result').hidden = true;
qs('openapi-import-result').replaceChildren();
updateSelection();
}
function clearServerSelection() {
qs('openapi-import-server-custom').value = '';
qs('openapi-import-server').replaceChildren();
}
function invalidate(options) {
state.revision += 1;
abort(state.previewController);
abort(state.applyController);
state.previewController = null;
state.applyController = null;
state.applyInFlight = false;
qs('openapi-import-preview').disabled = false;
qs('openapi-import-create').disabled = false;
qs('openapi-import-cancel').hidden = true;
clearPreview();
if (options && options.clearFile) {
state.file = null;
qs('openapi-import-file').value = '';
renderFileName();
}
}
function showRetry(show) {
qs('openapi-import-retry').hidden = !show;
}
function cancelCurrent() {
if (!state.previewController && !state.applyController) return;
invalidate();
showRetry(!!state.file);
setStatus(tKey('openapi.status.cancelled'));
}
function errorStatus(error, fallback) {
var known = {
'openapi_upload.missing_file': 'openapi.error.file_required',
'openapi_upload.invalid_media_type': 'openapi.error.file_type',
'openapi_upload.empty_file': 'openapi.error.file_empty',
'openapi_upload.file_too_large': 'openapi.error.file_large',
'openapi_upload.no_methods': 'openapi.error.no_methods',
'openapi_upload.malformed_multipart': 'openapi.error.malformed_multipart',
'openapi_upload.invalid_utf8': 'openapi.error.invalid_utf8',
'openapi_upload.invalid_document': 'openapi.error.invalid_document',
'openapi_upload.parser_unavailable': 'openapi.error.parser_unavailable',
'openapi_upload.storage_unavailable': 'openapi.error.storage_unavailable',
'openapi_upload.source_integrity': 'openapi.error.source_integrity',
'openapi_upload.source_unavailable': 'openapi.error.source_unavailable',
};
var message = tKey(known[error && error.code] || fallback);
var identifiers = [];
if (error && error.requestId) {
identifiers.push(tfKey('openapi.correlation.request_id', { id: error.requestId }));
}
if (error && error.traceId) {
identifiers.push(tfKey('openapi.correlation.trace_id', { id: error.traceId }));
}
return identifiers.length ? message + ' ' + identifiers.join(' · ') : message;
}
async function preview() {
var localError = validateFile(state.file);
if (localError) {
setStatus(tKey(localError), true, true);
showRetry(false);
return;
}
if (!state.workspaceId) {
setStatus(tKey('openapi.error.workspace'), true, true);
return;
}
invalidate();
var revision = state.revision;
var workspaceId = state.workspaceId;
var language = locale();
var controller = new AbortController();
state.previewController = controller;
qs('openapi-import-preview').disabled = true;
qs('openapi-import-cancel').hidden = false;
showRetry(false);
setStatus(tKey('openapi.status.previewing'));
try {
var response = await window.CrankApi.previewOpenApiImport(workspaceId, state.file, { signal: controller.signal });
if (!isCurrent(revision, workspaceId, language)) return;
renderPreview(response);
setStatus(tKey('openapi.status.preview_ready'));
} catch (error) {
if (!isCurrent(revision, workspaceId, language)) return;
if (error && error.name === 'AbortError') {
setStatus(tKey('openapi.status.cancelled'));
return;
}
clearPreview();
showRetry(true);
setStatus(errorStatus(error, 'openapi.error.preview'), true, true);
} finally {
if (isCurrent(revision, workspaceId, language)) {
state.previewController = null;
qs('openapi-import-preview').disabled = false;
qs('openapi-import-cancel').hidden = true;
}
}
}
function previewOperationByName(name) {
var groups = state.preview && state.preview.groups || [];
for (var groupIndex = 0; groupIndex < groups.length; groupIndex += 1) {
var operations = groups[groupIndex].operations || [];
for (var operationIndex = 0; operationIndex < operations.length; operationIndex += 1) {
if (operations[operationIndex].suggested_name === name) return operations[operationIndex];
}
}
return null;
}
function wizardHref(operationId) {
return ((window.CrankRoutes && window.CrankRoutes.wizard) || '/wizard/')
+ '?mode=edit&operationId=' + encodeURIComponent(operationId);
}
function appendFindingNodes(root, findings) {
if (!findings || !findings.length) {
var empty = document.createElement('span');
empty.className = 'openapi-import-result-ok';
empty.textContent = tKey('openapi.result.no_findings');
root.appendChild(empty);
return;
}
findings.slice(0, 4).forEach(function(finding) {
var wrapper = document.createElement('div');
wrapper.innerHTML = renderFinding(finding);
root.appendChild(wrapper.firstElementChild);
});
if (findings.length > 4) {
var more = document.createElement('span');
more.className = 'openapi-import-result-more';
more.textContent = tfKey('openapi.result.more', { count: findings.length - 4 });
root.appendChild(more);
}
}
function renderResult(response) {
var node = qs('openapi-import-result');
var title = document.createElement('strong');
node.replaceChildren();
title.textContent = tKey('openapi.result.title');
node.appendChild(title);
if (response.created && response.created.length) {
var primary = document.createElement('div');
var table = document.createElement('div');
primary.className = 'openapi-import-primary-result';
primary.innerHTML = '<a class="btn-primary" href="' + wizardHref(response.created[0].operation_id) + '">'
+ escapeHtml(tKey('openapi.result.open_first'))
+ '</a>';
node.appendChild(primary);
table.className = 'openapi-import-result-table';
table.setAttribute('role', 'table');
table.innerHTML = '<div class="openapi-import-result-row openapi-import-result-head" role="row">'
+ '<div role="columnheader">' + escapeHtml(tKey('openapi.result.draft')) + '</div>'
+ '<div role="columnheader">' + escapeHtml(tKey('openapi.result.findings')) + '</div>'
+ '<div role="columnheader">' + escapeHtml(tKey('openapi.result.action')) + '</div>'
+ '</div>';
response.created.forEach(function(operation) {
var previewOperation = previewOperationByName(operation.name);
var row = document.createElement('div');
var nameCell = document.createElement('div');
var name = document.createElement('div');
var meta = document.createElement('div');
var findingsCell = document.createElement('div');
var actionCell = document.createElement('div');
var action = document.createElement('a');
row.className = 'openapi-import-result-row';
row.setAttribute('role', 'row');
nameCell.setAttribute('role', 'cell');
name.className = 'openapi-import-result-name';
name.textContent = operation.name;
meta.className = 'openapi-import-result-meta';
meta.textContent = previewOperation
? previewOperation.method + ' ' + previewOperation.path + ' · v' + operation.version
: 'v' + operation.version;
nameCell.append(name, meta);
findingsCell.className = 'openapi-import-result-findings';
findingsCell.setAttribute('role', 'cell');
appendFindingNodes(findingsCell, previewOperation && previewOperation.findings);
actionCell.setAttribute('role', 'cell');
action.className = 'btn-secondary openapi-import-result-action';
action.href = wizardHref(operation.operation_id);
action.textContent = previewOperation && previewOperation.findings && previewOperation.findings.length
? tKey('openapi.result.fix')
: tKey('openapi.result.open');
actionCell.appendChild(action);
row.append(nameCell, findingsCell, actionCell);
table.appendChild(row);
});
node.appendChild(table);
}
if (response.skipped && response.skipped.length) {
var skippedNode = document.createElement('div');
skippedNode.className = 'openapi-import-result-skipped';
skippedNode.textContent = tKey('openapi.result.skipped') + ': ' + response.skipped.map(function(item) {
return (item.name || item.operation_key || tKey('openapi.result.unnamed')) + ' — '
+ findingMessage({ code: item.code || item.reason_code || item.reason });
}).join('; ');
node.appendChild(skippedNode);
}
if (response.findings && response.findings.length) {
var findings = document.createElement('div');
findings.className = 'openapi-import-result-findings';
findings.innerHTML = response.findings.map(renderFinding).join('');
node.appendChild(findings);
}
node.hidden = false;
}
async function createDrafts() {
if (state.applyInFlight) return;
var keys = selectedKeys();
if (!keys.length) {
setStatus(tKey('openapi.error.selection'), true, true);
return;
}
if (!state.jobId || !state.preview) {
setStatus(tKey('openapi.error.preview_required'), true, true);
return;
}
var serverUrl = (qs('openapi-import-server-custom').value || qs('openapi-import-server').value || '').trim();
if (!serverUrl) {
setStatus(tKey('openapi.error.server'), true, true);
return;
}
var revision = state.revision;
var workspaceId = state.workspaceId;
var language = locale();
var jobId = state.jobId;
var controller = new AbortController();
state.applyController = controller;
state.applyInFlight = true;
qs('openapi-import-create').disabled = true;
qs('openapi-import-cancel').hidden = false;
showRetry(false);
setStatus(tKey('openapi.status.creating'));
try {
var response = await window.CrankApi.createOpenApiImport(workspaceId, jobId, {
selected_operation_keys: keys,
server_url: serverUrl,
conflict_mode: qs('openapi-import-conflict-mode').value || 'rename',
}, { signal: controller.signal });
if (!isCurrent(revision, workspaceId, language)) return;
setStatus(tfKey('openapi.status.created', {
created: (response.created || []).length,
skipped: (response.skipped || []).length,
}));
renderResult(response);
if (typeof state.onImported === 'function') await state.onImported();
} catch (error) {
if (!isCurrent(revision, workspaceId, language)) return;
if (error && error.name === 'AbortError') {
setStatus(tKey('openapi.status.cancelled'));
return;
}
showRetry(false);
setStatus(errorStatus(error, 'openapi.error.create'), true, true);
} finally {
if (isCurrent(revision, workspaceId, language)) {
state.applyController = null;
state.applyInFlight = false;
qs('openapi-import-create').disabled = false;
qs('openapi-import-cancel').hidden = true;
}
}
}
function reset() {
invalidate({ clearFile: true });
showRetry(false);
setStatus('');
qs('openapi-import-server-custom').value = '';
qs('openapi-import-conflict-mode').value = 'rename';
}
function open(options) {
if (state.workspaceId && state.workspaceId !== options.workspaceId) {
invalidate({ clearFile: true });
}
state.workspaceId = options.workspaceId;
state.onImported = options.onImported;
state.restoreFocus = document.activeElement;
qs('openapi-import-modal').hidden = false;
renderFileName();
qs('openapi-import-file-select').focus();
}
function close() {
invalidate({ clearFile: true });
showRetry(false);
qs('openapi-import-modal').hidden = true;
if (state.restoreFocus && typeof state.restoreFocus.focus === 'function') {
state.restoreFocus.focus();
}
}
function selectFile(file) {
clearServerSelection();
invalidate();
state.file = file || null;
showRetry(false);
var localError = validateFile(state.file);
renderFileName();
if (localError) {
setStatus(tKey(localError), true, true);
} else if (state.file) {
setStatus(tKey('openapi.status.file_ready'));
}
}
document.addEventListener('DOMContentLoaded', function() {
if (!qs('openapi-import-modal')) return;
renderFileName();
qs('openapi-import-file-select').addEventListener('click', function(event) {
event.preventDefault();
qs('openapi-import-file').click();
});
qs('openapi-import-file').addEventListener('change', function(event) {
selectFile(event.target.files && event.target.files[0]);
});
qs('openapi-import-preview').addEventListener('click', preview);
qs('openapi-import-retry').addEventListener('click', preview);
qs('openapi-import-create').addEventListener('click', createDrafts);
qs('openapi-import-cancel').addEventListener('click', cancelCurrent);
qs('openapi-import-reset').addEventListener('click', reset);
qs('openapi-import-search').addEventListener('input', function(event) {
state.filterQuery = event.target.value.trim();
applyFilters();
});
qs('openapi-import-method-filter').addEventListener('change', function(event) {
state.filterMethod = event.target.value;
applyFilters();
});
qs('openapi-import-select-visible').addEventListener('click', function() {
setVisibleSelection(true);
});
qs('openapi-import-clear-visible').addEventListener('click', function() {
setVisibleSelection(false);
});
document.querySelectorAll('[data-openapi-close]').forEach(function(node) {
node.addEventListener('click', close);
});
document.addEventListener('keydown', function(event) {
var modal = qs('openapi-import-modal');
if (event.key === 'Escape' && !qs('openapi-import-modal').hidden) {
event.preventDefault();
close();
}
if (event.key !== 'Tab' || modal.hidden) return;
var focusable = Array.from(modal.querySelectorAll('button:not([disabled]):not([hidden]), input:not([disabled]), select:not([disabled]), a[href]'))
.filter(function(node) { return node.tabIndex >= 0 && !node.closest('[hidden]'); });
if (!focusable.length) return;
var first = focusable[0];
var last = focusable[focusable.length - 1];
if (event.shiftKey && (document.activeElement === first || !modal.contains(document.activeElement))) {
event.preventDefault();
last.focus();
} else if (!event.shiftKey && document.activeElement === last) {
event.preventDefault();
first.focus();
}
});
function invalidateForContext(options) {
if (!qs('openapi-import-modal').hidden) {
invalidate(options);
renderFileName();
showRetry(!options || !options.clearFile ? !!state.file : false);
setStatus(tKey('openapi.status.context_changed'));
}
}
window.addEventListener('crank:langchange', function() {
invalidateForContext();
});
window.addEventListener('crank:workspacechange', function(event) {
if (!qs('openapi-import-modal').hidden) {
state.workspaceId = event.detail && event.detail.id || null;
invalidateForContext({ clearFile: true });
}
});
window.addEventListener('storage', function(event) {
if (event.key === 'crank_lang') invalidateForContext();
});
window.addEventListener('pagehide', function() {
invalidate({ clearFile: true });
showRetry(false);
setStatus('');
});
window.addEventListener('pageshow', function(event) {
if (!event.persisted || qs('openapi-import-modal').hidden) return;
invalidateForContext({ clearFile: true });
});
});
window.CrankOpenApiImport = {
open: open,
close: close,
reset: reset,
};
}());