* ci(deployment): injecting secrets Signed-off-by: Rajesh Rajendran <rjshrjndrn@gmail.com> * fix: typo * feat(installation): Enterprise license check * fix(install): reset ee cli args Signed-off-by: Rajesh Rajendran <rjshrjndrn@gmail.com> * Fix typo * Update README.md * feat (tracker-axios): init plugin * fix (tracker-axios): version patch * Fixed alert's unknown metrics handler * fix (tracker-mobx): dev-dependencies and updated package-lock * feat: APIs for user session data deleteion - wip * fix: alert metric value of performance.speed_index * Build and deploy scripts for enterprise edition (#13) * feat(installation): enterprise installation * chore(install): enabling ansible gather_facts Signed-off-by: Rajesh Rajendran <rjshrjndrn@gmail.com> * chore(install): quotes for enterprise key Signed-off-by: Rajesh Rajendran <rjshrjndrn@gmail.com> * chore(installation): enterprise install dbs Signed-off-by: Rajesh Rajendran <rjshrjndrn@gmail.com> * chore(install): rename yaml * chore(install): change image tag Signed-off-by: Rajesh Rajendran <rjshrjndrn@gmail.com> * chore(install): License key variable added * chore(deployment): Injecting enterprise license key in workers. * chore(install): remove deprecated files * chore(install): make domain_name mandatory in vars.yaml Signed-off-by: Rajesh Rajendran <rjshrjndrn@gmail.com> * chore(actions): ee workers Signed-off-by: Rajesh Rajendran <rjshrjndrn@gmail.com> * feat(install): use local docker instead of crictl You can use the images built in the local machine, in installation, without putting that in any external registry. Signed-off-by: Rajesh Rajendran <rjshrjndrn@gmail.com> * feat: APIs for user session data deleteion * feat: prefix deleted mobs with DEL_ * feat: schedules to delete mobs * chore(ci): fix ee build Signed-off-by: Rajesh Rajendran <rjshrjndrn@gmail.com> * feat(build): passing build args to internal scripts Signed-off-by: Rajesh Rajendran <rjshrjndrn@gmail.com> * chore(install): moving kafka topic creation at the end Kafka pods usually takes time to be active. Signed-off-by: Rajesh Rajendran <rjshrjndrn@gmail.com> * chore(install): removing auth service. * chore(install): Adding rancher for cluster management * chore(install): proper name for alerts template * separate requirements and clean up * feat (frontend): typescript support * feat (tracker): 3.0.4: maintain baseURL & connAttempt options * feat(api): changed license validation * feat(api): ee-license fix for unprovided value * feat(api): fixed ee-signup cursor * feat(api): FOS fix replay-mob issue * feat(api): ee log ch-resources query * chore(ci): change openreplay-cli with kube-install.sh Signed-off-by: Rajesh Rajendran <rjshrjndrn@gmail.com> * ci(actions): change ee naming * feat(api): removed ch-logs * feat(install): injecting ee variables only on ee installation. Signed-off-by: Rajesh Rajendran <rjshrjndrn@gmail.com> * chore(install): remove licence key from ee Signed-off-by: Rajesh Rajendran <rjshrjndrn@gmail.com> * fix(install): ch values for chalice * feat(clickhouse): moved creation scripts to EE folder * fix (backend-ee): disable ios tables so far * chore(install): remove deprecated mandatory variables. Signed-off-by: Rajesh Rajendran <rjshrjndrn@gmail.com> * feat(api): remove duplicate files & changed signup * fix(backend-ee): ch prepare after commit * fix(backend-ee): syntax * feat(api): added missing EE tenant column * fix(scripts-ee): correct default clickhouse host * feat(api): changed version_number location * feat(api): ee log ch-errors query * feat(api): ee fix ch-errors query * feat: skip to issue button (#23) * feat(api): 🐛 ee fix ambiguous ch-error query & accounts endpoint * Feature: Autoplay Sessions (#22) * feat: autoplay sessions * change: removed unused import * auto play filter by tab * feat(api): changed JWT authorizer & API_KEY authorizer & fix undefined project_key * feat (backend-devops): Dockerfile for all services in one image * feat(sourcemap-uploader): --verbose argument use instead of --log * feat(api): log middleware * Feature - dom inspector (#28) * feat (frontend): typescript support * feat(frontend): DOM Inspector init * fix(frontend): use tailwind bg * feat(frontend dom-inspector): add element selection & deletion * fix(frontend): todo comment * di - styling wip * feature(di) - editor theme * feat(frontend): parse attributes with RE (+ability to add) * feature(di) - input width * fix(ui): di - review changes Co-authored-by: ShiKhu <alex.kaminsky.11@gmail.com> * chore(install): remove depricated init_dbs * feat(api): ee override multi-tenant-core * fix(frontend-build): gen css types before build * fix(ui) - checking for the license (#30) Co-authored-by: Rajesh Rajendran <rjshrjndrn@gmail.com> Co-authored-by: Mehdi Osman <estradino@users.noreply.github.com> Co-authored-by: ShiKhu <alex.kaminsky.11@gmail.com> Co-authored-by: KRAIEM Taha Yassine <tahayk2@gmail.com> Co-authored-by: Rajesh Rajendran <rjshrjndrn@users.noreply.github.com> Co-authored-by: ourvakan <hi-psi@yandex.com> Co-authored-by: tahayk2@gmail.com <enissay4ever4github>
188 lines
No EOL
4.7 KiB
TypeScript
188 lines
No EOL
4.7 KiB
TypeScript
import React, { useEffect, useState } from 'react';
|
|
import cn from 'classnames';
|
|
import useToggle from 'App/hooks/useToggle';
|
|
import useForceUpdate from 'App/hooks/useForceUpdate';
|
|
import { Icon } from 'UI';
|
|
import stl from './inspector.css';
|
|
|
|
import AttrView from './AttrView';
|
|
import TextView from './TextView';
|
|
import InlineInput from './InlineInput';
|
|
|
|
|
|
|
|
//TODO: add attribute, add child, add text (when there was no text before), Ctrl+Z
|
|
|
|
interface Window {
|
|
Element: typeof Element;
|
|
Text: typeof Text;
|
|
document: typeof document;
|
|
}
|
|
|
|
interface Props {
|
|
element: Element;
|
|
level: number;
|
|
context?: Window;
|
|
openChain: Element[];
|
|
forceUpdateParent: () => void;
|
|
selectedElement?: Element; // for deletion and other things
|
|
setSelectedElement?: (Element) => void;
|
|
onHover?: (Element) => void;
|
|
className?: String
|
|
}
|
|
|
|
interface TagEditorProps {
|
|
element: Element;
|
|
forceUpdateParent: () => void;
|
|
context: Window;
|
|
}
|
|
|
|
|
|
// TODO: to common space
|
|
function stopPropagation(cb: Function): React.MouseEventHandler {
|
|
return function(e) {
|
|
e.stopPropagation();
|
|
cb();
|
|
}
|
|
}
|
|
|
|
const RESTRICTED_TAGS = ['html', 'body', 'head'];
|
|
function TagEditor({ element, forceUpdateParent, context }: TagEditorProps) {
|
|
const [ editing, setEditing ] = useState(false);
|
|
const commitTag = (newTag: string) => {
|
|
if (newTag !== '' &&
|
|
!RESTRICTED_TAGS.includes(newTag) &&
|
|
element.parentNode &&
|
|
/^[a-zA-Z]+$/.test(newTag) // TODO: sync with spec
|
|
) {
|
|
const rElem = context.document.createElement(newTag);
|
|
rElem.innerHTML = element.innerHTML;
|
|
Array.from(element.attributes).forEach(attr => {
|
|
rElem.setAttribute(attr.name, attr.value);
|
|
})
|
|
element.parentNode.replaceChild(rElem, element);
|
|
}
|
|
setEditing(false);
|
|
forceUpdateParent();
|
|
}
|
|
|
|
const tag = element.tagName.toLowerCase();
|
|
return editing && !RESTRICTED_TAGS.includes(tag)
|
|
? <InlineInput value={ tag } commit={ commitTag } />
|
|
: <span
|
|
className={stl.tag}
|
|
onDoubleClick={
|
|
RESTRICTED_TAGS.includes(tag)
|
|
? undefined
|
|
: () => setEditing(true) }
|
|
>{ tag }</span>
|
|
;
|
|
}
|
|
|
|
//const IGNORE_CLASSES = [ "-openreplay-hover" ];
|
|
|
|
|
|
export default function ElementView({
|
|
element,
|
|
level,
|
|
context = window,
|
|
openChain,
|
|
forceUpdateParent,
|
|
selectedElement,
|
|
setSelectedElement,
|
|
onHover,
|
|
className
|
|
}: Props) {
|
|
const [ open, toggleOpen, _, setOpen ] = useToggle(false);
|
|
|
|
// useEffect(() => { // TODO: common. something like onElementMount
|
|
// IGNORE_CLASSES.forEach(cls => element.classList.remove(cls));
|
|
// if (element.classList.length === 0) {
|
|
// element.removeAttribute("class");
|
|
// }
|
|
// }, [])
|
|
|
|
useEffect(() => {
|
|
if (openChain[ level ] === element) {
|
|
setOpen();
|
|
}
|
|
}, [ openChain[ level ] ]);
|
|
const forceUpdate = useForceUpdate();
|
|
|
|
const tag = element.tagName.toLowerCase();
|
|
const isSelected = selectedElement === element;
|
|
const selectElement = setSelectedElement
|
|
? stopPropagation(() => setSelectedElement(element))
|
|
: undefined;
|
|
const onMouseOver = onHover
|
|
? stopPropagation(() => onHover(element))
|
|
: undefined;
|
|
return (
|
|
<div
|
|
className={ cn("font-mono", className, { // todo: only in root
|
|
[stl.bgHighlight]: !open && isSelected,
|
|
"hover:bg-gray-light": !open && !isSelected,
|
|
})}
|
|
style={{ fontSize: '12px' }}
|
|
onMouseOver={ onMouseOver }
|
|
>
|
|
<span
|
|
className={cn({
|
|
"block": open,
|
|
[stl.bgHighlight]: open && isSelected,
|
|
"hover:bg-gray-light": open && !isSelected,
|
|
})}
|
|
>
|
|
<span role="button mr-1" onClick={toggleOpen}>
|
|
<Icon inline name={open ? "caret-down-fill" : "caret-right-fill" }/>
|
|
</span>
|
|
<span onClick={ selectElement }>
|
|
<span className={stl.tag}>{'<'}</span>
|
|
<TagEditor
|
|
element={ element }
|
|
context={ context }
|
|
forceUpdateParent={ forceUpdateParent }
|
|
/>
|
|
{ Array.from(element.attributes).map(attr =>
|
|
<AttrView
|
|
attr={ attr }
|
|
forceUpdateElement={ forceUpdate }
|
|
/>
|
|
)}
|
|
<span className={stl.tag}>{'>'}</span>
|
|
</span>
|
|
</span>
|
|
{ open
|
|
?
|
|
<>
|
|
{Array.from(element.childNodes).map(child => {
|
|
if (child instanceof context.Element) {
|
|
return (
|
|
<ElementView
|
|
element={ child }
|
|
context={ context }
|
|
forceUpdateParent={ forceUpdate }
|
|
level={ level+1 }
|
|
openChain={ openChain }
|
|
selectedElement={ selectedElement }
|
|
setSelectedElement={ setSelectedElement }
|
|
onHover={ onHover }
|
|
className="pl-4"
|
|
/>
|
|
);
|
|
} else if (child instanceof context.Text) {
|
|
if (!child.nodeValue || child.nodeValue.trim() === "") {
|
|
return null;
|
|
}
|
|
return <TextView text={ child } />
|
|
}
|
|
return null;
|
|
})}
|
|
</>
|
|
: '...'
|
|
}
|
|
<span className={stl.tag}>{'</'}{ tag }{'>'}</span>
|
|
</div>
|
|
);
|
|
|
|
} |