您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Data Validator Helper
// ==UserScript== // @name Data Validator Helper v2 // @namespace http://tampermonkey.net/ // @version 0.2 // @description Data Validator Helper // @author Eric Liu <[email protected]> // @match https://data.veracity.com/dataValidator/* // @match https://datatest.veracity.com/dataValidator/* // @match https://datadevtest.veracity.com/dataValidator/* // @grant GM.xmlHttpRequest // @grant GM.registerMenuCommand // ==/UserScript== const baseUrl = location.origin + '/api/dataValidator'; (function () { 'use strict'; window._historyWrap = function (type) { var orig = history[type]; var e = new Event(type.toLowerCase()); return function () { var rv = orig.apply(this, arguments); e.arguments = arguments; window.dispatchEvent(e); return rv; }; }; history.pushState = _historyWrap('pushState'); history.replaceState = _historyWrap('replaceState'); window.schema = null; window.schemas = []; window.columnValidators = []; initialize(); window.addEventListener('pushstate', (e) => { window.setTimeout(onRouteChange, 500); }); })(); async function initialize() { await onRouteChange(); } async function onRouteChange() { if (isSchemaListPage()) { console.log('schema list'); await loadColumnValidators(); await loadSchemas(); await createConvertButton(); await createSchemaDeleteButtons(); } else if (isSchemaPage()) { console.log('schema'); await loadSchema(); await createDeleteVersionButton(); } } function isSchemaListPage() { // path = /dataValidator/08905150-2e46-4db0-b9c2-52dc6c376d29/schemas const path = document.location.pathname; return path.length == 59 && path.endsWith('/schemas'); } function isSchemaPage() { // path = /dataValidator/08905150-2e46-4db0-b9c2-52dc6c376d29/schemas/939bea1f-a595-4218-b31f-834a84aef632 const path = document.location.pathname; return path.length == 96 && path.slice(51, 59).endsWith('/schemas'); } function findElementByXPath(xpath, interval = 100) { return new Promise((resolve) => { window.__findElementByXPath = window.setInterval(() => { const element = document.evaluate(xpath, document, null, XPathResult.ANY_TYPE, null).iterateNext(); if (element) { console.log('findElementByXPath', element); resolve(element); window.clearInterval(window.__findElementByXPath); } }, interval); }); } function findElement(selector, interval = 100) { return new Promise((resolve) => { window.intervalHandler = window.setInterval(() => { const element = document.querySelector(selector); resolve(element); window.clearInterval(window.intervalHandler); }, interval); }); } function findElements(selector, interval = 100) { return new Promise((resolve) => { window.intervalHandler = window.setInterval(() => { const elements = [...document.querySelectorAll(selector)]; resolve(elements); window.clearInterval(window.intervalHandler); }, interval); }); } async function createConvertButton() { const addButton = await findElement('#addSchemaButton'); if (!addButton) return; const container = addButton.parentElement; let button = document.createElement('button'); button.innerText = 'Create Schema from IMT (json)'; button.id = 'convertButton'; button.style.borderRadius = '5px'; button.style.marginLeft = '5px'; button.style.backgroundColor = 'pink'; button.addEventListener('click', createSchemaFromIMT); container.appendChild(button); button = document.createElement('button'); button.innerText = 'Copy from another schema'; button.style.borderRadius = '5px'; button.style.marginLeft = '5px'; button.style.backgroundColor = 'pink'; button.addEventListener('click', copySchema); container.appendChild(button); } async function createSchemaDeleteButtons() { const list = await findElements('ul#sortedSchemasList > li'); if (list.length == 0) return; for (let r of list) { const name = r.querySelector('span:first-child').innerText.trim(); const container = r.querySelector('div:last-child'); const button = document.createElement('button'); button.innerText = 'Delete'; button.style.borderRadius = '5px'; button.style.marginLeft = '5px'; button.style.backgroundColor = 'pink'; button.addEventListener('click', (e) => { e.preventDefault(); e.cancelBubble = true; deleteSchema(name); }); container.appendChild(button); } } async function createDeleteVersionButton() { const targetButton = await findElementByXPath('//button[contains(text(), "Activate version")]'); if (!targetButton) return; const container = targetButton.parentElement; let button = document.createElement('button'); button.id = 'version-delete-button'; button.innerText = 'Delete version'; button.style = 'height: 40px; background-color: pink; border-radius: 5px'; button.addEventListener('click', (e) => deleteSchemaVersion(container)); container.appendChild(button); } async function deleteSchema(name) { function del(workspaceId, schemaId) { return new Promise((resolve, reject) => GM.xmlHttpRequest({ url: `${baseUrl}/workspaces/${workspaceId}/schemas/${schemaId}?delete`, method: 'DELETE', headers: { 'Content-Type': 'application/json' }, onload: () => resolve(), onerror: (err) => reject(err) }) ); } const schemas = window.schemas; const schema = schemas.find((s) => s.name == name); if (schema) { if (confirm(`Delete schema ${name}?`)) { const workspaceId = getWorkspaceId(); await del(workspaceId, schema.schemaId); location.assign(location.href); } } } async function deleteSchemaVersion(container) { function del(workspaceId, versionId) { return new Promise((resolve, reject) => GM.xmlHttpRequest({ url: `${baseUrl}/workspaces/${workspaceId}/schemaVersions/${versionId}?delete`, method: 'DELETE', headers: { 'Content-Type': 'application/json' }, onload: () => resolve(), onerror: (err) => reject(err) }) ); } const versionText = container.firstChild.querySelector('button').textContent; const version = parseInt(versionText.split(' ')[1]); const schema = window.schema; const schemaVersion = schema.versions.find((v) => v.version == version); if (schemaVersion) { if (schemaVersion.isActive) { alert('cannot delete active version'); return; } if (confirm(`Delete version ${version}?`)) { const workspaceId = getWorkspaceId(); await del(workspaceId, schemaVersion.schemaVersionId); location.assign(location.href); } } } function getWorkspaceId() { const path = document.location.pathname; return (path.length >= 51 && path.slice(15, 51)) || null; } function getSchemaId() { const path = document.location.pathname; return (path.length >= 96 && path.slice(60, 96)) || null; } async function createSchemaFromIMT() { const workspaceId = getWorkspaceId(); const shortName = prompt('Enter the short name of your schema'); const input = prompt('JSON from IMT'); if (!workspaceId || !shortName?.trim() || !input?.trim()) return; const imt = JSON.parse(input); const schema = imt2dv(shortName, shortName, shortName, imt); const result = await createSchema(workspaceId, schema); if (result) { location.assign(location.pathname); } } async function copySchema() { function get(workspaceId, schemaId) { return new Promise((resolve, reject) => GM.xmlHttpRequest({ url: `${baseUrl}/workspaces/${workspaceId}/schemas/${schemaId}`, method: 'GET', headers: { 'Content-Type': 'application/json' }, onload: (res) => resolve(JSON.parse(res.response)), onerror: (err) => reject(err) }) ); } function getValidators(workspaceId) { return new Promise((resolve, reject) => GM.xmlHttpRequest({ url: `${baseUrl}/workspaces/${workspaceId}/validators`, method: 'GET', headers: { 'Content-Type': 'application/json' }, onload: (res) => resolve(JSON.parse(res.response)), onerror: (err) => reject(err) }) ); } function createValidator(workspaceId, validator) { validator.name += '1'; return new Promise((resolve, reject) => GM.xmlHttpRequest({ url: `${baseUrl}/workspaces/${workspaceId}/validators`, method: 'POST', data: JSON.stringify(validator), headers: { 'Content-Type': 'application/json' }, onload: (res) => resolve(JSON.parse(res.response)), onerror: (err) => reject(err) }) ); } const workspaceId = getWorkspaceId(); const otherWorkspaceId = prompt('The other workspaceId'); const otherSchemaId = prompt('The other schemaId'); const shortName = prompt('Enter the short name of new schema'); if (!workspaceId || !otherWorkspaceId || !otherSchemaId || !shortName?.trim()) return; const otherSchema = await get(otherWorkspaceId, otherSchemaId); const otherValidators = await getValidators(otherWorkspaceId); const validators = [...window.columnValidators]; for (let ov of otherValidators) { if (validators.find((v) => v.name == ov.name)) continue; const newValidator = await createValidator(workspaceId, ov); validators.push(newValidator); } const schema = schemaReadToWrite(otherSchema, validators); if (!schema) { alert('Error'); return; } const result = await createSchema(workspaceId, schema); if (result) { location.assign(location.pathname); } } async function loadSchemas() { function get(workspaceId) { return new Promise((resolve, reject) => GM.xmlHttpRequest({ url: `${baseUrl}/workspaces/${workspaceId}/schemas`, method: 'GET', headers: { 'Content-Type': 'application/json' }, onload: (res) => resolve(JSON.parse(res.response)), onerror: (err) => reject(err) }) ); } const workspaceId = getWorkspaceId(); const schemas = await get(workspaceId); window.schemas = schemas; } async function loadSchema() { function get(workspaceId, schemaId) { return new Promise((resolve, reject) => GM.xmlHttpRequest({ url: `${baseUrl}/workspaces/${workspaceId}/schemas/${schemaId}`, method: 'GET', headers: { 'Content-Type': 'application/json' }, onload: (res) => resolve(JSON.parse(res.response)), onerror: (err) => reject(err) }) ); } const [workspaceId, schemaId] = [getWorkspaceId(), getSchemaId()]; const schema = await get(workspaceId, schemaId); window.schema = schema; } async function loadColumnValidators() { function getPredefined() { return new Promise((resolve, reject) => GM.xmlHttpRequest({ url: `${baseUrl}/validators`, method: 'GET', headers: { 'Content-Type': 'application/json' }, onload: (res) => resolve(JSON.parse(res.response)), onerror: (err) => reject(err) }) ); } function get(workspaceId) { return new Promise((resolve, reject) => GM.xmlHttpRequest({ url: `${baseUrl}/workspaces/${workspaceId}/validators`, method: 'GET', headers: { 'Content-Type': 'application/json' }, onload: (res) => { console.log(res.response); resolve(JSON.parse(res.response)); }, onerror: (err) => reject(err) }) ); } try { const v1 = (await getPredefined()) || []; const v2 = (await get(getWorkspaceId())) || []; const v = []; v.push(...v1); v.push(...v2); window.columnValidators = v; } catch (e) { console.error(e); } } function createSchema(workspaceId, schema) { return new Promise((resolve, reject) => { GM.xmlHttpRequest({ url: `${baseUrl}/workspaces/${workspaceId}/schemas`, method: 'POST', data: JSON.stringify(schema), headers: { 'Content-Type': 'application/json' }, onload: (res) => resolve(JSON.parse(res.response)), onerror: (err) => reject(err) }); }); } function imt2dv(name, shortName, description, imt) { const columnValidators = window.columnValidators; function getColumnValidator(name) { if (columnValidators) { return columnValidators.find((v) => v.name == name); } } function convertColumnValidators(imt) { return Object.keys(imt).map((k) => { const columnValidatorId = getColumnValidator(k).columnValidatorId; const severity = imt[k] == 0 ? 'Error' : imt[k] == 1 ? 'Warning' : 'Correction'; return { columnValidatorId, severity }; }); } function convertColumns(imt) { return imt.map((c, i) => ({ name: c.Src, mustBePresent: c.MustBePresent, columnOrder: i + 1, metaFormat: c.Format, schemaColumnType: c.Meta ? 'Metadata' : 'Validation', metaType: 'NotApplicable', columnValidators: convertColumnValidators(c.Rules) })); } function convertRowValidators(imt) { return Object.keys(imt).map((k) => { const v = imt[k]; return { name: k, checkParameter: v.CheckParameter || '', ogicalOperator: v.RulesLogicalOperator, rowValidatorType: v.Type, columnsToCheck: v.ColsToCheck, columnsToAffect: v.ColsToAffect }; }); } const schemaColumns = convertColumns(imt.ColumnsOrder); const rowValidators = convertRowValidators(imt.Row); return { name, shortName, description, version: { schemaColumns, rowValidators } }; } function schemaReadToWrite(schema, columnValidators) { schema.version = schema.activeVersion; for (let key of ['schemaId', 'isPredefined', 'workspaceId', 'activeVersion', 'versions']) { delete schema[key]; } for (let key of ['schemaVersionId', 'schemaId', 'version', 'isActive']) { delete schema.version[key]; } for (let column of schema.version.schemaColumns) { for (let key of ['schemaColumnId', 'schemaVersionId']) { delete column[key]; } for (let validator of column.columnValidators) { const v = columnValidators.find( (v) => v.name == validator.validatorName || v.name == validator.validatorName + '1' ); if (!v) { console.error(validator); return undefined; } validator.columnValidatorId = v.columnValidatorId; for (let key of ['schemaColumnId', 'validatorName']) { delete validator[key]; } } } for (let validator of schema.version.rowValidators) { for (let key of ['rowValidatorId', 'schemaVersionId']) { delete validator[key]; } validator.columnsToCheck = validator.columnsToCheck.map((c) => c.columnName); validator.columnsToAffect = validator.columnsToAffect.map((c) => c.columnName); } return schema; }