Remove unused code, refactor frontend and revisit libraries (#2458)
* start frontend thinning * continue thinning * removing moment and moment-range * remove highlightjs * remove semantic-ui * ghaida commits to openreplay finally * unused icons * unused icons * unused icons * fix missing icons --------- Co-authored-by: Ghaida Bouchaala <ghaida.bouchaala@gmail.com>
|
|
@ -10,6 +10,11 @@
|
|||
[ "@babel/plugin-transform-runtime", { "regenerator": true } ],
|
||||
[ "@babel/plugin-proposal-decorators", { "legacy":true } ],
|
||||
[ "@babel/plugin-transform-class-properties", { "loose":true } ],
|
||||
[ "@babel/plugin-transform-private-methods", { "loose": true }]
|
||||
[ "@babel/plugin-transform-private-methods", { "loose": true }],
|
||||
["prismjs", {
|
||||
"languages": ["javascript", "css", "bash", "typescript", "jsx", "kotlin", "swift"],
|
||||
"theme": "default",
|
||||
"css": true
|
||||
}]
|
||||
]
|
||||
}
|
||||
|
|
@ -1,9 +1,8 @@
|
|||
import React from 'react';
|
||||
import Highlight from 'react-highlight';
|
||||
import DocLink from 'Shared/DocLink/DocLink';
|
||||
import AssistScript from './AssistScript';
|
||||
import AssistNpm from './AssistNpm';
|
||||
import { Tabs } from 'UI';
|
||||
import { Tabs, CodeBlock } from 'UI';
|
||||
import { useState } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
|
|
@ -38,7 +37,7 @@ const AssistDoc = (props) => {
|
|||
</div>
|
||||
|
||||
<div className="font-bold my-2">Installation</div>
|
||||
<Highlight className="js">{`npm i @openreplay/tracker-assist`}</Highlight>
|
||||
<CodeBlock language={'bash'} code={`npm i @openreplay/tracker-assist`} />
|
||||
<div className="mb-4" />
|
||||
|
||||
<div className="font-bold my-2">Usage</div>
|
||||
|
|
|
|||
|
|
@ -1,18 +1,11 @@
|
|||
import React from 'react';
|
||||
import Highlight from 'react-highlight'
|
||||
import ToggleContent from 'Shared/ToggleContent'
|
||||
|
||||
import { CodeBlock } from 'UI';
|
||||
|
||||
import ToggleContent from 'Shared/ToggleContent';
|
||||
|
||||
function AssistNpm(props) {
|
||||
return (
|
||||
<div>
|
||||
<p>Initialize the tracker then load the @openreplay/tracker-assist plugin.</p>
|
||||
|
||||
<div className="font-bold my-2">Usage</div>
|
||||
<ToggleContent
|
||||
label="Server-Side-Rendered (SSR)?"
|
||||
first={
|
||||
<Highlight className="js">
|
||||
{`import OpenReplay from '@openreplay/tracker';
|
||||
const usage = `import OpenReplay from '@openreplay/tracker';
|
||||
import trackerAssist from '@openreplay/tracker-assist';
|
||||
const tracker = new OpenReplay({
|
||||
projectKey: '${props.projectKey}',
|
||||
|
|
@ -20,12 +13,8 @@ const tracker = new OpenReplay({
|
|||
// .start() returns a promise
|
||||
tracker.start().then(sessionData => ... ).catch(e => ... )
|
||||
|
||||
tracker.use(trackerAssist(options)); // check the list of available options below`}
|
||||
</Highlight>
|
||||
}
|
||||
second={
|
||||
<Highlight className="js">
|
||||
{`import OpenReplay from '@openreplay/tracker/cjs';
|
||||
tracker.use(trackerAssist(options)); // check the list of available options below`;
|
||||
const usageCjs = `import OpenReplay from '@openreplay/tracker/cjs';
|
||||
import trackerAssist from '@openreplay/tracker-assist/cjs';
|
||||
const tracker = new OpenReplay({
|
||||
projectKey: '${props.projectKey}'
|
||||
|
|
@ -38,14 +27,8 @@ function MyApp() {
|
|||
tracker.start().then(sessionData => ... ).catch(e => ... )
|
||||
}, [])
|
||||
//...
|
||||
}`}
|
||||
</Highlight>
|
||||
}
|
||||
/>
|
||||
|
||||
<div className="font-bold my-2">Options</div>
|
||||
<Highlight className="js">
|
||||
{`trackerAssist({
|
||||
}`;
|
||||
const options = `trackerAssist({
|
||||
onAgentConnect: StartEndCallback;
|
||||
onCallStart: StartEndCallback;
|
||||
onRemoteControlStart: StartEndCallback;
|
||||
|
|
@ -75,8 +58,22 @@ type ButtonOptions = HTMLButtonElement | string | {
|
|||
innerHTML?: string, // to pass an svg string or text
|
||||
style?: StyleObject, // style object (i.e {color: 'red', borderRadius: '10px'})
|
||||
}
|
||||
`}
|
||||
</Highlight>
|
||||
`
|
||||
return (
|
||||
<div>
|
||||
<p>
|
||||
Initialize the tracker then load the @openreplay/tracker-assist plugin.
|
||||
</p>
|
||||
|
||||
<div className="font-bold my-2">Usage</div>
|
||||
<ToggleContent
|
||||
label="Server-Side-Rendered (SSR)?"
|
||||
first={<CodeBlock code={usage} language="javascript" />}
|
||||
second={<CodeBlock code={usageCjs} language="jsx" />}
|
||||
/>
|
||||
|
||||
<div className="font-bold my-2">Options</div>
|
||||
<CodeBlock code={options} language="typescript" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,8 @@
|
|||
import React from 'react';
|
||||
import Highlight from 'react-highlight'
|
||||
import { CodeBlock } from "UI";
|
||||
|
||||
function AssistScript(props) {
|
||||
return (
|
||||
<div>
|
||||
<p>If your OpenReplay tracker is set up using the JS snippet, then simply replace the .../openreplay.js occurrence with .../openreplay-assist.js. Below is an example of how the script should like after the change:</p>
|
||||
<div className="py-3" />
|
||||
|
||||
<Highlight className="js">
|
||||
{`<!-- OpenReplay Tracking Code -->
|
||||
const scriptCode = `<!-- OpenReplay Tracking Code -->
|
||||
<script>
|
||||
(function(A,s,a,y,e,r){
|
||||
r=window.OpenReplay=[s,r,e,[y-1]];
|
||||
|
|
@ -24,8 +18,13 @@ function AssistScript(props) {
|
|||
r.isActive=function(){return false};
|
||||
r.getSessionToken=function(){};
|
||||
})(0, "${props.projectKey}", "${window.env.TRACKER_HOST || '//static.openreplay.com'}/${window.env.TRACKER_VERSION}/openreplay-assist.js", 1, 28);
|
||||
</script>`}
|
||||
</Highlight>
|
||||
</script>`
|
||||
return (
|
||||
<div>
|
||||
<p>If your OpenReplay tracker is set up using the JS snippet, then simply replace the .../openreplay.js occurrence with .../openreplay-assist.js. Below is an example of how the script should like after the change:</p>
|
||||
<div className="py-3" />
|
||||
|
||||
<CodeBlock code={scriptCode} language={'js'} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,37 +1,12 @@
|
|||
import React from 'react';
|
||||
import Highlight from 'react-highlight';
|
||||
import { CodeBlock } from "UI";
|
||||
import DocLink from 'Shared/DocLink/DocLink';
|
||||
import ToggleContent from 'Shared/ToggleContent';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
const GraphQLDoc = (props) => {
|
||||
const { projectKey } = props;
|
||||
return (
|
||||
<div className="bg-white h-screen overflow-y-auto" style={{ width: '500px' }}>
|
||||
<h3 className="p-5 text-2xl">GraphQL</h3>
|
||||
<div className="p-5">
|
||||
<p>
|
||||
This plugin allows you to capture GraphQL requests and inspect them later on while replaying session recordings. This is very
|
||||
useful for understanding and fixing issues.
|
||||
</p>
|
||||
<p>GraphQL plugin is compatible with Apollo and Relay implementations.</p>
|
||||
|
||||
<div className="font-bold my-2">Installation</div>
|
||||
<Highlight className="js">{`npm i @openreplay/tracker-graphql --save`}</Highlight>
|
||||
|
||||
<div className="font-bold my-2">Usage</div>
|
||||
<p>
|
||||
The plugin call will return the function, which receives four variables operationKind, operationName, variables and result. It
|
||||
returns result without changes.
|
||||
</p>
|
||||
|
||||
<div className="py-3" />
|
||||
|
||||
<ToggleContent
|
||||
label="Server-Side-Rendered (SSR)?"
|
||||
first={
|
||||
<Highlight className="js">
|
||||
{`import OpenReplay from '@openreplay/tracker';
|
||||
const usage = `import OpenReplay from '@openreplay/tracker';
|
||||
import trackerGraphQL from '@openreplay/tracker-graphql';
|
||||
//...
|
||||
const tracker = new OpenReplay({
|
||||
|
|
@ -40,12 +15,8 @@ const tracker = new OpenReplay({
|
|||
// .start() returns a promise
|
||||
tracker.start().then(sessionData => ... ).catch(e => ... )
|
||||
//...
|
||||
export const recordGraphQL = tracker.use(trackerGraphQL());`}
|
||||
</Highlight>
|
||||
}
|
||||
second={
|
||||
<Highlight className="js">
|
||||
{`import OpenReplay from '@openreplay/tracker/cjs';
|
||||
export const recordGraphQL = tracker.use(trackerGraphQL());`
|
||||
const usageCjs = `import OpenReplay from '@openreplay/tracker/cjs';
|
||||
import trackerGraphQL from '@openreplay/tracker-graphql/cjs';
|
||||
//...
|
||||
const tracker = new OpenReplay({
|
||||
|
|
@ -59,8 +30,35 @@ function SomeFunctionalComponent() {
|
|||
}, [])
|
||||
}
|
||||
//...
|
||||
export const recordGraphQL = tracker.use(trackerGraphQL());`}
|
||||
</Highlight>
|
||||
export const recordGraphQL = tracker.use(trackerGraphQL());`
|
||||
return (
|
||||
<div className="bg-white h-screen overflow-y-auto" style={{ width: '500px' }}>
|
||||
<h3 className="p-5 text-2xl">GraphQL</h3>
|
||||
<div className="p-5">
|
||||
<p>
|
||||
This plugin allows you to capture GraphQL requests and inspect them later on while replaying session recordings. This is very
|
||||
useful for understanding and fixing issues.
|
||||
</p>
|
||||
<p>GraphQL plugin is compatible with Apollo and Relay implementations.</p>
|
||||
|
||||
<div className="font-bold my-2">Installation</div>
|
||||
<CodeBlock code={'npm i @openreplay/tracker-graphql --save'} language={'bash'} />
|
||||
|
||||
<div className="font-bold my-2">Usage</div>
|
||||
<p>
|
||||
The plugin call will return the function, which receives four variables operationKind, operationName, variables and result. It
|
||||
returns result without changes.
|
||||
</p>
|
||||
|
||||
<div className="py-3" />
|
||||
|
||||
<ToggleContent
|
||||
label="Server-Side-Rendered (SSR)?"
|
||||
first={
|
||||
<CodeBlock language={'js'} code={usage} />
|
||||
}
|
||||
second={
|
||||
<CodeBlock language={'jsx'} code={usageCjs} />
|
||||
}
|
||||
/>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,36 +1,13 @@
|
|||
import React from 'react';
|
||||
import Highlight from 'react-highlight';
|
||||
import ToggleContent from 'Shared/ToggleContent';
|
||||
import DocLink from 'Shared/DocLink/DocLink';
|
||||
import { connect } from 'react-redux';
|
||||
import { CodeBlock } from "UI";
|
||||
|
||||
const MobxDoc = (props) => {
|
||||
const { projectKey } = props;
|
||||
return (
|
||||
<div className="bg-white h-screen overflow-y-auto" style={{ width: '500px' }}>
|
||||
<h3 className="p-5 text-2xl">MobX</h3>
|
||||
<div className="p-5">
|
||||
<div>
|
||||
This plugin allows you to capture MobX events and inspect them later on while replaying session recordings. This is very useful
|
||||
for understanding and fixing issues.
|
||||
</div>
|
||||
|
||||
<div className="font-bold my-2">Installation</div>
|
||||
<Highlight className="js">{`npm i @openreplay/tracker-mobx --save`}</Highlight>
|
||||
|
||||
<div className="font-bold my-2">Usage</div>
|
||||
<p>
|
||||
Initialize the @openreplay/tracker package as usual and load the plugin into it. Then put the generated middleware into your Redux
|
||||
chain.
|
||||
</p>
|
||||
<div className="py-3" />
|
||||
|
||||
<div className="font-bold my-2">Usage</div>
|
||||
<ToggleContent
|
||||
label="Server-Side-Rendered (SSR)?"
|
||||
first={
|
||||
<Highlight className="js">
|
||||
{`import OpenReplay from '@openreplay/tracker';
|
||||
const mobxUsage = `import OpenReplay from '@openreplay/tracker';
|
||||
import trackerMobX from '@openreplay/tracker-mobx';
|
||||
//...
|
||||
const tracker = new OpenReplay({
|
||||
|
|
@ -39,12 +16,9 @@ const tracker = new OpenReplay({
|
|||
tracker.use(trackerMobX(<options>)); // check list of available options below
|
||||
// .start() returns a promise
|
||||
tracker.start().then(sessionData => ... ).catch(e => ... );
|
||||
`}
|
||||
</Highlight>
|
||||
}
|
||||
second={
|
||||
<Highlight className="js">
|
||||
{`import OpenReplay from '@openreplay/tracker/cjs';
|
||||
`
|
||||
|
||||
const mobxUsageCjs = `import OpenReplay from '@openreplay/tracker/cjs';
|
||||
import trackerMobX from '@openreplay/tracker-mobx/cjs';
|
||||
//...
|
||||
const tracker = new OpenReplay({
|
||||
|
|
@ -57,9 +31,32 @@ function SomeFunctionalComponent() {
|
|||
// .start() returns a promise
|
||||
tracker.start().then(sessionData => ... ).catch(e => ... )
|
||||
}, [])
|
||||
}`}
|
||||
</Highlight>
|
||||
}
|
||||
}`
|
||||
|
||||
return (
|
||||
<div className="bg-white h-screen overflow-y-auto" style={{ width: '500px' }}>
|
||||
<h3 className="p-5 text-2xl">MobX</h3>
|
||||
<div className="p-5">
|
||||
<div>
|
||||
This plugin allows you to capture MobX events and inspect them later on while replaying session recordings. This is very useful
|
||||
for understanding and fixing issues.
|
||||
</div>
|
||||
|
||||
<div className="font-bold my-2">Installation</div>
|
||||
<CodeBlock language={'bash'} code={`npm i @openreplay/tracker-mobx --save`} />
|
||||
|
||||
<div className="font-bold my-2">Usage</div>
|
||||
<p>
|
||||
Initialize the @openreplay/tracker package as usual and load the plugin into it. Then put the generated middleware into your Redux
|
||||
chain.
|
||||
</p>
|
||||
<div className="py-3" />
|
||||
|
||||
<div className="font-bold my-2">Usage</div>
|
||||
<ToggleContent
|
||||
label="Server-Side-Rendered (SSR)?"
|
||||
first={<CodeBlock language={'js'} code={mobxUsage} />}
|
||||
second={<CodeBlock language={'jsx'} code={mobxUsageCjs} />}
|
||||
/>
|
||||
|
||||
<DocLink className="mt-4" label="Integrate MobX" url="https://docs.openreplay.com/plugins/mobx" />
|
||||
|
|
|
|||
|
|
@ -1,33 +1,12 @@
|
|||
import React from 'react';
|
||||
import Highlight from 'react-highlight';
|
||||
import { CodeBlock } from "UI";
|
||||
import ToggleContent from 'Shared/ToggleContent';
|
||||
import DocLink from 'Shared/DocLink/DocLink';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
const NgRxDoc = (props) => {
|
||||
const { projectKey } = props;
|
||||
return (
|
||||
<div className="bg-white h-screen overflow-y-auto" style={{ width: '500px' }}>
|
||||
<h3 className="p-5 text-2xl">NgRx</h3>
|
||||
<div className="p-5">
|
||||
<div>
|
||||
This plugin allows you to capture NgRx actions/state and inspect them later on while replaying session recordings. This is very
|
||||
useful for understanding and fixing issues.
|
||||
</div>
|
||||
|
||||
<div className="font-bold my-2">Installation</div>
|
||||
<Highlight className="js">{`npm i @openreplay/tracker-ngrx --save`}</Highlight>
|
||||
|
||||
<div className="font-bold my-2">Usage</div>
|
||||
<p>Add the generated meta-reducer into your imports. See NgRx documentation for more details.</p>
|
||||
<div className="py-3" />
|
||||
|
||||
<div className="font-bold my-2">Usage</div>
|
||||
<ToggleContent
|
||||
label="Server-Side-Rendered (SSR)?"
|
||||
first={
|
||||
<Highlight className="js">
|
||||
{`import { StoreModule } from '@ngrx/store';
|
||||
const usage = `import { StoreModule } from '@ngrx/store';
|
||||
import { reducers } from './reducers';
|
||||
import OpenReplay from '@openreplay/tracker';
|
||||
import trackerNgRx from '@openreplay/tracker-ngrx';
|
||||
|
|
@ -43,12 +22,8 @@ const metaReducers = [tracker.use(trackerNgRx(<options>))]; // check list of ava
|
|||
@NgModule({
|
||||
imports: [StoreModule.forRoot(reducers, { metaReducers })]
|
||||
})
|
||||
export class AppModule {}`}
|
||||
</Highlight>
|
||||
}
|
||||
second={
|
||||
<Highlight className="js">
|
||||
{`import { StoreModule } from '@ngrx/store';
|
||||
export class AppModule {}`
|
||||
const usageCjs = `import { StoreModule } from '@ngrx/store';
|
||||
import { reducers } from './reducers';
|
||||
import OpenReplay from '@openreplay/tracker/cjs';
|
||||
import trackerNgRx from '@openreplay/tracker-ngrx/cjs';
|
||||
|
|
@ -69,8 +44,31 @@ const metaReducers = [tracker.use(trackerNgRx(<options>))]; // check list of ava
|
|||
imports: [StoreModule.forRoot(reducers, { metaReducers })]
|
||||
})
|
||||
export class AppModule {}
|
||||
}`}
|
||||
</Highlight>
|
||||
}`
|
||||
return (
|
||||
<div className="bg-white h-screen overflow-y-auto" style={{ width: '500px' }}>
|
||||
<h3 className="p-5 text-2xl">NgRx</h3>
|
||||
<div className="p-5">
|
||||
<div>
|
||||
This plugin allows you to capture NgRx actions/state and inspect them later on while replaying session recordings. This is very
|
||||
useful for understanding and fixing issues.
|
||||
</div>
|
||||
|
||||
<div className="font-bold my-2">Installation</div>
|
||||
<CodeBlock code={'npm i @openreplay/tracker-ngrx --save'} language={'bash'} />
|
||||
|
||||
<div className="font-bold my-2">Usage</div>
|
||||
<p>Add the generated meta-reducer into your imports. See NgRx documentation for more details.</p>
|
||||
<div className="py-3" />
|
||||
|
||||
<div className="font-bold my-2">Usage</div>
|
||||
<ToggleContent
|
||||
label="Server-Side-Rendered (SSR)?"
|
||||
first={
|
||||
<CodeBlock language={'js'} code={usage} />
|
||||
}
|
||||
second={
|
||||
<CodeBlock language={'jsx'} code={usageCjs} />
|
||||
}
|
||||
/>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,35 +1,12 @@
|
|||
import React from 'react';
|
||||
import Highlight from 'react-highlight';
|
||||
import { CodeBlock } from "UI";
|
||||
import ToggleContent from '../../../shared/ToggleContent';
|
||||
import DocLink from 'Shared/DocLink/DocLink';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
const PiniaDoc = (props) => {
|
||||
const { projectKey } = props;
|
||||
return (
|
||||
<div className="bg-white h-screen overflow-y-auto" style={{ width: '500px' }}>
|
||||
<h3 className="p-5 text-2xl">VueX</h3>
|
||||
<div className="p-5">
|
||||
<div>
|
||||
This plugin allows you to capture Pinia mutations + state and inspect them later on while
|
||||
replaying session recordings. This is very useful for understanding and fixing issues.
|
||||
</div>
|
||||
|
||||
<div className="font-bold my-2 text-lg">Installation</div>
|
||||
<Highlight className="js">{`npm i @openreplay/tracker-vuex --save`}</Highlight>
|
||||
|
||||
<div className="font-bold my-2 text-lg">Usage</div>
|
||||
<p>
|
||||
Initialize the @openreplay/tracker package as usual and load the plugin into it. Then put
|
||||
the generated plugin into your plugins field of your store.
|
||||
</p>
|
||||
<div className="py-3" />
|
||||
|
||||
<ToggleContent
|
||||
label="Server-Side-Rendered (SSR)?"
|
||||
first={
|
||||
<Highlight className="js">
|
||||
{`import Vuex from 'vuex'
|
||||
const usage = `import Vuex from 'vuex'
|
||||
import OpenReplay from '@openreplay/tracker';
|
||||
import trackerVuex from '@openreplay/tracker-vuex';
|
||||
//...
|
||||
|
|
@ -51,12 +28,8 @@ piniaStorePlugin(examplePiniaStore)
|
|||
// now you can use examplePiniaStore as
|
||||
// usual pinia store
|
||||
// (destructure values or return it as a whole etc)
|
||||
`}
|
||||
</Highlight>
|
||||
}
|
||||
second={
|
||||
<Highlight className="js">
|
||||
{`import Vuex from 'vuex'
|
||||
`
|
||||
const usageCjs = `import Vuex from 'vuex'
|
||||
import OpenReplay from '@openreplay/tracker/cjs';
|
||||
import trackerVuex from '@openreplay/tracker-vuex/cjs';
|
||||
//...
|
||||
|
|
@ -82,8 +55,33 @@ piniaStorePlugin(examplePiniaStore)
|
|||
// now you can use examplePiniaStore as
|
||||
// usual pinia store
|
||||
// (destructure values or return it as a whole etc)
|
||||
}`}
|
||||
</Highlight>
|
||||
}`
|
||||
return (
|
||||
<div className="bg-white h-screen overflow-y-auto" style={{ width: '500px' }}>
|
||||
<h3 className="p-5 text-2xl">VueX</h3>
|
||||
<div className="p-5">
|
||||
<div>
|
||||
This plugin allows you to capture Pinia mutations + state and inspect them later on while
|
||||
replaying session recordings. This is very useful for understanding and fixing issues.
|
||||
</div>
|
||||
|
||||
<div className="font-bold my-2 text-lg">Installation</div>
|
||||
<CodeBlock code={`npm i @openreplay/tracker-vuex --save`} language="bash" />
|
||||
|
||||
<div className="font-bold my-2 text-lg">Usage</div>
|
||||
<p>
|
||||
Initialize the @openreplay/tracker package as usual and load the plugin into it. Then put
|
||||
the generated plugin into your plugins field of your store.
|
||||
</p>
|
||||
<div className="py-3" />
|
||||
|
||||
<ToggleContent
|
||||
label="Server-Side-Rendered (SSR)?"
|
||||
first={
|
||||
<CodeBlock code={usage} language="js" />
|
||||
}
|
||||
second={
|
||||
<CodeBlock code={usageCjs} language="js" />
|
||||
}
|
||||
/>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,33 +1,15 @@
|
|||
import React from 'react';
|
||||
import Highlight from 'react-highlight';
|
||||
import ToggleContent from 'Shared/ToggleContent';
|
||||
import DocLink from 'Shared/DocLink/DocLink';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { CodeBlock } from 'UI';
|
||||
|
||||
import DocLink from 'Shared/DocLink/DocLink';
|
||||
import ToggleContent from 'Shared/ToggleContent';
|
||||
|
||||
const ProfilerDoc = (props) => {
|
||||
const { projectKey } = props;
|
||||
return (
|
||||
<div className="bg-white h-screen overflow-y-auto" style={{ width: '500px' }}>
|
||||
<h3 className="p-5 text-2xl">Profiler</h3>
|
||||
<div className="p-5">
|
||||
<div>
|
||||
The profiler plugin allows you to measure your JS functions' performance and capture both arguments and result for each function
|
||||
call.
|
||||
</div>
|
||||
const { projectKey } = props;
|
||||
|
||||
<div className="font-bold my-2">Installation</div>
|
||||
<Highlight className="js">{`npm i @openreplay/tracker-profiler --save`}</Highlight>
|
||||
|
||||
<div className="font-bold my-2">Usage</div>
|
||||
<p>Initialize the tracker and load the plugin into it. Then decorate any function inside your code with the generated function.</p>
|
||||
<div className="py-3" />
|
||||
|
||||
<div className="font-bold my-2">Usage</div>
|
||||
<ToggleContent
|
||||
label="Server-Side-Rendered (SSR)?"
|
||||
first={
|
||||
<Highlight className="js">
|
||||
{`import OpenReplay from '@openreplay/tracker';
|
||||
const usage = `import OpenReplay from '@openreplay/tracker';
|
||||
import trackerProfiler from '@openreplay/tracker-profiler';
|
||||
//...
|
||||
const tracker = new OpenReplay({
|
||||
|
|
@ -40,12 +22,8 @@ export const profiler = tracker.use(trackerProfiler());
|
|||
//...
|
||||
const fn = profiler('call_name')(() => {
|
||||
//...
|
||||
}, thisArg); // thisArg is optional`}
|
||||
</Highlight>
|
||||
}
|
||||
second={
|
||||
<Highlight className="js">
|
||||
{`import OpenReplay from '@openreplay/tracker/cjs';
|
||||
}, thisArg); // thisArg is optional`;
|
||||
const usageCjs = `import OpenReplay from '@openreplay/tracker/cjs';
|
||||
import trackerProfiler from '@openreplay/tracker-profiler/cjs';
|
||||
//...
|
||||
const tracker = new OpenReplay({
|
||||
|
|
@ -63,15 +41,48 @@ export const profiler = tracker.use(trackerProfiler());
|
|||
const fn = profiler('call_name')(() => {
|
||||
//...
|
||||
}, thisArg); // thisArg is optional
|
||||
}`}
|
||||
</Highlight>
|
||||
}
|
||||
/>
|
||||
|
||||
<DocLink className="mt-4" label="Integrate Profiler" url="https://docs.openreplay.com/plugins/profiler" />
|
||||
</div>
|
||||
}`;
|
||||
return (
|
||||
<div
|
||||
className="bg-white h-screen overflow-y-auto"
|
||||
style={{ width: '500px' }}
|
||||
>
|
||||
<h3 className="p-5 text-2xl">Profiler</h3>
|
||||
<div className="p-5">
|
||||
<div>
|
||||
The profiler plugin allows you to measure your JS functions'
|
||||
performance and capture both arguments and result for each function
|
||||
call.
|
||||
</div>
|
||||
);
|
||||
|
||||
<div className="font-bold my-2">Installation</div>
|
||||
<CodeBlock
|
||||
code={`npm i @openreplay/tracker-profiler --save`}
|
||||
language={'bash'}
|
||||
/>
|
||||
|
||||
<div className="font-bold my-2">Usage</div>
|
||||
<p>
|
||||
Initialize the tracker and load the plugin into it. Then decorate any
|
||||
function inside your code with the generated function.
|
||||
</p>
|
||||
<div className="py-3" />
|
||||
|
||||
<div className="font-bold my-2">Usage</div>
|
||||
<ToggleContent
|
||||
label="Server-Side-Rendered (SSR)?"
|
||||
first={<CodeBlock language={'js'} code={usage} />}
|
||||
second={<CodeBlock language={'jsx'} code={usageCjs} />}
|
||||
/>
|
||||
|
||||
<DocLink
|
||||
className="mt-4"
|
||||
label="Integrate Profiler"
|
||||
url="https://docs.openreplay.com/plugins/profiler"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
ProfilerDoc.displayName = 'ProfilerDoc';
|
||||
|
|
@ -80,6 +91,8 @@ export default connect((state) => {
|
|||
const siteId = state.getIn(['integrations', 'siteId']);
|
||||
const sites = state.getIn(['site', 'list']);
|
||||
return {
|
||||
projectKey: sites.find((site) => site.get('id') === siteId).get('projectKey'),
|
||||
projectKey: sites
|
||||
.find((site) => site.get('id') === siteId)
|
||||
.get('projectKey'),
|
||||
};
|
||||
})(ProfilerDoc);
|
||||
|
|
|
|||
|
|
@ -1,32 +1,13 @@
|
|||
import React from 'react';
|
||||
import Highlight from 'react-highlight';
|
||||
import { CodeBlock } from 'UI'
|
||||
import ToggleContent from '../../../shared/ToggleContent';
|
||||
import DocLink from 'Shared/DocLink/DocLink';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
const ReduxDoc = (props) => {
|
||||
const { projectKey } = props;
|
||||
return (
|
||||
<div className="bg-white h-screen overflow-y-auto" style={{ width: '500px' }}>
|
||||
<h3 className="p-5 text-2xl">Redux</h3>
|
||||
|
||||
<div className="p-5">
|
||||
<div>
|
||||
This plugin allows you to capture Redux actions/state and inspect them later on while replaying session recordings. This is very
|
||||
useful for understanding and fixing issues.
|
||||
</div>
|
||||
|
||||
<div className="font-bold my-2 text-lg">Installation</div>
|
||||
<Highlight className="js">{`npm i @openreplay/tracker-redux --save`}</Highlight>
|
||||
|
||||
<div className="font-bold my-2 text-lg">Usage</div>
|
||||
<p>Initialize the tracker then put the generated middleware into your Redux chain.</p>
|
||||
<div className="py-3" />
|
||||
<ToggleContent
|
||||
label="Server-Side-Rendered (SSR)?"
|
||||
first={
|
||||
<Highlight className="js">
|
||||
{`import { applyMiddleware, createStore } from 'redux';
|
||||
const usage = `import { applyMiddleware, createStore } from 'redux';
|
||||
import OpenReplay from '@openreplay/tracker';
|
||||
import trackerRedux from '@openreplay/tracker-redux';
|
||||
//...
|
||||
|
|
@ -39,12 +20,8 @@ tracker.start().then(sessionData => ... ).catch(e => ... )
|
|||
const store = createStore(
|
||||
reducer,
|
||||
applyMiddleware(tracker.use(trackerRedux(<options>))) // check list of available options below
|
||||
);`}
|
||||
</Highlight>
|
||||
}
|
||||
second={
|
||||
<Highlight className="js">
|
||||
{`import { applyMiddleware, createStore } from 'redux';
|
||||
);`
|
||||
const usageCjs = `import { applyMiddleware, createStore } from 'redux';
|
||||
import OpenReplay from '@openreplay/tracker/cjs';
|
||||
import trackerRedux from '@openreplay/tracker-redux/cjs';
|
||||
//...
|
||||
|
|
@ -62,8 +39,30 @@ const store = createStore(
|
|||
reducer,
|
||||
applyMiddleware(tracker.use(trackerRedux(<options>))) // check list of available options below
|
||||
);
|
||||
}`}
|
||||
</Highlight>
|
||||
}`
|
||||
return (
|
||||
<div className="bg-white h-screen overflow-y-auto" style={{ width: '500px' }}>
|
||||
<h3 className="p-5 text-2xl">Redux</h3>
|
||||
|
||||
<div className="p-5">
|
||||
<div>
|
||||
This plugin allows you to capture Redux actions/state and inspect them later on while replaying session recordings. This is very
|
||||
useful for understanding and fixing issues.
|
||||
</div>
|
||||
|
||||
<div className="font-bold my-2 text-lg">Installation</div>
|
||||
<CodeBlock code={'npm i @openreplay/tracker-redux --save'} language={'bash'} />
|
||||
|
||||
<div className="font-bold my-2 text-lg">Usage</div>
|
||||
<p>Initialize the tracker then put the generated middleware into your Redux chain.</p>
|
||||
<div className="py-3" />
|
||||
<ToggleContent
|
||||
label="Server-Side-Rendered (SSR)?"
|
||||
first={
|
||||
<CodeBlock language={'js'} code={usage} />
|
||||
}
|
||||
second={
|
||||
<CodeBlock language={'jsx'} code={usageCjs} />
|
||||
}
|
||||
/>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,35 +1,13 @@
|
|||
import React from 'react';
|
||||
import Highlight from 'react-highlight';
|
||||
import { CodeBlock } from "UI";
|
||||
import ToggleContent from '../../../shared/ToggleContent';
|
||||
import DocLink from 'Shared/DocLink/DocLink';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
const VueDoc = (props) => {
|
||||
const { projectKey, siteId } = props;
|
||||
return (
|
||||
<div className="bg-white h-screen overflow-y-auto" style={{ width: '500px' }}>
|
||||
<h3 className="p-5 text-2xl">VueX</h3>
|
||||
<div className="p-5">
|
||||
<div>
|
||||
This plugin allows you to capture VueX mutations/state and inspect them later on while
|
||||
replaying session recordings. This is very useful for understanding and fixing issues.
|
||||
</div>
|
||||
|
||||
<div className="font-bold my-2 text-lg">Installation</div>
|
||||
<Highlight className="js">{`npm i @openreplay/tracker-vuex --save`}</Highlight>
|
||||
|
||||
<div className="font-bold my-2 text-lg">Usage</div>
|
||||
<p>
|
||||
Initialize the @openreplay/tracker package as usual and load the plugin into it. Then put
|
||||
the generated plugin into your plugins field of your store.
|
||||
</p>
|
||||
<div className="py-3" />
|
||||
|
||||
<ToggleContent
|
||||
label="Server-Side-Rendered (SSR)?"
|
||||
first={
|
||||
<Highlight className="js">
|
||||
{`import Vuex from 'vuex'
|
||||
const usage = `import Vuex from 'vuex'
|
||||
import OpenReplay from '@openreplay/tracker';
|
||||
import trackerVuex from '@openreplay/tracker-vuex';
|
||||
//...
|
||||
|
|
@ -42,12 +20,8 @@ tracker.start().then(sessionData => ... ).catch(e => ... )
|
|||
const store = new Vuex.Store({
|
||||
//...
|
||||
plugins: [tracker.use(trackerVuex(<options>))] // check list of available options below
|
||||
});`}
|
||||
</Highlight>
|
||||
}
|
||||
second={
|
||||
<Highlight className="js">
|
||||
{`import Vuex from 'vuex'
|
||||
});`
|
||||
const usageCjs = `import Vuex from 'vuex'
|
||||
import OpenReplay from '@openreplay/tracker/cjs';
|
||||
import trackerVuex from '@openreplay/tracker-vuex/cjs';
|
||||
//...
|
||||
|
|
@ -65,8 +39,33 @@ const store = new Vuex.Store({
|
|||
//...
|
||||
plugins: [tracker.use(trackerVuex(<options>))] // check list of available options below
|
||||
});
|
||||
}`}
|
||||
</Highlight>
|
||||
}`
|
||||
return (
|
||||
<div className="bg-white h-screen overflow-y-auto" style={{ width: '500px' }}>
|
||||
<h3 className="p-5 text-2xl">VueX</h3>
|
||||
<div className="p-5">
|
||||
<div>
|
||||
This plugin allows you to capture VueX mutations/state and inspect them later on while
|
||||
replaying session recordings. This is very useful for understanding and fixing issues.
|
||||
</div>
|
||||
|
||||
<div className="font-bold my-2 text-lg">Installation</div>
|
||||
<CodeBlock code={`npm i @openreplay/tracker-vuex --save`} language={'bash'} />
|
||||
|
||||
<div className="font-bold my-2 text-lg">Usage</div>
|
||||
<p>
|
||||
Initialize the @openreplay/tracker package as usual and load the plugin into it. Then put
|
||||
the generated plugin into your plugins field of your store.
|
||||
</p>
|
||||
<div className="py-3" />
|
||||
|
||||
<ToggleContent
|
||||
label="Server-Side-Rendered (SSR)?"
|
||||
first={
|
||||
<CodeBlock language={'js'} code={usage} />
|
||||
}
|
||||
second={
|
||||
<CodeBlock language={'jsx'} code={usageCjs} />
|
||||
}
|
||||
/>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,35 +1,13 @@
|
|||
import React from 'react';
|
||||
import Highlight from 'react-highlight';
|
||||
import { CodeBlock } from "UI";
|
||||
import ToggleContent from '../../../shared/ToggleContent';
|
||||
import DocLink from 'Shared/DocLink/DocLink';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
const ZustandDoc = (props) => {
|
||||
const { projectKey } = props;
|
||||
return (
|
||||
<div className="bg-white h-screen overflow-y-auto" style={{ width: '500px' }}>
|
||||
<h3 className="p-5 text-2xl">Zustand</h3>
|
||||
<div className="p-5">
|
||||
<div>
|
||||
This plugin allows you to capture Zustand mutations/state and inspect them later on while replaying session recordings. This is very
|
||||
useful for understanding and fixing issues.
|
||||
</div>
|
||||
|
||||
<div className="font-bold my-2 text-lg">Installation</div>
|
||||
<Highlight className="js">{`npm i @openreplay/tracker-zustand --save`}</Highlight>
|
||||
|
||||
<div className="font-bold my-2 text-lg">Usage</div>
|
||||
<p>
|
||||
Initialize the @openreplay/tracker package as usual and load the plugin into it. Then put the generated plugin into your plugins
|
||||
field of your store.
|
||||
</p>
|
||||
<div className="py-3" />
|
||||
|
||||
<ToggleContent
|
||||
label="Server-Side-Rendered (SSR)?"
|
||||
first={
|
||||
<Highlight className="js">
|
||||
{`import create from "zustand";
|
||||
const usage = `import create from "zustand";
|
||||
import Tracker from '@openreplay/tracker';
|
||||
import trackerZustand, { StateLogger } from '@openreplay/tracker-zustand';
|
||||
|
||||
|
|
@ -55,12 +33,8 @@ const useBearStore = create(
|
|||
'bear_store'
|
||||
)
|
||||
)
|
||||
`}
|
||||
</Highlight>
|
||||
}
|
||||
second={
|
||||
<Highlight className="js">
|
||||
{`import create from "zustand";
|
||||
`
|
||||
const usageCjs =`import create from "zustand";
|
||||
import Tracker from '@openreplay/tracker/cjs';
|
||||
import trackerZustand, { StateLogger } from '@openreplay/tracker-zustand/cjs';
|
||||
|
||||
|
|
@ -85,8 +59,33 @@ const useBearStore = create(
|
|||
// and is randomly generated if undefined
|
||||
'bear_store'
|
||||
)
|
||||
)`}
|
||||
</Highlight>
|
||||
)`
|
||||
return (
|
||||
<div className="bg-white h-screen overflow-y-auto" style={{ width: '500px' }}>
|
||||
<h3 className="p-5 text-2xl">Zustand</h3>
|
||||
<div className="p-5">
|
||||
<div>
|
||||
This plugin allows you to capture Zustand mutations/state and inspect them later on while replaying session recordings. This is very
|
||||
useful for understanding and fixing issues.
|
||||
</div>
|
||||
|
||||
<div className="font-bold my-2 text-lg">Installation</div>
|
||||
<CodeBlock language={'bash'} code={`npm i @openreplay/tracker-zustand --save`} />
|
||||
|
||||
<div className="font-bold my-2 text-lg">Usage</div>
|
||||
<p>
|
||||
Initialize the @openreplay/tracker package as usual and load the plugin into it. Then put the generated plugin into your plugins
|
||||
field of your store.
|
||||
</p>
|
||||
<div className="py-3" />
|
||||
|
||||
<ToggleContent
|
||||
label="Server-Side-Rendered (SSR)?"
|
||||
first={
|
||||
<CodeBlock language={'js'} code={usage} />
|
||||
}
|
||||
second={
|
||||
<CodeBlock language={'jsx'} code={usageCjs} />
|
||||
}
|
||||
/>
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ function ByComponent({ title, rows, lineWidth, onCard, type }: {
|
|||
displayName: r.label,
|
||||
sessionCount: r.value
|
||||
})).slice(0, 4);
|
||||
|
||||
return (
|
||||
<ExCard
|
||||
title={title}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ function DashboardOptions(props: Props) {
|
|||
const { editHandler, deleteHandler, renderReport, isEnterprise, isTitlePresent } = props;
|
||||
const menuItems = [
|
||||
{ icon: 'pencil', text: 'Rename', onClick: () => editHandler(true) },
|
||||
// { icon: 'text-paragraph', text: `${!isTitlePresent ? 'Add' : 'Edit'} Description`, onClick: () => editHandler(false) },
|
||||
{ icon: 'users', text: 'Visibility & Access', onClick: editHandler },
|
||||
{ icon: 'trash', text: 'Delete', onClick: deleteHandler },
|
||||
{ icon: 'pdf-download', text: 'Download Report', onClick: renderReport, disabled: !isEnterprise, tooltipTitle: ENTERPRISE_REQUEIRED }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import cn from 'classnames';
|
||||
import moment from 'moment';
|
||||
import { DateTime } from 'luxon'
|
||||
import { IGNORED, RESOLVED } from 'Types/errorInfo';
|
||||
import ErrorName from '../ErrorName';
|
||||
import ErrorLabel from '../ErrorLabel';
|
||||
|
|
@ -76,9 +76,10 @@ export default ErrorListItem;
|
|||
const CustomTooltip = ({ active, payload, label }: any) => {
|
||||
if (active) {
|
||||
const p = payload[0].payload;
|
||||
const dateStr = p.timestamp ? DateTime.fromMillis(p.timestamp).toFormat('l') : ''
|
||||
return (
|
||||
<div className="rounded border bg-white p-2">
|
||||
<p className="label text-sm color-gray-medium">{`${p.timestamp ? moment(p.timestamp).format('l') : ''}`}</p>
|
||||
<p className="label text-sm color-gray-medium">{dateStr}</p>
|
||||
<p className="text-sm">Sessions: {p.count}</p>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
import React from 'react';
|
||||
import { ResponsiveContainer, XAxis, YAxis, CartesianGrid, Tooltip, BarChart, Bar } from 'recharts';
|
||||
import domain from "Components/Dashboard/Widgets/common/domain";
|
||||
import moment from 'moment';
|
||||
import { DateTime } from 'luxon'
|
||||
|
||||
const CustomTooltip = ({ active, payload, label, timeFormat = 'hh:mm a' }) => {
|
||||
if (active) {
|
||||
const p = payload[0].payload;
|
||||
const dateStr = DateTime.fromMillis(p.timestamp).toFormat(timeFormat)
|
||||
return (
|
||||
<div className="rounded border bg-white p-2">
|
||||
<p className="label text-sm color-gray-medium">{`${moment(p.timestamp).format(timeFormat)}`}</p>
|
||||
<p className="label text-sm color-gray-medium">{dateStr}</p>
|
||||
<p className="text-sm">Sessions: {p.count}</p>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import { BarChart, Bar, YAxis, Tooltip, XAxis } from 'recharts';
|
||||
import cn from 'classnames';
|
||||
import moment from 'moment';
|
||||
import { DateTime } from 'luxon'
|
||||
import { diffFromNowString } from 'App/date';
|
||||
import { error as errorRoute } from 'App/routes';
|
||||
import { IGNORED, RESOLVED } from 'Types/errorInfo';
|
||||
|
|
@ -14,9 +14,10 @@ import { Styles } from '../../../Dashboard/Widgets/common';
|
|||
const CustomTooltip = ({ active, payload, label }) => {
|
||||
if (active) {
|
||||
const p = payload[0].payload;
|
||||
const dateStr = p.timestamp ? DateTime.fromMillis(p.timestamp).toFormat('l') : ''
|
||||
return (
|
||||
<div className="rounded border bg-white p-2">
|
||||
<p className="label text-sm color-gray-medium">{`${moment(p.timestamp).format('l')}`}</p>
|
||||
<p className="label text-sm color-gray-medium">{dateStr}</p>
|
||||
<p className="text-sm">Sessions: {p.count}</p>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,16 +1,8 @@
|
|||
import React from 'react';
|
||||
// @ts-ignore
|
||||
import Highlight from 'react-highlight';
|
||||
import { PageTitle } from 'UI';
|
||||
import { PageTitle, CodeBlock } from 'UI';
|
||||
|
||||
function HowTo() {
|
||||
return (
|
||||
<div className={'w-full h-screen p-4'}>
|
||||
<PageTitle title={'Implement feature flags'} />
|
||||
|
||||
<div className={'my-2'}>
|
||||
<Highlight className={'js'}>
|
||||
{`
|
||||
const code = `
|
||||
// can be imported from @openreplay/tracker
|
||||
interface IFeatureFlag {
|
||||
key: string
|
||||
|
|
@ -36,8 +28,13 @@ tracker.getFeatureFlag('my_flag')
|
|||
// reload flags from server
|
||||
// (in case if any user data changed during the session)
|
||||
tracker.reloadFlags()
|
||||
`}
|
||||
</Highlight>
|
||||
`
|
||||
return (
|
||||
<div className={'w-full h-screen p-4'}>
|
||||
<PageTitle title={'Implement feature flags'} />
|
||||
|
||||
<div className={'my-2'}>
|
||||
<CodeBlock code={code} language={'typescript'} />
|
||||
</div>
|
||||
<a className={'link'} href={"https://docs.openreplay.com/en/installation/feature-flags"}>Documentation</a>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ const Login: React.FC<LoginProps> = ({
|
|||
handleSpotLogin(resp.spotJwt);
|
||||
}
|
||||
loginSuccess(resp)
|
||||
setJwt(resp.jwt)
|
||||
})
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import React from 'react';
|
||||
import stl from './installDocs.module.css';
|
||||
import cn from 'classnames';
|
||||
import Highlight from 'react-highlight';
|
||||
import React from 'react';
|
||||
|
||||
import { CodeBlock, CopyButton } from 'UI';
|
||||
|
||||
import CircleNumber from '../../CircleNumber';
|
||||
import { CopyButton } from 'UI';
|
||||
import stl from './installDocs.module.css';
|
||||
|
||||
export const installationCommand = `// Add it in your root build.gradle at the end of repositories:
|
||||
dependencyResolutionManagement {
|
||||
|
|
@ -50,111 +51,117 @@ let wifiOnly: Bool`;
|
|||
const touches = `class MainActivity : ComponentActivity() {
|
||||
// ...
|
||||
OpenReplay.setupGestureDetector(this)
|
||||
}`
|
||||
}`;
|
||||
|
||||
const sensitive = `import com.openreplay.tracker.OpenReplay
|
||||
|
||||
OpenReplay.addIgnoredView(view)
|
||||
`
|
||||
`;
|
||||
|
||||
const inputs = `import com.openreplay.tracker.OpenReplay
|
||||
|
||||
val passwordEditText = binding.password
|
||||
passwordEditText.trackTextInput(label = "password", masked = true)`
|
||||
passwordEditText.trackTextInput(label = "password", masked = true)`;
|
||||
|
||||
function AndroidInstallDocs({ site, ingestPoint }: any) {
|
||||
let _usageCode = usageCode.replace('PROJECT_KEY', site.projectKey).replace('INGEST_POINT', ingestPoint);
|
||||
let _usageCode = usageCode
|
||||
.replace('PROJECT_KEY', site.projectKey)
|
||||
.replace('INGEST_POINT', ingestPoint);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="mb-4">
|
||||
<div className="font-semibold mb-2 flex items-center">
|
||||
<CircleNumber text="1" />
|
||||
Install the SDK
|
||||
</div>
|
||||
<div className={cn(stl.snippetWrapper, 'ml-10')}>
|
||||
<div className="absolute mt-1 mr-2 right-0">
|
||||
<CopyButton content={installationCommand} />
|
||||
</div>
|
||||
<Highlight className="cli">{installationCommand}</Highlight>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="font-semibold mb-2 flex items-center">
|
||||
<CircleNumber text="2" />
|
||||
Add to your app
|
||||
</div>
|
||||
<div className="flex ml-10 mt-4">
|
||||
<div className="w-full">
|
||||
<div className={cn(stl.snippetWrapper)}>
|
||||
<div className="absolute mt-1 mr-2 right-0">
|
||||
<CopyButton content={_usageCode} />
|
||||
</div>
|
||||
<Highlight className="swift">{_usageCode}</Highlight>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="font-semibold mb-2 mt-4 flex items-center">
|
||||
<CircleNumber text="3" />
|
||||
Configuration
|
||||
</div>
|
||||
<div className="flex ml-10 mt-4">
|
||||
<div className="w-full">
|
||||
<div className={cn(stl.snippetWrapper)}>
|
||||
<Highlight className="swift">{configuration}</Highlight>
|
||||
<div className={"mt-2"}>By default, all options equals <code
|
||||
className={'p-1 text-red rounded bg-gray-lightest'}>true</code></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="font-semibold mb-2 mt-4 flex items-center">
|
||||
<CircleNumber text="4" />
|
||||
Set up touch events listener
|
||||
</div>
|
||||
<div className="flex ml-10 mt-4">
|
||||
<div className="w-full">
|
||||
<div className={cn(stl.snippetWrapper)}>
|
||||
<div className="absolute mt-1 mr-2 right-0">
|
||||
<CopyButton content={touches} />
|
||||
</div>
|
||||
<Highlight className="swift">{touches}</Highlight>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="font-semibold mb-2 mt-4 flex items-center">
|
||||
<CircleNumber text="5" />
|
||||
Hide sensitive views
|
||||
</div>
|
||||
<div className="flex ml-10 mt-4">
|
||||
<div className="w-full">
|
||||
<div className={cn(stl.snippetWrapper)}>
|
||||
<div className="absolute mt-1 mr-2 right-0">
|
||||
<CopyButton content={sensitive} />
|
||||
</div>
|
||||
<Highlight className="swift">{sensitive}</Highlight>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="font-semibold mb-2 mt-4 flex items-center">
|
||||
<CircleNumber text="6" />
|
||||
Track inputs
|
||||
</div>
|
||||
<div className="flex ml-10 mt-4">
|
||||
<div className="w-full">
|
||||
<div className={cn(stl.snippetWrapper)}>
|
||||
<div className="absolute mt-1 mr-2 right-0">
|
||||
<CopyButton content={inputs} />
|
||||
</div>
|
||||
<Highlight className="swift">{inputs}</Highlight>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
return (
|
||||
<div>
|
||||
<div className="mb-4">
|
||||
<div className="font-semibold mb-2 flex items-center">
|
||||
<CircleNumber text="1" />
|
||||
Install the SDK
|
||||
</div>
|
||||
);
|
||||
<div className={cn(stl.snippetWrapper, 'ml-10')}>
|
||||
<div className="absolute mt-1 mr-2 right-0">
|
||||
<CopyButton content={installationCommand} />
|
||||
</div>
|
||||
<CodeBlock code={installationCommand} language="bash" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="font-semibold mb-2 flex items-center">
|
||||
<CircleNumber text="2" />
|
||||
Add to your app
|
||||
</div>
|
||||
<div className="flex ml-10 mt-4">
|
||||
<div className="w-full">
|
||||
<div className={cn(stl.snippetWrapper)}>
|
||||
<div className="absolute mt-1 mr-2 right-0">
|
||||
<CopyButton content={_usageCode} />
|
||||
</div>
|
||||
<CodeBlock language={'kt'} code={_usageCode} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="font-semibold mb-2 mt-4 flex items-center">
|
||||
<CircleNumber text="3" />
|
||||
Configuration
|
||||
</div>
|
||||
<div className="flex ml-10 mt-4">
|
||||
<div className="w-full">
|
||||
<div className={cn(stl.snippetWrapper)}>
|
||||
<CodeBlock code={configuration} language={'kt'} />
|
||||
<div className={'mt-2'}>
|
||||
By default, all options equals{' '}
|
||||
<code className={'p-1 text-red rounded bg-gray-lightest'}>
|
||||
true
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="font-semibold mb-2 mt-4 flex items-center">
|
||||
<CircleNumber text="4" />
|
||||
Set up touch events listener
|
||||
</div>
|
||||
<div className="flex ml-10 mt-4">
|
||||
<div className="w-full">
|
||||
<div className={cn(stl.snippetWrapper)}>
|
||||
<div className="absolute mt-1 mr-2 right-0">
|
||||
<CopyButton content={touches} />
|
||||
</div>
|
||||
<CodeBlock code={touches} language={'kt'} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="font-semibold mb-2 mt-4 flex items-center">
|
||||
<CircleNumber text="5" />
|
||||
Hide sensitive views
|
||||
</div>
|
||||
<div className="flex ml-10 mt-4">
|
||||
<div className="w-full">
|
||||
<div className={cn(stl.snippetWrapper)}>
|
||||
<div className="absolute mt-1 mr-2 right-0">
|
||||
<CopyButton content={sensitive} />
|
||||
</div>
|
||||
<CodeBlock code={sensitive} language={'kt'} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="font-semibold mb-2 mt-4 flex items-center">
|
||||
<CircleNumber text="6" />
|
||||
Track inputs
|
||||
</div>
|
||||
<div className="flex ml-10 mt-4">
|
||||
<div className="w-full">
|
||||
<div className={cn(stl.snippetWrapper)}>
|
||||
<div className="absolute mt-1 mr-2 right-0">
|
||||
<CopyButton content={inputs} />
|
||||
</div>
|
||||
<CodeBlock code={inputs} language={'kt'} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default AndroidInstallDocs;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
import React, { useState } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import stl from './installDocs.module.css';
|
||||
import cn from 'classnames';
|
||||
import Highlight from 'react-highlight';
|
||||
import CircleNumber from '../../CircleNumber';
|
||||
import { CopyButton } from 'UI';
|
||||
import { CopyButton, CodeBlock } from 'UI';
|
||||
import { Toggler } from 'UI';
|
||||
|
||||
const installationCommand = 'npm i @openreplay/tracker';
|
||||
|
|
@ -47,7 +45,7 @@ function InstallDocs({ site }) {
|
|||
<div className="absolute mt-1 mr-2 right-0">
|
||||
<CopyButton content={installationCommand} />
|
||||
</div>
|
||||
<Highlight className="cli">{installationCommand}</Highlight>
|
||||
<CodeBlock code={installationCommand} language={'bash'} />
|
||||
</div>
|
||||
</div>
|
||||
<div className={'mb-6'}>
|
||||
|
|
@ -80,7 +78,7 @@ function InstallDocs({ site }) {
|
|||
<div className="absolute mt-1 mr-2 right-0">
|
||||
<CopyButton content={_usageCode} />
|
||||
</div>
|
||||
<Highlight className="js">{_usageCode}</Highlight>
|
||||
<CodeBlock code={_usageCode} language={'js'} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -97,7 +95,7 @@ function InstallDocs({ site }) {
|
|||
<div className="absolute mt-1 mr-2 right-0">
|
||||
<CopyButton content={_usageCodeSST} />
|
||||
</div>
|
||||
<Highlight className="js">{_usageCodeSST}</Highlight>
|
||||
<CodeBlock code={_usageCodeSST} language={'js'} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -120,7 +118,7 @@ function InstallDocs({ site }) {
|
|||
<div className="absolute mt-1 mr-2 right-0">
|
||||
<CopyButton content={`npm i @openreplay/tracker-assist`} />
|
||||
</div>
|
||||
<Highlight className="js">{`$ npm i @openreplay/tracker-assist`}</Highlight>
|
||||
<CodeBlock code={`npm i @openreplay/tracker-assist`} language={'bash'} />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
|
|
@ -131,7 +129,7 @@ function InstallDocs({ site }) {
|
|||
<div className="absolute mt-1 mr-2 right-0">
|
||||
<CopyButton content={`tracker.use(trackerAssist(options));`} />
|
||||
</div>
|
||||
<Highlight className="js">{`tracker.use(trackerAssist(options));`}</Highlight>
|
||||
<CodeBlock code={`tracker.use(trackerAssist(options));`} language={'js'} />
|
||||
</div>
|
||||
<div className={'text-sm'}>Read more about available options <a
|
||||
className={'text-main'}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import React from 'react';
|
||||
import stl from './installDocs.module.css';
|
||||
import cn from 'classnames';
|
||||
import Highlight from 'react-highlight';
|
||||
import CircleNumber from '../../CircleNumber';
|
||||
import { CopyButton } from 'UI';
|
||||
import { CopyButton, CodeBlock } from 'UI';
|
||||
|
||||
export const installationCommand = `
|
||||
// make sure to grab latest version from https://github.com/openreplay/ios-tracker
|
||||
|
|
@ -86,7 +85,7 @@ function MobileInstallDocs({ site, ingestPoint }: any) {
|
|||
<div className="absolute mt-1 mr-2 right-0">
|
||||
<CopyButton content={installationCommand} />
|
||||
</div>
|
||||
<Highlight className="cli">{installationCommand}</Highlight>
|
||||
<CodeBlock code={installationCommand} language={'bash'} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -100,7 +99,7 @@ function MobileInstallDocs({ site, ingestPoint }: any) {
|
|||
<div className="absolute mt-1 mr-2 right-0">
|
||||
<CopyButton content={_usageCode} />
|
||||
</div>
|
||||
<Highlight className="swift">{_usageCode}</Highlight>
|
||||
<CodeBlock code={_usageCode} language={'swift'} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -112,7 +111,7 @@ function MobileInstallDocs({ site, ingestPoint }: any) {
|
|||
<div className="flex ml-10 mt-4">
|
||||
<div className="w-full">
|
||||
<div className={cn(stl.snippetWrapper)}>
|
||||
<Highlight className="swift">{configuration}</Highlight>
|
||||
<CodeBlock code={configuration} language={'swift'} />
|
||||
<div className={"mt-2"}>By default, all options equals <code className={'p-1 text-red rounded bg-gray-lightest'}>true</code></div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -128,7 +127,7 @@ function MobileInstallDocs({ site, ingestPoint }: any) {
|
|||
<div className="absolute mt-1 mr-2 right-0">
|
||||
<CopyButton content={touches} />
|
||||
</div>
|
||||
<Highlight className="swift">{touches}</Highlight>
|
||||
<CodeBlock code={touches} language={'swift'} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -143,7 +142,7 @@ function MobileInstallDocs({ site, ingestPoint }: any) {
|
|||
<div className="absolute mt-1 mr-2 right-0">
|
||||
<CopyButton content={sensitive} />
|
||||
</div>
|
||||
<Highlight className="swift">{sensitive}</Highlight>
|
||||
<CodeBlock code={sensitive} language={'swift'} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -158,7 +157,7 @@ function MobileInstallDocs({ site, ingestPoint }: any) {
|
|||
<div className="absolute mt-1 mr-2 right-0">
|
||||
<CopyButton content={inputs} />
|
||||
</div>
|
||||
<Highlight className="swift">{inputs}</Highlight>
|
||||
<CodeBlock code={inputs} language={'swift'} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -22,20 +22,8 @@ class EventGroupWrapper extends React.Component {
|
|||
this.props.toggleLoadInfo();
|
||||
};
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (
|
||||
prevProps.showLoadInfo !== this.props.showLoadInfo ||
|
||||
prevProps.query !== this.props.query ||
|
||||
prevProps.event.timestamp !== this.props.event.timestamp ||
|
||||
prevProps.isNote !== this.props.isNote
|
||||
) {
|
||||
this.props.mesureHeight();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.toggleLoadInfo(this.props.isFirst);
|
||||
this.props.mesureHeight();
|
||||
}
|
||||
|
||||
onEventClick = (e) => this.props.onEventClick(e, this.props.event);
|
||||
|
|
|
|||
|
|
@ -1,20 +1,21 @@
|
|||
import Session, { mergeEventLists, sortEvents } from 'Types/session';
|
||||
import { TYPES } from 'Types/session/event';
|
||||
import { InjectedEvent } from 'Types/session/event';
|
||||
import cn from 'classnames';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import cn from 'classnames';
|
||||
import { Icon } from 'UI';
|
||||
import { List, AutoSizer, CellMeasurer } from 'react-virtualized';
|
||||
import { TYPES } from 'Types/session/event';
|
||||
import { setEventFilter, filterOutNote } from 'Duck/sessions';
|
||||
import EventGroupWrapper from './EventGroupWrapper';
|
||||
import styles from './eventsBlock.module.css';
|
||||
import EventSearch from './EventSearch/EventSearch';
|
||||
import { VList, VListHandle } from 'virtua';
|
||||
|
||||
import { PlayerContext } from 'App/components/Session/playerContext';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { RootStore } from 'App/duck';
|
||||
import useCellMeasurerCache from 'App/hooks/useCellMeasurerCache';
|
||||
import { InjectedEvent } from 'Types/session/event';
|
||||
import Session, { mergeEventLists, sortEvents } from 'Types/session';
|
||||
import { useStore } from 'App/mstore';
|
||||
import { filterOutNote, setEventFilter } from 'Duck/sessions';
|
||||
import { Icon } from 'UI';
|
||||
|
||||
import EventGroupWrapper from './EventGroupWrapper';
|
||||
import EventSearch from './EventSearch/EventSearch';
|
||||
import styles from './eventsBlock.module.css';
|
||||
|
||||
interface IProps {
|
||||
setEventFilter: (filter: { query: string }) => void;
|
||||
|
|
@ -33,16 +34,18 @@ interface IProps {
|
|||
|
||||
function EventsBlock(props: IProps) {
|
||||
const { notesStore, uxtestingStore } = useStore();
|
||||
const [mouseOver, setMouseOver] = React.useState(true);
|
||||
const scroller = React.useRef<List>(null);
|
||||
const cache = useCellMeasurerCache({
|
||||
fixedWidth: true,
|
||||
defaultHeight: 300,
|
||||
});
|
||||
const [mouseOver, setMouseOver] = React.useState(false);
|
||||
const scroller = React.useRef<VListHandle>(null);
|
||||
|
||||
const { store, player } = React.useContext(PlayerContext);
|
||||
|
||||
const { time, endTime, playing, tabStates, tabChangeEvents = [] } = store.get();
|
||||
const {
|
||||
time,
|
||||
endTime,
|
||||
playing,
|
||||
tabStates,
|
||||
tabChangeEvents = [],
|
||||
} = store.get();
|
||||
|
||||
const {
|
||||
filteredEvents,
|
||||
|
|
@ -99,48 +102,50 @@ function EventsBlock(props: IProps) {
|
|||
props.zoomStartTs,
|
||||
props.zoomEndTs,
|
||||
]);
|
||||
const findLastFitting = React.useCallback((time: number) => {
|
||||
if (!usedEvents.length) return 0;
|
||||
let i = usedEvents.length - 1;
|
||||
if (time > endTime / 2) {
|
||||
while (i >= 0) {
|
||||
const event = usedEvents[i];
|
||||
if ('time' in event && event.time <= time) break;
|
||||
i--;
|
||||
const findLastFitting = React.useCallback(
|
||||
(time: number) => {
|
||||
if (!usedEvents.length) return 0;
|
||||
let i = usedEvents.length - 1;
|
||||
if (time > endTime / 2) {
|
||||
while (i >= 0) {
|
||||
const event = usedEvents[i];
|
||||
if ('time' in event && event.time <= time) break;
|
||||
i--;
|
||||
}
|
||||
return i;
|
||||
} else {
|
||||
let l = 0;
|
||||
while (l < i) {
|
||||
const event = usedEvents[l];
|
||||
if ('time' in event && event.time >= time) break;
|
||||
l++;
|
||||
}
|
||||
return l;
|
||||
}
|
||||
return i;
|
||||
} else {
|
||||
let l = 0;
|
||||
while (l < i) {
|
||||
const event = usedEvents[l];
|
||||
if ('time' in event && event.time >= time) break;
|
||||
l++;
|
||||
}
|
||||
return l;
|
||||
}
|
||||
}, [usedEvents, time, endTime]);
|
||||
const currentTimeEventIndex = findLastFitting(time)
|
||||
},
|
||||
[usedEvents, time, endTime]
|
||||
);
|
||||
const currentTimeEventIndex = findLastFitting(time);
|
||||
|
||||
const write = ({ target: { value } }: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const write = ({
|
||||
target: { value },
|
||||
}: React.ChangeEvent<HTMLInputElement>) => {
|
||||
props.setEventFilter({ query: value });
|
||||
|
||||
setTimeout(() => {
|
||||
if (!scroller.current) return;
|
||||
|
||||
scroller.current.scrollToRow(0);
|
||||
scroller.current.scrollToIndex(0);
|
||||
}, 100);
|
||||
};
|
||||
|
||||
const clearSearch = () => {
|
||||
props.setEventFilter({ query: '' });
|
||||
if (scroller.current) {
|
||||
scroller.current.forceUpdateGrid();
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
if (!scroller.current) return;
|
||||
|
||||
scroller.current.scrollToRow(0);
|
||||
scroller.current.scrollToIndex(0);
|
||||
}, 100);
|
||||
};
|
||||
|
||||
|
|
@ -151,9 +156,9 @@ function EventsBlock(props: IProps) {
|
|||
}, []);
|
||||
React.useEffect(() => {
|
||||
if (scroller.current) {
|
||||
scroller.current.forceUpdateGrid();
|
||||
if (!mouseOver) {
|
||||
scroller.current.scrollToRow(currentTimeEventIndex);
|
||||
console.log('scrolling to index', currentTimeEventIndex, scroller.current);
|
||||
scroller.current.scrollToIndex(currentTimeEventIndex, { align: 'center' });
|
||||
}
|
||||
}
|
||||
}, [currentTimeEventIndex]);
|
||||
|
|
@ -167,45 +172,33 @@ function EventsBlock(props: IProps) {
|
|||
|
||||
const renderGroup = ({
|
||||
index,
|
||||
key,
|
||||
style,
|
||||
parent,
|
||||
}: {
|
||||
index: number;
|
||||
key: string;
|
||||
style: React.CSSProperties;
|
||||
parent: any;
|
||||
}) => {
|
||||
const isLastEvent = index === usedEvents.length - 1;
|
||||
const isLastInGroup = isLastEvent || usedEvents[index + 1]?.type === TYPES.LOCATION;
|
||||
const isLastInGroup =
|
||||
isLastEvent || usedEvents[index + 1]?.type === TYPES.LOCATION;
|
||||
const event = usedEvents[index];
|
||||
const isNote = 'noteId' in event;
|
||||
const isTabChange = 'type' in event && event.type === 'TABCHANGE';
|
||||
const isCurrent = index === currentTimeEventIndex;
|
||||
const isPrev = index < currentTimeEventIndex;
|
||||
return (
|
||||
<CellMeasurer key={key} cache={cache} parent={parent} rowIndex={index}>
|
||||
{({ measure, registerChild }) => (
|
||||
<div style={{ ...style }} ref={registerChild}>
|
||||
<EventGroupWrapper
|
||||
query={query}
|
||||
presentInSearch={eventsIndex.includes(index)}
|
||||
isFirst={index == 0}
|
||||
mesureHeight={measure}
|
||||
onEventClick={onEventClick}
|
||||
event={event}
|
||||
isLastEvent={isLastEvent}
|
||||
isLastInGroup={isLastInGroup}
|
||||
isCurrent={isCurrent}
|
||||
showSelection={!playing}
|
||||
isNote={isNote}
|
||||
isTabChange={isTabChange}
|
||||
isPrev={isPrev}
|
||||
filterOutNote={filterOutNote}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</CellMeasurer>
|
||||
<EventGroupWrapper
|
||||
query={query}
|
||||
presentInSearch={eventsIndex.includes(index)}
|
||||
isFirst={index == 0}
|
||||
onEventClick={onEventClick}
|
||||
event={event}
|
||||
isLastEvent={isLastEvent}
|
||||
isLastInGroup={isLastInGroup}
|
||||
isCurrent={isCurrent}
|
||||
showSelection={!playing}
|
||||
isNote={isNote}
|
||||
isTabChange={isTabChange}
|
||||
isPrev={isPrev}
|
||||
filterOutNote={filterOutNote}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -226,7 +219,11 @@ function EventsBlock(props: IProps) {
|
|||
width={240}
|
||||
/>
|
||||
<div
|
||||
style={{ top: '40%', left: '50%', transform: 'translate(-50%, -50%)' }}
|
||||
style={{
|
||||
top: '40%',
|
||||
left: '50%',
|
||||
transform: 'translate(-50%, -50%)',
|
||||
}}
|
||||
className={'absolute z-10'}
|
||||
>
|
||||
No video
|
||||
|
|
@ -234,7 +231,11 @@ function EventsBlock(props: IProps) {
|
|||
</div>
|
||||
) : null}
|
||||
<div className={cn(styles.hAndProgress, 'mt-3')}>
|
||||
<EventSearch onChange={write} setActiveTab={setActiveTab} value={query} />
|
||||
<EventSearch
|
||||
onChange={write}
|
||||
setActiveTab={setActiveTab}
|
||||
value={query}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-1 color-gray-medium">{eventsText}</div>
|
||||
</div>
|
||||
|
|
@ -251,23 +252,16 @@ function EventsBlock(props: IProps) {
|
|||
<span className="ml-2">No Matching Results</span>
|
||||
</div>
|
||||
)}
|
||||
<AutoSizer disableWidth>
|
||||
{({ height }) => (
|
||||
<List
|
||||
ref={scroller}
|
||||
className={styles.eventsList}
|
||||
height={height + 10}
|
||||
width={270}
|
||||
overscanRowCount={6}
|
||||
itemSize={230}
|
||||
rowCount={usedEvents.length}
|
||||
deferredMeasurementCache={cache}
|
||||
rowHeight={cache.rowHeight}
|
||||
rowRenderer={renderGroup}
|
||||
scrollToAlignment="center"
|
||||
/>
|
||||
<VList
|
||||
count={usedEvents.length}
|
||||
className={styles.eventsList}
|
||||
ref={scroller}
|
||||
>
|
||||
{usedEvents.map((_, i) => {
|
||||
return renderGroup({ index: i })
|
||||
}
|
||||
)}
|
||||
</AutoSizer>
|
||||
</VList>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,67 +1,83 @@
|
|||
import React from 'react';
|
||||
|
||||
import { CodeBlock } from 'UI';
|
||||
|
||||
import stl from './contentRender.module.css';
|
||||
import Highlight from 'react-highlight'
|
||||
|
||||
const elType = {
|
||||
PARAGRAPH: 'paragraph',
|
||||
TEXT: 'text',
|
||||
QUOTE: 'blockquote',
|
||||
CODE_BLOCK: 'codeBlock',
|
||||
MENTION: 'mention',
|
||||
RULE: 'rule',
|
||||
HARD_BREAK: 'hardBreak',
|
||||
}
|
||||
PARAGRAPH: 'paragraph',
|
||||
TEXT: 'text',
|
||||
QUOTE: 'blockquote',
|
||||
CODE_BLOCK: 'codeBlock',
|
||||
MENTION: 'mention',
|
||||
RULE: 'rule',
|
||||
HARD_BREAK: 'hardBreak',
|
||||
};
|
||||
|
||||
const renderElement = (el, provider) => {
|
||||
if (provider === 'github')
|
||||
return el
|
||||
|
||||
switch(el.type) {
|
||||
case elType.PARAGRAPH:
|
||||
return <p className={ stl.para }><ContentRender message={ el } /></p>;
|
||||
case elType.QUOTE:
|
||||
return <blockquote className={ stl.quote }><ContentRender message={ el } /></blockquote>;
|
||||
case elType.CODE_BLOCK:
|
||||
return <Highlight className={ stl.codeMirror } language={ el.attrs.language || '' }>{ codeRender(el.content)[0] }</Highlight>;
|
||||
// return <CodeMirror
|
||||
// className={ stl.codeMirror }
|
||||
// value={ codeRender(el.content)[0] }
|
||||
// options={{
|
||||
// mode: el.attrs.language || '',
|
||||
// theme: 'material',
|
||||
// lineNumbers: true,
|
||||
// readOnly: true,
|
||||
// showCursorWhenSelecting: false,
|
||||
// scroll: true
|
||||
// }}
|
||||
// />
|
||||
case elType.MENTION:
|
||||
return <span className={ stl.mention }>{ `@${el.attrs.text}` }</span>;
|
||||
case elType.RULE:
|
||||
return <hr className={ stl.rule } />
|
||||
case elType.HARD_BREAK:
|
||||
return <br />
|
||||
case elType.RULE:
|
||||
return <hr className={ stl.rule } />
|
||||
case elType.TEXT:
|
||||
return el.text;
|
||||
}
|
||||
return <ContentRender key={el.text} message={ el } />;
|
||||
}
|
||||
if (provider === 'github') return el;
|
||||
|
||||
const codeRender = (content) => content.map(el => el.text);
|
||||
switch (el.type) {
|
||||
case elType.PARAGRAPH:
|
||||
return (
|
||||
<p className={stl.para}>
|
||||
<ContentRender message={el} />
|
||||
</p>
|
||||
);
|
||||
case elType.QUOTE:
|
||||
return (
|
||||
<blockquote className={stl.quote}>
|
||||
<ContentRender message={el} />
|
||||
</blockquote>
|
||||
);
|
||||
case elType.CODE_BLOCK:
|
||||
return (
|
||||
<CodeBlock
|
||||
code={codeRender(el.content)[0]}
|
||||
language={el.attrs.language || ''}
|
||||
/>
|
||||
);
|
||||
// return <CodeMirror
|
||||
// className={ stl.codeMirror }
|
||||
// value={ codeRender(el.content)[0] }
|
||||
// options={{
|
||||
// mode: el.attrs.language || '',
|
||||
// theme: 'material',
|
||||
// lineNumbers: true,
|
||||
// readOnly: true,
|
||||
// showCursorWhenSelecting: false,
|
||||
// scroll: true
|
||||
// }}
|
||||
// />
|
||||
case elType.MENTION:
|
||||
return <span className={stl.mention}>{`@${el.attrs.text}`}</span>;
|
||||
case elType.RULE:
|
||||
return <hr className={stl.rule} />;
|
||||
case elType.HARD_BREAK:
|
||||
return <br />;
|
||||
case elType.RULE:
|
||||
return <hr className={stl.rule} />;
|
||||
case elType.TEXT:
|
||||
return el.text;
|
||||
}
|
||||
return <ContentRender key={el.text} message={el} />;
|
||||
};
|
||||
|
||||
const ContentRender = props => {
|
||||
const { message, provider } = props;
|
||||
return (
|
||||
<React.Fragment>
|
||||
{ provider === 'github' ? message :
|
||||
message && message.content && message.content.map(el => (
|
||||
<React.Fragment>{ renderElement(el, provider) }</React.Fragment>
|
||||
))
|
||||
}
|
||||
</React.Fragment>
|
||||
);
|
||||
const codeRender = (content) => content.map((el) => el.text);
|
||||
|
||||
const ContentRender = (props) => {
|
||||
const { message, provider } = props;
|
||||
return (
|
||||
<React.Fragment>
|
||||
{provider === 'github'
|
||||
? message
|
||||
: message &&
|
||||
message.content &&
|
||||
message.content.map((el) => (
|
||||
<React.Fragment>{renderElement(el, provider)}</React.Fragment>
|
||||
))}
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default ContentRender;
|
||||
|
|
|
|||
|
|
@ -3,65 +3,80 @@ import { getIn, get } from 'immutable';
|
|||
import cn from 'classnames';
|
||||
import { withRequest } from 'HOCs';
|
||||
import { Loader, Icon, JSONTree } from 'UI';
|
||||
import { Accordion } from 'semantic-ui-react';
|
||||
import { Collapse } from 'antd';
|
||||
import stl from './sentry.module.css';
|
||||
|
||||
const { Panel } = Collapse;
|
||||
|
||||
@withRequest({
|
||||
endpoint: (props) => `/integrations/sentry/events/${props.event.id}`,
|
||||
dataName: 'detailedEvent',
|
||||
loadOnInitialize: true,
|
||||
endpoint: props => `/integrations/sentry/events/${props.event.id}`,
|
||||
dataName: "detailedEvent",
|
||||
loadOnInitialize: true
|
||||
})
|
||||
export default class SentryEventInfo extends React.PureComponent {
|
||||
|
||||
makePanelsFromStackTrace(stacktrace) {
|
||||
return get(stacktrace, 'frames', []).map(({ filename, function: method, lineNo, context = [] }) => ({
|
||||
key: `${filename}_${method}_${lineNo}`,
|
||||
title: {
|
||||
content: (
|
||||
<span className={stl.accordionTitle}>
|
||||
<b>{filename}</b>
|
||||
{' in '}
|
||||
<b>{method}</b>
|
||||
{' at line '}
|
||||
<b>{lineNo}</b>
|
||||
</span>
|
||||
),
|
||||
},
|
||||
content: {
|
||||
content: (
|
||||
<ol start={getIn(context, [0, 0], 0)} className={stl.lineList}>
|
||||
{context.map(([ctxLineNo, codeText]) => (
|
||||
<li className={cn(stl.codeLine, { [stl.highlighted]: ctxLineNo === lineNo })}>{codeText}</li>
|
||||
))}
|
||||
</ol>
|
||||
),
|
||||
},
|
||||
header: (
|
||||
<span className={stl.accordionTitle}>
|
||||
<b>{filename}</b>
|
||||
{' in '}
|
||||
<b>{method}</b>
|
||||
{' at line '}
|
||||
<b>{lineNo}</b>
|
||||
</span>
|
||||
),
|
||||
content: (
|
||||
<ol start={getIn(context, [0, 0], 0)} className={stl.lineList}>
|
||||
{context.map(([ctxLineNo, codeText]) => (
|
||||
<li key={ctxLineNo} className={cn(stl.codeLine, { [stl.highlighted]: ctxLineNo === lineNo })}>
|
||||
{codeText}
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
)
|
||||
}));
|
||||
}
|
||||
|
||||
renderBody() {
|
||||
const { detailedEvent, requestError, event } = this.props;
|
||||
|
||||
const exceptionEntry = get(detailedEvent, ['entries'], []).find(({ type }) => type === 'exception');
|
||||
const exceptionEntry = get(detailedEvent, ['entries'], []).find(({ type }) => type === "exception");
|
||||
const stacktraces = getIn(exceptionEntry, ['data', 'values']);
|
||||
if (!stacktraces) {
|
||||
return <JSONTree src={requestError ? event : detailedEvent} sortKeys={false} enableClipboard />;
|
||||
return <JSONTree src={requestError ? event : detailedEvent} sortKeys={false} enableClipboard />
|
||||
}
|
||||
return stacktraces.map(({ type, value, stacktrace }) => (
|
||||
<div key={type} className={stl.stacktrace}>
|
||||
<h6>{type}</h6>
|
||||
<p>{value}</p>
|
||||
<Accordion styled panels={this.makePanelsFromStackTrace(stacktrace)} />
|
||||
</div>
|
||||
<div key={type} className={stl.stacktrace} >
|
||||
<h6>{type}</h6>
|
||||
<p>
|
||||
{value}
|
||||
</p>
|
||||
<Collapse accordion>
|
||||
{this.makePanelsFromStackTrace(stacktrace).map(panel => (
|
||||
<Panel key={panel.key} header={panel.header}>
|
||||
{panel.content}
|
||||
</Panel>
|
||||
))}
|
||||
</Collapse>
|
||||
</div>
|
||||
));
|
||||
}
|
||||
|
||||
render() {
|
||||
const { open, toggleOpen, loading } = this.props;
|
||||
const {
|
||||
open,
|
||||
toggleOpen,
|
||||
loading,
|
||||
} = this.props;
|
||||
return (
|
||||
<div className={stl.wrapper}>
|
||||
<Icon name="integrations/sentry-text" size="30" color="gray-medium" />
|
||||
<Loader loading={loading}>{this.renderBody()}</Loader>
|
||||
</div>
|
||||
<div className={stl.wrapper}>
|
||||
<Icon className={stl.icon} name="integrations/sentry-text" height="25" width="70" color="gray-medium" />
|
||||
<Loader loading={loading} >
|
||||
{this.renderBody()}
|
||||
</Loader>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||
import stl from './SelectorCard.module.css';
|
||||
import cn from 'classnames';
|
||||
import type { MarkedTarget } from 'Player';
|
||||
import { Tooltip } from 'react-tippy';
|
||||
import { Tooltip } from 'antd'
|
||||
import { PlayerContext } from 'App/components/Session/playerContext';
|
||||
|
||||
interface Props {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import { screenRecorder } from 'App/utils/screenRecorder';
|
||||
import { Tooltip } from 'react-tippy';
|
||||
import { Tooltip } from 'antd'
|
||||
import { connect } from 'react-redux';
|
||||
import { Button } from 'UI';
|
||||
import { SessionRecordingStatus } from 'Player';
|
||||
|
|
|
|||
|
|
@ -3,11 +3,13 @@ import { getIn, get } from 'immutable';
|
|||
import cn from 'classnames';
|
||||
import { withRequest } from 'HOCs';
|
||||
import { Loader, Icon, JSONTree } from 'UI';
|
||||
import { Accordion } from 'semantic-ui-react'
|
||||
import { Collapse } from 'antd';
|
||||
import stl from './sentry.module.css';
|
||||
|
||||
const { Panel } = Collapse;
|
||||
|
||||
@withRequest({
|
||||
endpoint: props => `/integrations/sentry/events/${ props.event.id }`,
|
||||
endpoint: props => `/integrations/sentry/events/${props.event.id}`,
|
||||
dataName: "detailedEvent",
|
||||
loadOnInitialize: true
|
||||
})
|
||||
|
|
@ -15,28 +17,25 @@ export default class SentryEventInfo extends React.PureComponent {
|
|||
|
||||
makePanelsFromStackTrace(stacktrace) {
|
||||
return get(stacktrace, 'frames', []).map(({ filename, function: method, lineNo, context = [] }) => ({
|
||||
key: `${ filename }_${ method }_${ lineNo }`,
|
||||
title: {
|
||||
content: (
|
||||
<span className={ stl.accordionTitle }>
|
||||
<b>{ filename }</b>
|
||||
{ ' in ' }
|
||||
<b>{ method }</b>
|
||||
{ ' at line '}
|
||||
<b>{ lineNo }</b>
|
||||
</span>
|
||||
),
|
||||
},
|
||||
content: {
|
||||
content: (
|
||||
<ol start={ getIn(context, [ 0, 0 ], 0) } className={ stl.lineList }>
|
||||
{ context.map(([ ctxLineNo, codeText ]) => (
|
||||
<li className={ cn(stl.codeLine, { [ stl.highlighted ]: ctxLineNo === lineNo }) }>
|
||||
{ codeText }
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
)}
|
||||
key: `${filename}_${method}_${lineNo}`,
|
||||
header: (
|
||||
<span className={stl.accordionTitle}>
|
||||
<b>{filename}</b>
|
||||
{' in '}
|
||||
<b>{method}</b>
|
||||
{' at line '}
|
||||
<b>{lineNo}</b>
|
||||
</span>
|
||||
),
|
||||
content: (
|
||||
<ol start={getIn(context, [0, 0], 0)} className={stl.lineList}>
|
||||
{context.map(([ctxLineNo, codeText]) => (
|
||||
<li key={ctxLineNo} className={cn(stl.codeLine, { [stl.highlighted]: ctxLineNo === lineNo })}>
|
||||
{codeText}
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
)
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
@ -46,32 +45,38 @@ export default class SentryEventInfo extends React.PureComponent {
|
|||
const exceptionEntry = get(detailedEvent, ['entries'], []).find(({ type }) => type === "exception");
|
||||
const stacktraces = getIn(exceptionEntry, ['data', 'values']);
|
||||
if (!stacktraces) {
|
||||
return <JSONTree src={ requestError ? event : detailedEvent } sortKeys={ false } enableClipboard />
|
||||
return <JSONTree src={requestError ? event : detailedEvent} sortKeys={false} enableClipboard />
|
||||
}
|
||||
return stacktraces.map(({ type, value, stacktrace }) => (
|
||||
<div key={ type } className={ stl.stacktrace } >
|
||||
<h6>{ type }</h6>
|
||||
<div key={type} className={stl.stacktrace} >
|
||||
<h6>{type}</h6>
|
||||
<p>
|
||||
{ value }
|
||||
{value}
|
||||
</p>
|
||||
<Accordion styled panels={ this.makePanelsFromStackTrace(stacktrace) }/>
|
||||
<Collapse accordion>
|
||||
{this.makePanelsFromStackTrace(stacktrace).map(panel => (
|
||||
<Panel key={panel.key} header={panel.header}>
|
||||
{panel.content}
|
||||
</Panel>
|
||||
))}
|
||||
</Collapse>
|
||||
</div>
|
||||
));
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
const {
|
||||
open,
|
||||
toggleOpen,
|
||||
loading,
|
||||
} = this.props;
|
||||
return (
|
||||
<div className={ stl.wrapper }>
|
||||
<Icon className={ stl.icon } name="integrations/sentry-text" height="25" width="70" color="gray-medium"/>
|
||||
<Loader loading={ loading } >
|
||||
{ this.renderBody() }
|
||||
<div className={stl.wrapper}>
|
||||
<Icon className={stl.icon} name="integrations/sentry-text" height="25" width="70" color="gray-medium" />
|
||||
<Loader loading={loading} >
|
||||
{this.renderBody()}
|
||||
</Loader>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
import React from 'react';
|
||||
import { List, AutoSizer } from 'react-virtualized';
|
||||
import cn from 'classnames';
|
||||
import { Duration } from "luxon";
|
||||
import { NoContent, Button } from 'UI';
|
||||
import { percentOf } from 'App/utils';
|
||||
import { Duration } from 'luxon';
|
||||
import React from 'react';
|
||||
import { VList, VListHandle } from 'virtua';
|
||||
|
||||
import { percentOf } from 'App/utils';
|
||||
import { Button, NoContent } from 'UI';
|
||||
|
||||
import autoscrollStl from '../autoscroll.module.css';
|
||||
import BarRow from './BarRow';
|
||||
import stl from './timeTable.module.css';
|
||||
|
||||
import autoscrollStl from '../autoscroll.module.css'; //aaa
|
||||
//aaa
|
||||
|
||||
type Timed = {
|
||||
time: number;
|
||||
|
|
@ -24,7 +26,8 @@ type CanBeRed = {
|
|||
};
|
||||
|
||||
interface Row extends Timed, Durationed, CanBeRed {
|
||||
[key: string]: any, key: string
|
||||
[key: string]: any;
|
||||
key: string;
|
||||
}
|
||||
|
||||
type Line = {
|
||||
|
|
@ -37,7 +40,7 @@ type Column = {
|
|||
label: string;
|
||||
width: number;
|
||||
dataKey?: string;
|
||||
render?: (row: any) => void
|
||||
render?: (row: any) => void;
|
||||
referenceLines?: Array<Line>;
|
||||
style?: React.CSSProperties;
|
||||
} & RenderOrKey;
|
||||
|
|
@ -49,25 +52,25 @@ type Column = {
|
|||
// }
|
||||
type RenderOrKey =
|
||||
| {
|
||||
render?: (row: Row) => React.ReactNode;
|
||||
key?: string;
|
||||
}
|
||||
render?: (row: Row) => React.ReactNode;
|
||||
key?: string;
|
||||
}
|
||||
| {
|
||||
dataKey: string;
|
||||
};
|
||||
dataKey: string;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
className?: string;
|
||||
rows: Array<Row>;
|
||||
children: Array<Column>;
|
||||
tableHeight?: number
|
||||
activeIndex?: number
|
||||
renderPopup?: boolean
|
||||
navigation?: boolean
|
||||
referenceLines?: any[]
|
||||
additionalHeight?: number
|
||||
hoverable?: boolean
|
||||
onRowClick?: (row: any, index: number) => void
|
||||
tableHeight?: number;
|
||||
activeIndex?: number;
|
||||
renderPopup?: boolean;
|
||||
navigation?: boolean;
|
||||
referenceLines?: any[];
|
||||
additionalHeight?: number;
|
||||
hoverable?: boolean;
|
||||
onRowClick?: (row: any, index: number) => void;
|
||||
};
|
||||
|
||||
type TimeLineInfo = {
|
||||
|
|
@ -86,15 +89,26 @@ const TIME_SECTIONS_COUNT = 8;
|
|||
const ZERO_TIMEWIDTH = 1000;
|
||||
function formatTime(ms: number) {
|
||||
if (ms < 0) return '';
|
||||
if (ms < 1000) return Duration.fromMillis(ms).toFormat('0.SSS')
|
||||
if (ms < 1000) return Duration.fromMillis(ms).toFormat('0.SSS');
|
||||
return Duration.fromMillis(ms).toFormat('mm:ss');
|
||||
}
|
||||
|
||||
function computeTimeLine(rows: Array<Row>, firstVisibleRowIndex: number, visibleCount: number): TimeLineInfo {
|
||||
const visibleRows = rows.slice(firstVisibleRowIndex, firstVisibleRowIndex + visibleCount + _additionalHeight);
|
||||
let timestart = visibleRows.length > 0 ? Math.min(...visibleRows.map((r) => r.time)) : 0;
|
||||
function computeTimeLine(
|
||||
rows: Array<Row>,
|
||||
firstVisibleRowIndex: number,
|
||||
visibleCount: number
|
||||
): TimeLineInfo {
|
||||
const visibleRows = rows.slice(
|
||||
firstVisibleRowIndex,
|
||||
firstVisibleRowIndex + visibleCount + _additionalHeight
|
||||
);
|
||||
let timestart =
|
||||
visibleRows.length > 0 ? Math.min(...visibleRows.map((r) => r.time)) : 0;
|
||||
// TODO: GraphQL requests do not have a duration, so their timeline is borked. Assume a duration of 0.2s for every GraphQL request
|
||||
const timeend = visibleRows.length > 0 ? Math.max(...visibleRows.map((r) => r.time + (r.duration ?? 200))) : 0;
|
||||
const timeend =
|
||||
visibleRows.length > 0
|
||||
? Math.max(...visibleRows.map((r) => r.time + (r.duration ?? 200)))
|
||||
: 0;
|
||||
let timewidth = timeend - timestart;
|
||||
const offset = timewidth / 70;
|
||||
if (timestart >= offset) {
|
||||
|
|
@ -116,7 +130,11 @@ const initialState = {
|
|||
|
||||
export default class TimeTable extends React.PureComponent<Props, State> {
|
||||
state = {
|
||||
...computeTimeLine(this.props.rows, initialState.firstVisibleRowIndex, this.visibleCount),
|
||||
...computeTimeLine(
|
||||
this.props.rows,
|
||||
initialState.firstVisibleRowIndex,
|
||||
this.visibleCount
|
||||
),
|
||||
...initialState,
|
||||
};
|
||||
|
||||
|
|
@ -128,47 +146,70 @@ export default class TimeTable extends React.PureComponent<Props, State> {
|
|||
return Math.ceil(this.tableHeight / ROW_HEIGHT);
|
||||
}
|
||||
|
||||
scroller = React.createRef<List>();
|
||||
scroller = React.createRef<VListHandle>();
|
||||
autoScroll = true;
|
||||
|
||||
componentDidMount() {
|
||||
if (this.scroller.current) {
|
||||
this.scroller.current.scrollToRow(this.props.activeIndex);
|
||||
this.scroller.current.scrollToIndex(this.props.activeIndex);
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: any, prevState: any) {
|
||||
if (
|
||||
prevState.firstVisibleRowIndex !== this.state.firstVisibleRowIndex ||
|
||||
(this.props.rows.length <= this.visibleCount + _additionalHeight && prevProps.rows.length !== this.props.rows.length)
|
||||
(this.props.rows.length <= this.visibleCount + _additionalHeight &&
|
||||
prevProps.rows.length !== this.props.rows.length)
|
||||
) {
|
||||
this.setState({
|
||||
...computeTimeLine(this.props.rows, this.state.firstVisibleRowIndex, this.visibleCount),
|
||||
...computeTimeLine(
|
||||
this.props.rows,
|
||||
this.state.firstVisibleRowIndex,
|
||||
this.visibleCount
|
||||
),
|
||||
});
|
||||
}
|
||||
if (this.props.activeIndex && this.props.activeIndex >= 0 && prevProps.activeIndex !== this.props.activeIndex && this.scroller.current) {
|
||||
this.scroller.current.scrollToRow(this.props.activeIndex);
|
||||
if (
|
||||
this.props.activeIndex &&
|
||||
this.props.activeIndex >= 0 &&
|
||||
prevProps.activeIndex !== this.props.activeIndex &&
|
||||
this.scroller.current
|
||||
) {
|
||||
this.scroller.current.scrollToIndex(this.props.activeIndex);
|
||||
}
|
||||
}
|
||||
|
||||
onScroll = ({ scrollTop, scrollHeight, clientHeight }: { scrollTop: number; scrollHeight: number; clientHeight: number }): void => {
|
||||
onScroll = ({
|
||||
scrollTop,
|
||||
scrollHeight,
|
||||
clientHeight,
|
||||
}: {
|
||||
scrollTop: number;
|
||||
scrollHeight: number;
|
||||
clientHeight: number;
|
||||
}): void => {
|
||||
const firstVisibleRowIndex = Math.floor(scrollTop / ROW_HEIGHT + 0.33);
|
||||
|
||||
if (this.state.firstVisibleRowIndex !== firstVisibleRowIndex) {
|
||||
this.autoScroll = scrollHeight - clientHeight - scrollTop < ROW_HEIGHT / 2;
|
||||
this.autoScroll =
|
||||
scrollHeight - clientHeight - scrollTop < ROW_HEIGHT / 2;
|
||||
this.setState({ firstVisibleRowIndex });
|
||||
}
|
||||
};
|
||||
|
||||
renderRow = ({ index, key, style: rowStyle }: any) => {
|
||||
renderRow = (index: number) => {
|
||||
const { activeIndex } = this.props;
|
||||
const { children: columns, rows, renderPopup, hoverable, onRowClick } = this.props;
|
||||
const {
|
||||
children: columns,
|
||||
rows,
|
||||
renderPopup,
|
||||
hoverable,
|
||||
onRowClick,
|
||||
} = this.props;
|
||||
const { timestart, timewidth } = this.state;
|
||||
const row = rows[index];
|
||||
return (
|
||||
<div
|
||||
style={rowStyle}
|
||||
key={key}
|
||||
className={cn('border-b border-color-gray-light-shade', stl.row, {
|
||||
[stl.hoverable]: hoverable,
|
||||
'error color-red': !!row.isRed && row.isRed,
|
||||
|
|
@ -176,16 +217,33 @@ export default class TimeTable extends React.PureComponent<Props, State> {
|
|||
[stl.activeRow]: activeIndex === index,
|
||||
// [stl.inactiveRow]: !activeIndex || index > activeIndex,
|
||||
})}
|
||||
onClick={typeof onRowClick === 'function' ? () => onRowClick(row, index) : undefined}
|
||||
onClick={
|
||||
typeof onRowClick === 'function'
|
||||
? () => onRowClick(row, index)
|
||||
: undefined
|
||||
}
|
||||
id="table-row"
|
||||
>
|
||||
{columns.map((column, key) => (
|
||||
<div key={column.label.replace(' ', '')} className={stl.cell} style={{ width: `${column.width}px` }}>
|
||||
{column.render ? column.render(row) : row[column.dataKey || ''] || <i className="color-gray-light">{'empty'}</i>}
|
||||
<div
|
||||
key={column.label.replace(' ', '')}
|
||||
className={stl.cell}
|
||||
style={{ width: `${column.width}px` }}
|
||||
>
|
||||
{column.render
|
||||
? column.render(row)
|
||||
: row[column.dataKey || ''] || (
|
||||
<i className="color-gray-light">{'empty'}</i>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
<div className={cn('relative flex-1 flex', stl.timeBarWrapper)}>
|
||||
<BarRow resource={row} timestart={timestart} timewidth={timewidth} popup={renderPopup} />
|
||||
<BarRow
|
||||
resource={row}
|
||||
timestart={timestart}
|
||||
timewidth={timewidth}
|
||||
popup={renderPopup}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -200,25 +258,37 @@ export default class TimeTable extends React.PureComponent<Props, State> {
|
|||
}
|
||||
}
|
||||
if (this.scroller.current != null) {
|
||||
this.scroller.current.scrollToRow(prevRedIndex);
|
||||
this.scroller.current.scrollToIndex(prevRedIndex);
|
||||
}
|
||||
};
|
||||
|
||||
onNextClick = () => {
|
||||
let prevRedIndex = -1;
|
||||
for (let i = this.state.firstVisibleRowIndex + 1; i < this.props.rows.length; i++) {
|
||||
for (
|
||||
let i = this.state.firstVisibleRowIndex + 1;
|
||||
i < this.props.rows.length;
|
||||
i++
|
||||
) {
|
||||
if (this.props.rows[i].isRed) {
|
||||
prevRedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (this.scroller.current != null) {
|
||||
this.scroller.current.scrollToRow(prevRedIndex);
|
||||
this.scroller.current.scrollToIndex(prevRedIndex);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { className, rows, children: columns, navigation = false, referenceLines = [], additionalHeight = 0, activeIndex } = this.props;
|
||||
const {
|
||||
className,
|
||||
rows,
|
||||
children: columns,
|
||||
navigation = false,
|
||||
referenceLines = [],
|
||||
additionalHeight = 0,
|
||||
activeIndex,
|
||||
} = this.props;
|
||||
const { timewidth, timestart } = this.state;
|
||||
|
||||
_additionalHeight = additionalHeight;
|
||||
|
|
@ -231,7 +301,9 @@ export default class TimeTable extends React.PureComponent<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
const visibleRefLines = referenceLines.filter(({ time }) => time > timestart && time < timestart + timewidth);
|
||||
const visibleRefLines = referenceLines.filter(
|
||||
({ time }) => time > timestart && time < timestart + timewidth
|
||||
);
|
||||
|
||||
const columnsSumWidth = columns.reduce((sum, { width }) => sum + width, 0);
|
||||
|
||||
|
|
@ -262,7 +334,11 @@ export default class TimeTable extends React.PureComponent<Props, State> {
|
|||
<div className={stl.headers}>
|
||||
<div className={stl.infoHeaders}>
|
||||
{columns.map(({ label, width }) => (
|
||||
<div key={label.replace(' ', '')} className={stl.headerCell} style={{ width: `${width}px` }}>
|
||||
<div
|
||||
key={label.replace(' ', '')}
|
||||
className={stl.headerCell}
|
||||
style={{ width: `${width}px` }}
|
||||
>
|
||||
{label}
|
||||
</div>
|
||||
))}
|
||||
|
|
@ -278,42 +354,37 @@ export default class TimeTable extends React.PureComponent<Props, State> {
|
|||
|
||||
<NoContent size="small" show={rows.length === 0}>
|
||||
<div className="relative">
|
||||
<div className={stl.timePart} style={{ left: `${columnsSumWidth}px` }}>
|
||||
<div
|
||||
className={stl.timePart}
|
||||
style={{ left: `${columnsSumWidth}px` }}
|
||||
>
|
||||
{timeColumns.map((_, index) => (
|
||||
<div key={`tc-${index}`} className={stl.timeCell} />
|
||||
))}
|
||||
{visibleRefLines.map((line, key) => (
|
||||
<div
|
||||
key={line.time+key}
|
||||
key={line.time + key}
|
||||
className={cn(stl.refLine, `bg-${line.color}`)}
|
||||
style={{
|
||||
left: `${percentOf(line.time - timestart, timewidth)}%`,
|
||||
cursor: typeof line.onClick === 'function' ? 'click' : 'auto',
|
||||
cursor:
|
||||
typeof line.onClick === 'function' ? 'click' : 'auto',
|
||||
}}
|
||||
onClick={line.onClick}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<AutoSizer disableHeight>
|
||||
{({ width }: { width: number }) => (
|
||||
<List
|
||||
ref={this.scroller}
|
||||
className={stl.list}
|
||||
height={this.tableHeight + additionalHeight}
|
||||
width={width}
|
||||
overscanRowCount={20}
|
||||
rowCount={rows.length}
|
||||
rowHeight={ROW_HEIGHT}
|
||||
rowRenderer={this.renderRow}
|
||||
onScroll={this.onScroll}
|
||||
scrollToAlignment="start"
|
||||
forceUpdateProp={timestart | timewidth | (activeIndex || 0)}
|
||||
/>
|
||||
)}
|
||||
</AutoSizer>
|
||||
<VList
|
||||
ref={this.scroller}
|
||||
className={stl.list}
|
||||
count={rows.length}
|
||||
itemSize={ROW_HEIGHT}
|
||||
>
|
||||
{this.props.rows.map((_, i) => this.renderRow(i))}
|
||||
</VList>
|
||||
</div>
|
||||
</NoContent>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import { observer } from 'mobx-react-lite';
|
||||
import React from 'react';
|
||||
import { AutoSizer, CellMeasurer, List } from 'react-virtualized';
|
||||
import { VList, VListHandle } from 'virtua';
|
||||
|
||||
import useCellMeasurerCache from 'App/hooks/useCellMeasurerCache';
|
||||
import BottomBlock from 'Components/shared/DevTools/BottomBlock';
|
||||
import {
|
||||
TABS,
|
||||
|
|
@ -16,13 +15,11 @@ import spotPlayerStore from '../../spotPlayerStore';
|
|||
|
||||
function SpotConsole({ onClose }: { onClose: () => void }) {
|
||||
const [activeTab, setActiveTab] = React.useState(TABS[0]);
|
||||
const _list = React.useRef<List>(null);
|
||||
const cache = useCellMeasurerCache();
|
||||
const _list = React.useRef<VListHandle>(null);
|
||||
const onTabClick = (tab: any) => {
|
||||
setActiveTab(tab);
|
||||
};
|
||||
const logs = spotPlayerStore.logs;
|
||||
console.log(logs)
|
||||
const filteredList = React.useMemo(() => {
|
||||
return logs.filter((log) => {
|
||||
const tabType = activeTab.text.toLowerCase();
|
||||
|
|
@ -30,36 +27,10 @@ function SpotConsole({ onClose }: { onClose: () => void }) {
|
|||
return tabType.includes(log.level);
|
||||
});
|
||||
}, [activeTab]);
|
||||
|
||||
const jump = (t: number) => {
|
||||
spotPlayerStore.setTime(t);
|
||||
};
|
||||
const _rowRenderer = ({ index, key, parent, style }: any) => {
|
||||
const item = filteredList[index];
|
||||
|
||||
return (
|
||||
// @ts-ignore
|
||||
<CellMeasurer
|
||||
cache={cache}
|
||||
columnIndex={0}
|
||||
key={key}
|
||||
rowIndex={index}
|
||||
parent={parent}
|
||||
>
|
||||
{({ measure, registerChild }) => (
|
||||
// @ts-ignore
|
||||
<div ref={registerChild} style={style}>
|
||||
<ConsoleRow
|
||||
log={item}
|
||||
jump={jump}
|
||||
iconProps={getIconProps(item.level)}
|
||||
renderWithNL={renderWithNL}
|
||||
recalcHeight={measure}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</CellMeasurer>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<BottomBlock>
|
||||
|
|
@ -85,22 +56,21 @@ function SpotConsole({ onClose }: { onClose: () => void }) {
|
|||
size="small"
|
||||
show={filteredList.length === 0}
|
||||
>
|
||||
<AutoSizer>
|
||||
{({ height, width }: any) => (
|
||||
<List
|
||||
ref={_list}
|
||||
deferredMeasurementCache={cache}
|
||||
overscanRowCount={5}
|
||||
estimatedRowSize={24}
|
||||
rowCount={Math.ceil(filteredList.length || 1)}
|
||||
rowHeight={cache.rowHeight}
|
||||
rowRenderer={_rowRenderer}
|
||||
width={width}
|
||||
height={height}
|
||||
scrollToAlignment="center"
|
||||
<VList
|
||||
ref={_list}
|
||||
itemSize={25}
|
||||
count={filteredList.length || 1}
|
||||
>
|
||||
{filteredList.map((log, index) => (
|
||||
<ConsoleRow
|
||||
key={log.time + index}
|
||||
log={log}
|
||||
jump={jump}
|
||||
iconProps={getIconProps(log.level)}
|
||||
renderWithNL={renderWithNL}
|
||||
/>
|
||||
)}
|
||||
</AutoSizer>
|
||||
))}
|
||||
</VList>
|
||||
</NoContent>
|
||||
</BottomBlock.Content>
|
||||
</BottomBlock>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import Hls from 'hls.js';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import React from 'react';
|
||||
|
||||
|
|
@ -34,69 +33,71 @@ function SpotVideoContainer({
|
|||
const hlsRef = React.useRef<Hls | null>(null);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (Hls.isSupported() && videoRef.current) {
|
||||
videoRef.current.addEventListener('loadeddata', () => {
|
||||
setLoaded(true);
|
||||
});
|
||||
if (streamFile) {
|
||||
const hls = new Hls({
|
||||
enableWorker: false,
|
||||
// workerPath: '/hls-worker.js',
|
||||
// 1MB buffer -- we have small videos anyways
|
||||
maxBufferSize: 1000 * 1000,
|
||||
});
|
||||
const url = URL.createObjectURL(base64toblob(streamFile));
|
||||
if (url && videoRef.current) {
|
||||
hls.loadSource(url);
|
||||
hls.attachMedia(videoRef.current);
|
||||
if (spotPlayerStore.isPlaying) {
|
||||
void videoRef.current.play();
|
||||
}
|
||||
hlsRef.current = hls;
|
||||
} else {
|
||||
if (videoRef.current) {
|
||||
videoRef.current.src = videoURL;
|
||||
if (spotPlayerStore.isPlaying) {
|
||||
void videoRef.current.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const check = () => {
|
||||
fetch(videoLink).then((r) => {
|
||||
if (r.ok && r.status === 200) {
|
||||
if (videoRef.current) {
|
||||
videoRef.current.src = '';
|
||||
setTimeout(() => {
|
||||
videoRef.current!.src = videoURL;
|
||||
}, 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
check();
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
};
|
||||
check();
|
||||
videoRef.current.src = videoURL;
|
||||
if (spotPlayerStore.isPlaying) {
|
||||
void videoRef.current.play();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (videoRef.current) {
|
||||
import('hls.js').then(({ default: Hls }) => {
|
||||
if (Hls.isSupported() && videoRef.current) {
|
||||
videoRef.current.addEventListener('loadeddata', () => {
|
||||
setLoaded(true);
|
||||
});
|
||||
videoRef.current.src = videoURL;
|
||||
if (spotPlayerStore.isPlaying) {
|
||||
void videoRef.current.play();
|
||||
if (streamFile) {
|
||||
const hls = new Hls({
|
||||
enableWorker: false,
|
||||
// workerPath: '/hls-worker.js',
|
||||
// 1MB buffer -- we have small videos anyways
|
||||
maxBufferSize: 1000 * 1000,
|
||||
});
|
||||
const url = URL.createObjectURL(base64toblob(streamFile));
|
||||
if (url && videoRef.current) {
|
||||
hls.loadSource(url);
|
||||
hls.attachMedia(videoRef.current);
|
||||
if (spotPlayerStore.isPlaying) {
|
||||
void videoRef.current.play();
|
||||
}
|
||||
hlsRef.current = hls;
|
||||
} else {
|
||||
if (videoRef.current) {
|
||||
videoRef.current.src = videoURL;
|
||||
if (spotPlayerStore.isPlaying) {
|
||||
void videoRef.current.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const check = () => {
|
||||
fetch(videoLink).then((r) => {
|
||||
if (r.ok && r.status === 200) {
|
||||
if (videoRef.current) {
|
||||
videoRef.current.src = '';
|
||||
setTimeout(() => {
|
||||
videoRef.current!.src = videoURL;
|
||||
}, 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
check();
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
};
|
||||
check();
|
||||
videoRef.current.src = videoURL;
|
||||
if (spotPlayerStore.isPlaying) {
|
||||
void videoRef.current.play();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (videoRef.current) {
|
||||
videoRef.current.addEventListener('loadeddata', () => {
|
||||
setLoaded(true);
|
||||
});
|
||||
videoRef.current.src = videoURL;
|
||||
if (spotPlayerStore.isPlaying) {
|
||||
void videoRef.current.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return () => {
|
||||
hlsRef.current?.destroy();
|
||||
};
|
||||
|
|
@ -125,8 +126,8 @@ function SpotVideoContainer({
|
|||
}, 100);
|
||||
if (videoRef.current) {
|
||||
videoRef.current.addEventListener('ended', () => {
|
||||
spotPlayerStore.onComplete()
|
||||
})
|
||||
spotPlayerStore.onComplete();
|
||||
});
|
||||
}
|
||||
return () => clearInterval(int);
|
||||
}, []);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import { convertElementToImage } from 'App/utils';
|
||||
import { jsPDF } from 'jspdf';
|
||||
import { useStore } from 'App/mstore';
|
||||
import { useObserver } from 'mobx-react-lite';
|
||||
import { connect } from 'react-redux';
|
||||
|
|
@ -50,90 +49,92 @@ export default function withReport<P extends Props>(WrappedComponent: React.Comp
|
|||
|
||||
const processReport = () => {
|
||||
document.body.scrollIntoView();
|
||||
const doc = new jsPDF('p', 'mm', 'a4');
|
||||
const now = new Date().toISOString();
|
||||
import('jspdf').then(({ jsPDF }) => {
|
||||
const doc = new jsPDF('p', 'mm', 'a4');
|
||||
const now = new Date().toISOString();
|
||||
|
||||
doc.addMetadata('Author', 'OpenReplay');
|
||||
doc.addMetadata('Title', 'OpenReplay Report');
|
||||
doc.addMetadata('Subject', 'OpenReplay Report');
|
||||
doc.addMetadata('Keywords', 'OpenReplay Report');
|
||||
doc.addMetadata('Creator', 'OpenReplay');
|
||||
doc.addMetadata('Producer', 'OpenReplay');
|
||||
doc.addMetadata('CreationDate', now);
|
||||
doc.addMetadata('Author', 'OpenReplay');
|
||||
doc.addMetadata('Title', 'OpenReplay Report');
|
||||
doc.addMetadata('Subject', 'OpenReplay Report');
|
||||
doc.addMetadata('Keywords', 'OpenReplay Report');
|
||||
doc.addMetadata('Creator', 'OpenReplay');
|
||||
doc.addMetadata('Producer', 'OpenReplay');
|
||||
doc.addMetadata('CreationDate', now);
|
||||
|
||||
const parentElement = document.getElementById('report') as HTMLElement;
|
||||
const pageHeight = 1200;
|
||||
const pagesCount = parentElement.offsetHeight / pageHeight;
|
||||
const pages: Array<any> = [];
|
||||
for (let i = 0; i < pagesCount; i++) {
|
||||
const page = document.createElement('div');
|
||||
page.classList.add('page');
|
||||
page.style.height = `${pageHeight}px`;
|
||||
page.style.whiteSpace = 'no-wrap !important';
|
||||
const parentElement = document.getElementById('report') as HTMLElement;
|
||||
const pageHeight = 1200;
|
||||
const pagesCount = parentElement.offsetHeight / pageHeight;
|
||||
const pages: Array<any> = [];
|
||||
for (let i = 0; i < pagesCount; i++) {
|
||||
const page = document.createElement('div');
|
||||
page.classList.add('page');
|
||||
page.style.height = `${pageHeight}px`;
|
||||
page.style.whiteSpace = 'no-wrap !important';
|
||||
|
||||
const childrens = Array.from(parentElement.children).filter((child) => {
|
||||
const rect = child.getBoundingClientRect();
|
||||
const parentRect = parentElement.getBoundingClientRect();
|
||||
const top = rect.top - parentRect.top;
|
||||
return top >= i * pageHeight && top < (i + 1) * pageHeight;
|
||||
});
|
||||
if (childrens.length > 0) {
|
||||
pages.push(childrens);
|
||||
}
|
||||
}
|
||||
|
||||
const rportLayer = document.getElementById('report-layer');
|
||||
|
||||
pages.forEach(async (page, index) => {
|
||||
const pageDiv = document.createElement('div');
|
||||
pageDiv.classList.add(
|
||||
'grid',
|
||||
'gap-4',
|
||||
'grid-cols-4',
|
||||
'items-start',
|
||||
'pb-10',
|
||||
'auto-rows-min',
|
||||
'printable-report'
|
||||
);
|
||||
pageDiv.id = `page-${index}`;
|
||||
pageDiv.style.backgroundColor = '#f6f6f6';
|
||||
pageDiv.style.gridAutoRows = 'min-content';
|
||||
pageDiv.style.padding = '50px';
|
||||
pageDiv.style.height = '490mm';
|
||||
|
||||
if (index > 0) {
|
||||
pageDiv.style.paddingTop = '100px';
|
||||
}
|
||||
|
||||
if (index === 0) {
|
||||
const header = document.getElementById('report-header')?.cloneNode(true) as HTMLElement;
|
||||
header.classList.add('col-span-4');
|
||||
header.style.display = 'block';
|
||||
pageDiv.appendChild(header);
|
||||
}
|
||||
page.forEach((child: any) => {
|
||||
pageDiv.appendChild(child.cloneNode(true));
|
||||
});
|
||||
rportLayer?.appendChild(pageDiv);
|
||||
});
|
||||
|
||||
setTimeout(async () => {
|
||||
for (let i = 0; i < pages.length; i++) {
|
||||
const pageDiv = document.getElementById(`page-${i}`) as HTMLElement;
|
||||
const pageImage = await convertElementToImage(pageDiv);
|
||||
doc.addImage(pageImage, 'PNG', 0, 0, 210, 0);
|
||||
if (i === pages.length - 1) {
|
||||
addFooters(doc);
|
||||
doc.save(fileNameFormat(dashboard.name + '_Report_' + Date.now(), '.pdf'));
|
||||
rportLayer!.innerHTML = '';
|
||||
setRendering(false);
|
||||
toast.dismiss();
|
||||
toast.success(TEXT_SUCCESS);
|
||||
} else {
|
||||
doc.addPage();
|
||||
const childrens = Array.from(parentElement.children).filter((child) => {
|
||||
const rect = child.getBoundingClientRect();
|
||||
const parentRect = parentElement.getBoundingClientRect();
|
||||
const top = rect.top - parentRect.top;
|
||||
return top >= i * pageHeight && top < (i + 1) * pageHeight;
|
||||
});
|
||||
if (childrens.length > 0) {
|
||||
pages.push(childrens);
|
||||
}
|
||||
}
|
||||
}, 100);
|
||||
|
||||
const rportLayer = document.getElementById('report-layer');
|
||||
|
||||
pages.forEach(async (page, index) => {
|
||||
const pageDiv = document.createElement('div');
|
||||
pageDiv.classList.add(
|
||||
'grid',
|
||||
'gap-4',
|
||||
'grid-cols-4',
|
||||
'items-start',
|
||||
'pb-10',
|
||||
'auto-rows-min',
|
||||
'printable-report'
|
||||
);
|
||||
pageDiv.id = `page-${index}`;
|
||||
pageDiv.style.backgroundColor = '#f6f6f6';
|
||||
pageDiv.style.gridAutoRows = 'min-content';
|
||||
pageDiv.style.padding = '50px';
|
||||
pageDiv.style.height = '490mm';
|
||||
|
||||
if (index > 0) {
|
||||
pageDiv.style.paddingTop = '100px';
|
||||
}
|
||||
|
||||
if (index === 0) {
|
||||
const header = document.getElementById('report-header')?.cloneNode(true) as HTMLElement;
|
||||
header.classList.add('col-span-4');
|
||||
header.style.display = 'block';
|
||||
pageDiv.appendChild(header);
|
||||
}
|
||||
page.forEach((child: any) => {
|
||||
pageDiv.appendChild(child.cloneNode(true));
|
||||
});
|
||||
rportLayer?.appendChild(pageDiv);
|
||||
});
|
||||
|
||||
setTimeout(async () => {
|
||||
for (let i = 0; i < pages.length; i++) {
|
||||
const pageDiv = document.getElementById(`page-${i}`) as HTMLElement;
|
||||
const pageImage = await convertElementToImage(pageDiv);
|
||||
doc.addImage(pageImage, 'PNG', 0, 0, 210, 0);
|
||||
if (i === pages.length - 1) {
|
||||
addFooters(doc);
|
||||
doc.save(fileNameFormat(dashboard.name + '_Report_' + Date.now(), '.pdf'));
|
||||
rportLayer!.innerHTML = '';
|
||||
setRendering(false);
|
||||
toast.dismiss();
|
||||
toast.success(TEXT_SUCCESS);
|
||||
} else {
|
||||
doc.addPage();
|
||||
}
|
||||
}
|
||||
}, 100);
|
||||
})
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
@ -155,9 +156,9 @@ export default function withReport<P extends Props>(WrappedComponent: React.Comp
|
|||
<div className="text-2xl font-semibold">{dashboard && dashboard.name}</div>
|
||||
<div className="font-semibold">
|
||||
{period &&
|
||||
period.range.start.format('MMM Do YY') +
|
||||
period.range.start.toFormat('MMM Do YY') +
|
||||
' - ' +
|
||||
period.range.end.format('MMM Do YY')}
|
||||
period.range.end.toFormat('MMM Do YY')}
|
||||
</div>
|
||||
</div>
|
||||
{dashboard && dashboard.description && (
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import React from 'react';
|
||||
import { CopyButton } from 'UI';
|
||||
import Highlight from 'react-highlight';
|
||||
import { CopyButton, CodeBlock } from 'UI';
|
||||
|
||||
const inputModeOptions = [
|
||||
{ label: 'Record all inputs', value: 'plain' },
|
||||
|
|
@ -53,9 +52,7 @@ function CodeSnippet(props: Props) {
|
|||
<div className="absolute top-0 right-0 mt-2 mr-2">
|
||||
<CopyButton content={codeSnippet} className="uppercase" />
|
||||
</div>
|
||||
<Highlight className="html">
|
||||
{codeSnippet}
|
||||
</Highlight>
|
||||
<CodeBlock code={codeSnippet} language={'js'} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,152 +1,13 @@
|
|||
// @ts-nocheck
|
||||
import { DatePicker } from 'antd';
|
||||
import { PickerTimeProps } from 'antd/es/time-picker';
|
||||
import moment from 'moment';
|
||||
import type { Moment } from 'moment';
|
||||
import React from 'react';
|
||||
import luxonGenerateConfig from 'rc-picker/lib/generate/luxon';
|
||||
|
||||
const generateConfig = {
|
||||
// get
|
||||
getNow: () => moment(),
|
||||
getFixedDate: (string: string) => moment(string, 'YYYY-MM-DD'),
|
||||
getEndDate: (date) => {
|
||||
const clone = date.clone();
|
||||
return clone.endOf('month');
|
||||
},
|
||||
getWeekDay: (date) => {
|
||||
const clone = date.clone().locale('en_US');
|
||||
return clone.weekday() + clone.localeData().firstDayOfWeek();
|
||||
},
|
||||
getYear: (date) => date.year(),
|
||||
getMonth: (date) => date.month(),
|
||||
getDate: (date) => date.date(),
|
||||
getHour: (date) => date.hour(),
|
||||
getMinute: (date) => date.minute(),
|
||||
getSecond: (date) => date.second(),
|
||||
getMillisecond: (date) => date.millisecond(),
|
||||
|
||||
// set
|
||||
addYear: (date, diff) => {
|
||||
const clone = date.clone();
|
||||
return clone.add(diff, 'year');
|
||||
},
|
||||
addMonth: (date, diff) => {
|
||||
const clone = date.clone();
|
||||
return clone.add(diff, 'month');
|
||||
},
|
||||
addDate: (date, diff) => {
|
||||
const clone = date.clone();
|
||||
return clone.add(diff, 'day');
|
||||
},
|
||||
setYear: (date, year) => {
|
||||
const clone = date.clone();
|
||||
return clone.year(year);
|
||||
},
|
||||
setMonth: (date, month) => {
|
||||
const clone = date.clone();
|
||||
return clone.month(month);
|
||||
},
|
||||
setDate: (date, num) => {
|
||||
const clone = date.clone();
|
||||
return clone.date(num);
|
||||
},
|
||||
setHour: (date, hour) => {
|
||||
const clone = date.clone();
|
||||
return clone.hour(hour);
|
||||
},
|
||||
setMinute: (date, minute) => {
|
||||
const clone = date.clone();
|
||||
return clone.minute(minute);
|
||||
},
|
||||
setSecond: (date, second) => {
|
||||
const clone = date.clone();
|
||||
return clone.second(second);
|
||||
},
|
||||
setMillisecond: (date, millisecond) => {
|
||||
const clone = date.clone();
|
||||
return clone.millisecond(millisecond);
|
||||
},
|
||||
|
||||
// Compare
|
||||
isAfter: (date1, date2) => date1.isAfter(date2),
|
||||
isValidate: (date) => date.isValid(),
|
||||
|
||||
locale: {
|
||||
getWeekFirstDay: (locale) => {
|
||||
const date = moment().locale(locale);
|
||||
return date.localeData().firstDayOfWeek();
|
||||
},
|
||||
getWeekFirstDate: (locale, date) => {
|
||||
const clone = date.clone();
|
||||
const result = clone.locale(locale);
|
||||
return result.weekday(0);
|
||||
},
|
||||
getWeek: (locale, date) => {
|
||||
const clone = date.clone();
|
||||
const result = clone.locale(locale);
|
||||
return result.week();
|
||||
},
|
||||
getShortWeekDays: (locale) => {
|
||||
const date = moment().locale(locale);
|
||||
return date.localeData().weekdaysMin();
|
||||
},
|
||||
getShortMonths: (locale) => {
|
||||
const date = moment().locale(locale);
|
||||
return date.localeData().monthsShort();
|
||||
},
|
||||
format: (locale, date, format) => {
|
||||
const clone = date.clone();
|
||||
const result = clone.locale(locale);
|
||||
return result.format(format);
|
||||
},
|
||||
parse: (locale, text, formats) => {
|
||||
const fallbackFormatList: string[] = [];
|
||||
|
||||
for (let i = 0; i < formats.length; i += 1) {
|
||||
let format = formats[i];
|
||||
let formatText = text;
|
||||
|
||||
if (format.includes('wo') || format.includes('Wo')) {
|
||||
format = format.replace(/wo/g, 'w').replace(/Wo/g, 'W');
|
||||
const matchFormat = format.match(/[-YyMmDdHhSsWwGg]+/g);
|
||||
const matchText = formatText.match(/[-\d]+/g);
|
||||
|
||||
if (matchFormat && matchText) {
|
||||
format = matchFormat.join('');
|
||||
formatText = matchText.join('');
|
||||
} else {
|
||||
fallbackFormatList.push(format.replace(/o/g, ''));
|
||||
}
|
||||
}
|
||||
|
||||
const date = moment(formatText, format, locale, true);
|
||||
if (date.isValid()) {
|
||||
return date;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to fuzzy matching, this should always not reach match or need fire a issue
|
||||
for (let i = 0; i < fallbackFormatList.length; i += 1) {
|
||||
const date = moment(text, fallbackFormatList[i], locale, false);
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (date.isValid()) {
|
||||
console.error(
|
||||
'Not match any format strictly and fallback to fuzzy match. Please help to fire a issue about this.'
|
||||
);
|
||||
return date;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const CustomPicker = DatePicker.generatePicker<Moment>(generateConfig);
|
||||
const CustomPicker = DatePicker.generatePicker<DateTime>(luxonGenerateConfig);
|
||||
|
||||
export interface TimePickerProps
|
||||
extends Omit<PickerTimeProps<Moment>, 'picker'> {}
|
||||
extends Omit<PickerTimeProps<DateTime>, 'picker'> {}
|
||||
|
||||
const TimePicker = React.forwardRef<any, TimePickerProps>((props, ref) => (
|
||||
<CustomPicker {...props} picker="time" mode={undefined} ref={ref} />
|
||||
|
|
|
|||
|
|
@ -1,113 +1,115 @@
|
|||
import { Button } from 'antd';
|
||||
import React from 'react';
|
||||
import DateRangePicker from 'react-daterange-picker'
|
||||
import { getDateRangeFromValue, getDateRangeLabel, dateRangeValues, CUSTOM_RANGE, moment, DATE_RANGE_VALUES } from 'App/dateRange';
|
||||
import { Button } from 'antd'
|
||||
import { TimePicker } from 'App/components/shared/DatePicker'
|
||||
import DateRangePicker from '@wojtekmaj/react-daterange-picker';
|
||||
import '@wojtekmaj/react-daterange-picker/dist/DateRangePicker.css';
|
||||
import 'react-calendar/dist/Calendar.css';
|
||||
|
||||
import { TimePicker } from 'App/components/shared/DatePicker';
|
||||
import {
|
||||
CUSTOM_RANGE,
|
||||
DATE_RANGE_VALUES,
|
||||
dateRangeValues,
|
||||
getDateRangeFromValue,
|
||||
getDateRangeLabel,
|
||||
} from 'App/dateRange';
|
||||
import { DateTime, Interval } from 'luxon';
|
||||
|
||||
import styles from './dateRangePopup.module.css';
|
||||
|
||||
export default class DateRangePopup extends React.PureComponent {
|
||||
state = {
|
||||
range: this.props.selectedDateRange || moment.range(),
|
||||
range: this.props.selectedDateRange || Interval.fromDateTimes(DateTime.now(), DateTime.now()),
|
||||
value: null,
|
||||
}
|
||||
};
|
||||
|
||||
selectCustomRange = (range) => {
|
||||
range.end.endOf('day');
|
||||
console.log(range)
|
||||
const updatedRange = Interval.fromDateTimes(DateTime.fromJSDate(range[0]), DateTime.fromJSDate(range[1]));
|
||||
this.setState({
|
||||
range,
|
||||
range: updatedRange,
|
||||
value: CUSTOM_RANGE,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
setRangeTimeStart = value => {
|
||||
if (value.isAfter(this.state.range.end)) {
|
||||
setRangeTimeStart = (value) => {
|
||||
if (value > this.state.range.end) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
range: moment.range(
|
||||
value,
|
||||
this.state.range.end,
|
||||
),
|
||||
range: Interval.fromDateTimes(value, this.state.range.end),
|
||||
value: CUSTOM_RANGE,
|
||||
});
|
||||
}
|
||||
setRangeTimeEnd = value => {
|
||||
if (value && value.isBefore(this.state.range.start)) {
|
||||
};
|
||||
|
||||
setRangeTimeEnd = (value) => {
|
||||
if (value && value < this.state.range.start) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
range: moment.range(
|
||||
this.state.range.start,
|
||||
value,
|
||||
),
|
||||
range: Interval.fromDateTimes(this.state.range.start, value),
|
||||
value: CUSTOM_RANGE,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
selectValue = (value) => {
|
||||
const range = getDateRangeFromValue(value);
|
||||
this.setState({ range, value });
|
||||
}
|
||||
};
|
||||
|
||||
onApply = () => this.props.onApply(this.state.range, this.state.value)
|
||||
onApply = () => this.props.onApply(this.state.range, this.state.value);
|
||||
|
||||
render() {
|
||||
const { onCancel, onApply } = this.props;
|
||||
const { range } = this.state;
|
||||
|
||||
const rangeForDisplay = range.clone();
|
||||
rangeForDisplay.start.startOf('day');
|
||||
rangeForDisplay.end.startOf('day');
|
||||
|
||||
const selectionRange = {
|
||||
startDate: new Date(),
|
||||
endDate: new Date(),
|
||||
key: 'selection',
|
||||
}
|
||||
const rangeForDisplay = [range.start.startOf('day').ts, range.end.startOf('day').ts]
|
||||
|
||||
return (
|
||||
<div className={ styles.wrapper }>
|
||||
<div className={ styles.body }>
|
||||
<div className={ styles.preSelections }>
|
||||
{ dateRangeValues.filter(value => value !== CUSTOM_RANGE && value !== DATE_RANGE_VALUES.LAST_30_MINUTES).map(value => (
|
||||
<div
|
||||
key={ value }
|
||||
onClick={ () => this.selectValue(value) }
|
||||
>
|
||||
{ getDateRangeLabel(value) }
|
||||
</div>
|
||||
))
|
||||
}
|
||||
<div className={styles.wrapper}>
|
||||
<div className={styles.body}>
|
||||
<div className={styles.preSelections}>
|
||||
{dateRangeValues
|
||||
.filter(
|
||||
(value) =>
|
||||
value !== CUSTOM_RANGE &&
|
||||
value !== DATE_RANGE_VALUES.LAST_30_MINUTES
|
||||
)
|
||||
.map((value) => (
|
||||
<div key={value} onClick={() => this.selectValue(value)}>
|
||||
{getDateRangeLabel(value)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<DateRangePicker
|
||||
name="dateRangePicker"
|
||||
onSelect={ this.selectCustomRange }
|
||||
numberOfCalendars={ 2 }
|
||||
// singleDateRange
|
||||
selectionType="range"
|
||||
maximumDate={ new Date() }
|
||||
singleDateRange={true}
|
||||
value={ rangeForDisplay }
|
||||
// onSelect={this.selectCustomRange} -> onChange
|
||||
// numberOfCalendars={2}
|
||||
// selectionType="range"
|
||||
// maximumDate={new Date()}
|
||||
// singleDateRange={true}
|
||||
onChange={this.selectCustomRange}
|
||||
shouldCloseCalendar={() => false}
|
||||
isOpen
|
||||
maxDate={new Date()}
|
||||
value={rangeForDisplay}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center justify-between py-2 px-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<label>From: </label>
|
||||
<span>{range.start.format("DD/MM")} </span>
|
||||
<span>{range.start.toFormat('dd/MM')} </span>
|
||||
<TimePicker
|
||||
format={"HH:mm"}
|
||||
defaultValue={ range.start }
|
||||
format={'HH:mm'}
|
||||
defaultValue={range.start}
|
||||
className="w-24"
|
||||
onChange={this.setRangeTimeStart}
|
||||
needConfirm={false}
|
||||
showNow={false}
|
||||
/>
|
||||
<label>To: </label>
|
||||
<span>{range.end.format("DD/MM")} </span>
|
||||
<span>{range.end.toFormat('dd/MM')} </span>
|
||||
<TimePicker
|
||||
format={"HH:mm"}
|
||||
defaultValue={ range.end }
|
||||
format={'HH:mm'}
|
||||
defaultValue={range.end}
|
||||
onChange={this.setRangeTimeEnd}
|
||||
className="w-24"
|
||||
needConfirm={false}
|
||||
|
|
@ -115,8 +117,15 @@ export default class DateRangePopup extends React.PureComponent {
|
|||
/>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<Button onClick={ onCancel }>{ 'Cancel' }</Button>
|
||||
<Button type="primary" className="ml-2" onClick={ this.onApply } disabled={ !range }>{ 'Apply' }</Button>
|
||||
<Button onClick={onCancel}>{'Cancel'}</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
className="ml-2"
|
||||
onClick={this.onApply}
|
||||
disabled={!range}
|
||||
>
|
||||
{'Apply'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -6,14 +6,13 @@ import cn from 'classnames';
|
|||
import ConsoleRow from '../ConsoleRow';
|
||||
import { PlayerContext } from 'App/components/Session/playerContext';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { List, CellMeasurer, AutoSizer } from 'react-virtualized';
|
||||
import { useStore } from 'App/mstore';
|
||||
import ErrorDetailsModal from 'App/components/Dashboard/components/Errors/ErrorDetailsModal';
|
||||
import { useModal } from 'App/components/Modal';
|
||||
import useAutoscroll, { getLastItemTime } from '../useAutoscroll';
|
||||
import { useRegExListFilterMemo, useTabListFilterMemo } from '../useListFilter';
|
||||
import useCellMeasurerCache from 'App/hooks/useCellMeasurerCache';
|
||||
import { connect } from 'react-redux';
|
||||
import { VList, VListHandle } from "virtua";
|
||||
|
||||
const ALL = 'ALL';
|
||||
const INFO = 'INFO';
|
||||
|
|
@ -82,6 +81,7 @@ function ConsolePanel({
|
|||
sessionStore: { devTools },
|
||||
} = useStore();
|
||||
|
||||
const _list = useRef<VListHandle>(null);
|
||||
const filter = devTools[INDEX_KEY].filter;
|
||||
const activeTab = devTools[INDEX_KEY].activeTab;
|
||||
// Why do we need to keep index in the store? if we could get read of it it would simplify the code
|
||||
|
|
@ -115,10 +115,6 @@ function ConsolePanel({
|
|||
filteredList = useTabListFilterMemo(filteredList, (l) => LEVEL_TAB[l.level], ALL, activeTab);
|
||||
|
||||
React.useEffect(() => {
|
||||
setTimeout(() => {
|
||||
cache.clearAll();
|
||||
_list.current?.recomputeRowHeights();
|
||||
}, 0);
|
||||
}, [activeTab, filter]);
|
||||
const onTabClick = (activeTab: any) => devTools.update(INDEX_KEY, { activeTab });
|
||||
const onFilterChange = ({ target: { value } }: any) =>
|
||||
|
|
@ -139,16 +135,13 @@ function ConsolePanel({
|
|||
timeoutStartAutoscroll();
|
||||
};
|
||||
|
||||
const _list = useRef<List>(null); // TODO: fix react-virtualized types & encapsulate scrollToRow logic
|
||||
useEffect(() => {
|
||||
if (_list.current) {
|
||||
// @ts-ignore
|
||||
_list.current.scrollToRow(activeIndex);
|
||||
_list.current.scrollToIndex(activeIndex);
|
||||
}
|
||||
}, [activeIndex]);
|
||||
|
||||
const cache = useCellMeasurerCache();
|
||||
|
||||
const showDetails = (log: any) => {
|
||||
setIsDetailsModalActive(true);
|
||||
showModal(<ErrorDetailsModal errorId={log.errorId} />, {
|
||||
|
|
@ -162,27 +155,6 @@ function ConsolePanel({
|
|||
devTools.update(INDEX_KEY, { index: filteredList.indexOf(log) });
|
||||
stopAutoscroll();
|
||||
};
|
||||
const _rowRenderer = ({ index, key, parent, style }: any) => {
|
||||
const item = filteredList[index];
|
||||
|
||||
return (
|
||||
// @ts-ignore
|
||||
<CellMeasurer cache={cache} columnIndex={0} key={key} rowIndex={index} parent={parent}>
|
||||
{({ measure, registerChild }) => (
|
||||
<div ref={registerChild} style={style}>
|
||||
<ConsoleRow
|
||||
log={item}
|
||||
jump={jump}
|
||||
iconProps={getIconProps(item.level)}
|
||||
renderWithNL={renderWithNL}
|
||||
onClick={() => showDetails(item)}
|
||||
recalcHeight={measure}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</CellMeasurer>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<BottomBlock style={{ height: '100%' }} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
|
||||
|
|
@ -215,25 +187,17 @@ function ConsolePanel({
|
|||
size="small"
|
||||
show={filteredList.length === 0}
|
||||
>
|
||||
{/* @ts-ignore */}
|
||||
<AutoSizer>
|
||||
{({ height, width }: any) => (
|
||||
// @ts-ignore
|
||||
<List
|
||||
ref={_list}
|
||||
deferredMeasurementCache={cache}
|
||||
overscanRowCount={5}
|
||||
estimatedRowSize={24}
|
||||
rowCount={Math.ceil(filteredList.length || 1)}
|
||||
rowHeight={cache.rowHeight}
|
||||
rowRenderer={_rowRenderer}
|
||||
width={width}
|
||||
height={height}
|
||||
// scrollToIndex={activeIndex}
|
||||
scrollToAlignment="center"
|
||||
<VList ref={_list} itemSize={25}>
|
||||
{filteredList.map((log) => (
|
||||
<ConsoleRow
|
||||
log={log}
|
||||
jump={jump}
|
||||
iconProps={getIconProps(log.level)}
|
||||
renderWithNL={renderWithNL}
|
||||
onClick={() => showDetails(log)}
|
||||
/>
|
||||
)}
|
||||
</AutoSizer>
|
||||
))}
|
||||
</VList>
|
||||
</NoContent>
|
||||
{/* @ts-ignore */}
|
||||
</BottomBlock.Content>
|
||||
|
|
|
|||
|
|
@ -6,13 +6,12 @@ import cn from 'classnames';
|
|||
import ConsoleRow from '../ConsoleRow';
|
||||
import { IOSPlayerContext, MobilePlayerContext } from 'App/components/Session/playerContext';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { List, CellMeasurer, AutoSizer } from 'react-virtualized';
|
||||
import { VList, VListHandle } from 'virtua';
|
||||
import { useStore } from 'App/mstore';
|
||||
import ErrorDetailsModal from 'App/components/Dashboard/components/Errors/ErrorDetailsModal';
|
||||
import { useModal } from 'App/components/Modal';
|
||||
import useAutoscroll, { getLastItemTime } from '../useAutoscroll';
|
||||
import { useRegExListFilterMemo, useTabListFilterMemo } from '../useListFilter';
|
||||
import useCellMeasurerCache from 'App/hooks/useCellMeasurerCache';
|
||||
|
||||
const ALL = 'ALL';
|
||||
const INFO = 'INFO';
|
||||
|
|
@ -87,12 +86,6 @@ function MobileConsolePanel() {
|
|||
let filteredList = useRegExListFilterMemo(list, (l) => l.value, filter);
|
||||
filteredList = useTabListFilterMemo(filteredList, (l) => LEVEL_TAB[l.level], ALL, activeTab);
|
||||
|
||||
React.useEffect(() => {
|
||||
setTimeout(() => {
|
||||
cache.clearAll();
|
||||
_list.current?.recomputeRowHeights();
|
||||
}, 0);
|
||||
}, [activeTab, filter]);
|
||||
const onTabClick = (activeTab: any) => devTools.update(INDEX_KEY, { activeTab });
|
||||
const onFilterChange = ({ target: { value } }: any) =>
|
||||
devTools.update(INDEX_KEY, { filter: value });
|
||||
|
|
@ -112,16 +105,14 @@ function MobileConsolePanel() {
|
|||
timeoutStartAutoscroll();
|
||||
};
|
||||
|
||||
const _list = useRef<List>(null); // TODO: fix react-virtualized types & encapsulate scrollToRow logic
|
||||
const _list = useRef<VListHandle>(null); // TODO: fix react-virtualized types & encapsulate scrollToRow logic
|
||||
useEffect(() => {
|
||||
if (_list.current) {
|
||||
// @ts-ignore
|
||||
_list.current.scrollToRow(activeIndex);
|
||||
_list.current.scrollToIndex(activeIndex);
|
||||
}
|
||||
}, [activeIndex]);
|
||||
|
||||
const cache = useCellMeasurerCache();
|
||||
|
||||
const showDetails = (log: any) => {
|
||||
setIsDetailsModalActive(true);
|
||||
showModal(<ErrorDetailsModal errorId={log.errorId} />, {
|
||||
|
|
@ -135,27 +126,6 @@ function MobileConsolePanel() {
|
|||
devTools.update(INDEX_KEY, { index: filteredList.indexOf(log) });
|
||||
stopAutoscroll();
|
||||
};
|
||||
const _rowRenderer = ({ index, key, parent, style }: any) => {
|
||||
const item = filteredList[index];
|
||||
|
||||
return (
|
||||
// @ts-ignore
|
||||
<CellMeasurer cache={cache} columnIndex={0} key={key} rowIndex={index} parent={parent}>
|
||||
{({ measure, registerChild }) => (
|
||||
<div ref={registerChild} style={style}>
|
||||
<ConsoleRow
|
||||
log={item}
|
||||
jump={jump}
|
||||
iconProps={getIconProps(item.level)}
|
||||
renderWithNL={renderWithNL}
|
||||
onClick={() => showDetails(item)}
|
||||
recalcHeight={measure}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</CellMeasurer>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<BottomBlock
|
||||
|
|
@ -163,7 +133,6 @@ function MobileConsolePanel() {
|
|||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
>
|
||||
{/* @ts-ignore */}
|
||||
<BottomBlock.Header>
|
||||
<div className="flex items-center">
|
||||
<span className="font-semibold color-gray-medium mr-4">Console</span>
|
||||
|
|
@ -178,9 +147,7 @@ function MobileConsolePanel() {
|
|||
onChange={onFilterChange}
|
||||
value={filter}
|
||||
/>
|
||||
{/* @ts-ignore */}
|
||||
</BottomBlock.Header>
|
||||
{/* @ts-ignore */}
|
||||
<BottomBlock.Content className="overflow-y-auto">
|
||||
<NoContent
|
||||
title={
|
||||
|
|
@ -192,27 +159,23 @@ function MobileConsolePanel() {
|
|||
size="small"
|
||||
show={filteredList.length === 0}
|
||||
>
|
||||
{/* @ts-ignore */}
|
||||
<AutoSizer>
|
||||
{({ height, width }: any) => (
|
||||
// @ts-ignore
|
||||
<List
|
||||
ref={_list}
|
||||
deferredMeasurementCache={cache}
|
||||
overscanRowCount={5}
|
||||
estimatedRowSize={36}
|
||||
rowCount={Math.ceil(filteredList.length || 1)}
|
||||
rowHeight={cache.rowHeight}
|
||||
rowRenderer={_rowRenderer}
|
||||
width={width}
|
||||
height={height}
|
||||
// scrollToIndex={activeIndex}
|
||||
scrollToAlignment="center"
|
||||
<VList
|
||||
ref={_list}
|
||||
itemSize={25}
|
||||
count={filteredList.length || 1}
|
||||
>
|
||||
{filteredList.map((log, index) => (
|
||||
<ConsoleRow
|
||||
key={log.time + index}
|
||||
log={log}
|
||||
jump={jump}
|
||||
iconProps={getIconProps(log.level)}
|
||||
renderWithNL={renderWithNL}
|
||||
onClick={() => showDetails(log)}
|
||||
/>
|
||||
)}
|
||||
</AutoSizer>
|
||||
))}
|
||||
</VList>
|
||||
</NoContent>
|
||||
{/* @ts-ignore */}
|
||||
</BottomBlock.Content>
|
||||
</BottomBlock>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useState } from 'react';
|
||||
import cn from 'classnames';
|
||||
import { Icon, TextEllipsis } from 'UI';
|
||||
import { Icon } from 'UI';
|
||||
import JumpButton from 'Shared/DevTools/JumpButton';
|
||||
|
||||
interface Props {
|
||||
|
|
@ -9,23 +9,15 @@ interface Props {
|
|||
jump?: any;
|
||||
renderWithNL?: any;
|
||||
style?: any;
|
||||
recalcHeight?: () => void;
|
||||
onClick?: () => void;
|
||||
}
|
||||
function ConsoleRow(props: Props) {
|
||||
const { log, iconProps, jump, renderWithNL, style, recalcHeight } = props;
|
||||
const { log, iconProps, jump, renderWithNL, style } = props;
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const lines = log.value?.split('\n').filter((l: any) => !!l) || [];
|
||||
const canExpand = lines.length > 1;
|
||||
const clickable = canExpand || !!log.errorId;
|
||||
|
||||
React.useEffect(() => {
|
||||
recalcHeight?.();
|
||||
}, [expanded])
|
||||
React.useEffect(() => {
|
||||
recalcHeight?.();
|
||||
}, [])
|
||||
|
||||
const toggleExpand = () => {
|
||||
setExpanded(!expanded);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import { Timed } from 'Player';
|
|||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { Tabs, Input, NoContent, Icon } from 'UI';
|
||||
import { List, CellMeasurer, AutoSizer } from 'react-virtualized';
|
||||
import { PlayerContext, MobilePlayerContext } from 'App/components/Session/playerContext';
|
||||
import BottomBlock from '../BottomBlock';
|
||||
import { useModal } from 'App/components/Modal';
|
||||
|
|
@ -13,8 +12,8 @@ import StackEventRow from 'Shared/DevTools/StackEventRow';
|
|||
import StackEventModal from '../StackEventModal';
|
||||
import useAutoscroll, { getLastItemTime } from '../useAutoscroll';
|
||||
import { useRegExListFilterMemo, useTabListFilterMemo } from '../useListFilter';
|
||||
import useCellMeasurerCache from 'App/hooks/useCellMeasurerCache';
|
||||
import { connect } from 'react-redux';
|
||||
import { VList, VListHandle } from 'virtua';
|
||||
|
||||
const mapNames = (type: string) => {
|
||||
if (type === 'openreplay') return 'OpenReplay';
|
||||
|
|
@ -153,8 +152,6 @@ function EventsPanel({
|
|||
timeoutStartAutoscroll();
|
||||
};
|
||||
|
||||
const cache = useCellMeasurerCache();
|
||||
|
||||
const showDetails = (item: any) => {
|
||||
setIsDetailsModalActive(true);
|
||||
showModal(<StackEventModal event={item} />, {
|
||||
|
|
@ -169,38 +166,13 @@ function EventsPanel({
|
|||
stopAutoscroll();
|
||||
};
|
||||
|
||||
const _list = React.useRef();
|
||||
const _list = React.useRef<VListHandle>(null);
|
||||
useEffect(() => {
|
||||
if (_list.current) {
|
||||
// @ts-ignore
|
||||
_list.current.scrollToRow(activeIndex);
|
||||
_list.current.scrollToIndex(activeIndex);
|
||||
}
|
||||
}, [activeIndex]);
|
||||
|
||||
const _rowRenderer = ({ index, key, parent, style }: any) => {
|
||||
const item = filteredList[index];
|
||||
|
||||
return (
|
||||
// @ts-ignore
|
||||
<CellMeasurer cache={cache} columnIndex={0} key={key} rowIndex={index} parent={parent}>
|
||||
{() => (
|
||||
<StackEventRow
|
||||
isActive={activeIndex === index}
|
||||
style={style}
|
||||
key={item.key}
|
||||
event={item}
|
||||
onJump={() => {
|
||||
stopAutoscroll();
|
||||
devTools.update(INDEX_KEY, { index: filteredList.indexOf(item) });
|
||||
jump(item.time);
|
||||
}}
|
||||
onClick={() => showDetails(item)}
|
||||
/>
|
||||
)}
|
||||
</CellMeasurer>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<BottomBlock style={{ height: '100%' }} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
|
||||
<BottomBlock.Header>
|
||||
|
|
@ -235,21 +207,24 @@ function EventsPanel({
|
|||
size="small"
|
||||
show={filteredList.length === 0}
|
||||
>
|
||||
<AutoSizer>
|
||||
{({ height, width }: any) => (
|
||||
<List
|
||||
ref={_list}
|
||||
deferredMeasurementCache={cache}
|
||||
overscanRowCount={5}
|
||||
rowCount={Math.ceil(filteredList.length || 1)}
|
||||
rowHeight={cache.rowHeight}
|
||||
rowRenderer={_rowRenderer}
|
||||
width={width}
|
||||
height={height}
|
||||
scrollToAlignment="center"
|
||||
<VList
|
||||
ref={_list}
|
||||
count={filteredList.length || 1}
|
||||
>
|
||||
{filteredList.map((item, index) => (
|
||||
<StackEventRow
|
||||
isActive={activeIndex === index}
|
||||
key={item.key}
|
||||
event={item}
|
||||
onJump={() => {
|
||||
stopAutoscroll();
|
||||
devTools.update(INDEX_KEY, { index: filteredList.indexOf(item) });
|
||||
jump(item.time);
|
||||
}}
|
||||
onClick={() => showDetails(item)}
|
||||
/>
|
||||
)}
|
||||
</AutoSizer>
|
||||
))}
|
||||
</VList>
|
||||
</NoContent>
|
||||
</BottomBlock.Content>
|
||||
</BottomBlock>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { List, AutoSizer } from 'react-virtualized';
|
||||
import { VList, VListHandle } from 'virtua';
|
||||
import cn from 'classnames';
|
||||
import { Duration } from 'luxon';
|
||||
import { NoContent, Button } from 'UI';
|
||||
|
|
@ -140,7 +140,7 @@ export default class TimeTable extends React.PureComponent<Props, State> {
|
|||
return Math.ceil(this.tableHeight / ROW_HEIGHT);
|
||||
}
|
||||
|
||||
scroller = React.createRef<List>();
|
||||
scroller = React.createRef<VListHandle>();
|
||||
autoScroll = true;
|
||||
|
||||
adjustScroll(prevActiveIndex: number) {
|
||||
|
|
@ -150,7 +150,7 @@ export default class TimeTable extends React.PureComponent<Props, State> {
|
|||
prevActiveIndex !== this.props.activeIndex &&
|
||||
this.scroller.current
|
||||
) {
|
||||
this.scroller.current.scrollToRow(this.props.activeIndex);
|
||||
this.scroller.current.scrollToIndex(this.props.activeIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -191,15 +191,13 @@ export default class TimeTable extends React.PureComponent<Props, State> {
|
|||
}
|
||||
};
|
||||
|
||||
renderRow = ({ index, key, style: rowStyle }: any) => {
|
||||
renderRow = (index: number) => {
|
||||
const { activeIndex } = this.props;
|
||||
const { children: columns, rows, renderPopup, hoverable, onRowClick } = this.props;
|
||||
const { timestart, timewidth } = this.state;
|
||||
const row = rows[index];
|
||||
return (
|
||||
<div
|
||||
style={rowStyle}
|
||||
key={key}
|
||||
className={cn(
|
||||
'dev-row border-b border-color-gray-light-shade group items-center',
|
||||
stl.row,
|
||||
|
|
@ -240,7 +238,7 @@ export default class TimeTable extends React.PureComponent<Props, State> {
|
|||
}
|
||||
}
|
||||
if (this.scroller.current != null) {
|
||||
this.scroller.current.scrollToRow(prevRedIndex);
|
||||
this.scroller.current.scrollToIndex(prevRedIndex);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -253,15 +251,13 @@ export default class TimeTable extends React.PureComponent<Props, State> {
|
|||
}
|
||||
}
|
||||
if (this.scroller.current != null) {
|
||||
this.scroller.current.scrollToRow(prevRedIndex);
|
||||
this.scroller.current.scrollToIndex(prevRedIndex);
|
||||
}
|
||||
};
|
||||
|
||||
onColumnClick = (dataKey: string, onClick: any) => {
|
||||
if (typeof onClick === 'function') {
|
||||
// this.scroller.current.scrollToRow(0);
|
||||
onClick(dataKey);
|
||||
this.scroller.current.forceUpdateGrid();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -359,24 +355,9 @@ export default class TimeTable extends React.PureComponent<Props, State> {
|
|||
/>
|
||||
))}
|
||||
</div>
|
||||
<AutoSizer disableHeight>
|
||||
{({ width }: { width: number }) => (
|
||||
<List
|
||||
scrollToIndex={this.props.activeIndex || 0}
|
||||
ref={this.scroller}
|
||||
className={stl.list}
|
||||
height={this.tableHeight + additionalHeight}
|
||||
width={width}
|
||||
overscanRowCount={20}
|
||||
rowCount={rows.length}
|
||||
rowHeight={ROW_HEIGHT}
|
||||
rowRenderer={this.renderRow}
|
||||
onScroll={this.onScroll}
|
||||
scrollToAlignment="center"
|
||||
forceUpdateProp={timestart | timewidth | (activeIndex || 0)}
|
||||
/>
|
||||
)}
|
||||
</AutoSizer>
|
||||
<VList className={stl.list} ref={this.scroller} itemSize={ROW_HEIGHT} count={rows.length}>
|
||||
{this.props.rows.map((_, index) => this.renderRow(index))}
|
||||
</VList>
|
||||
</div>
|
||||
</NoContent>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ function ErrorsBadge({ errorsStats = {}, fetchNewErrorsCount, projects }) {
|
|||
useEffect(() => {
|
||||
if (projects.size === 0 || !!intervalId) return;
|
||||
|
||||
const params = { startTimestamp: weekRange.start.unix() * 1000, endTimestamp: weekRange.end.unix() * 1000 };
|
||||
const params = { startTimestamp: weekRange.start.ts, endTimestamp: weekRange.end.ts };
|
||||
fetchNewErrorsCount(params)
|
||||
|
||||
intervalId = setInterval(() => {
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
import React from 'react';
|
||||
import { DownOutlined } from '@ant-design/icons';
|
||||
import Period from 'Types/app/period';
|
||||
import { Dropdown, Button, Menu, Space, MenuProps } from 'antd';
|
||||
import { Dropdown, Button } from 'antd';
|
||||
import cn from 'classnames';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import React from 'react';
|
||||
import { components } from 'react-select';
|
||||
|
||||
import { CUSTOM_RANGE, DATE_RANGE_OPTIONS } from 'App/dateRange';
|
||||
|
||||
import DateRangePopup from 'Shared/DateRangeDropdown/DateRangePopup';
|
||||
import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv';
|
||||
import Select from 'Shared/Select';
|
||||
|
||||
interface Props {
|
||||
period: any;
|
||||
|
|
@ -23,7 +25,7 @@ interface Props {
|
|||
[x: string]: any;
|
||||
}
|
||||
|
||||
const SelectDateRange: React.FC<Props> = (props: Props) => {
|
||||
function SelectDateRange(props: Props) {
|
||||
const [isCustom, setIsCustom] = React.useState(false);
|
||||
const { right = false, period, disableCustom = false, timezone, useButtonStyle = false } = props;
|
||||
let selectedValue = DATE_RANGE_OPTIONS.find(
|
||||
|
|
@ -33,21 +35,21 @@ const SelectDateRange: React.FC<Props> = (props: Props) => {
|
|||
disableCustom ? obj.value !== CUSTOM_RANGE : true
|
||||
);
|
||||
|
||||
const onChange = (e: any) => {
|
||||
if (e.key === CUSTOM_RANGE) {
|
||||
const onChange = (value: any) => {
|
||||
if (value === CUSTOM_RANGE) {
|
||||
setTimeout(() => {
|
||||
setIsCustom(true);
|
||||
}, 1);
|
||||
} else {
|
||||
props.onChange(Period({ rangeName: e.key }));
|
||||
props.onChange(new Period({ rangeName: value }));
|
||||
}
|
||||
};
|
||||
|
||||
const onApplyDateRange = (value: any) => {
|
||||
const range = Period({
|
||||
const range = new Period({
|
||||
rangeName: CUSTOM_RANGE,
|
||||
start: value.start,
|
||||
end: value.end
|
||||
end: value.end,
|
||||
});
|
||||
props.onChange(range);
|
||||
setIsCustom(false);
|
||||
|
|
@ -56,27 +58,91 @@ const SelectDateRange: React.FC<Props> = (props: Props) => {
|
|||
const isCustomRange = period.rangeName === CUSTOM_RANGE;
|
||||
const customRange = isCustomRange ? period.rangeFormatted() : '';
|
||||
|
||||
const menuItems: MenuProps['items'] = options.map((opt) => ({
|
||||
key: opt.value,
|
||||
label: opt.label,
|
||||
className: opt.value === selectedValue?.value ? 'ant-select-item-option-selected' : '',
|
||||
}));
|
||||
if (props.isAnt) {
|
||||
const menuProps = {
|
||||
items: options.map((opt) => ({
|
||||
label: opt.label,
|
||||
key: opt.value,
|
||||
})),
|
||||
defaultSelectedKeys: selectedValue?.value ? [selectedValue.value] : undefined,
|
||||
onClick: (e: any) => {
|
||||
onChange(e.key);
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={'relative'}>
|
||||
<Dropdown menu={menuProps} >
|
||||
{useButtonStyle ? (
|
||||
<Button type='text'>
|
||||
<span>{isCustomRange ? customRange : selectedValue?.label}</span>
|
||||
<DownOutlined />
|
||||
</Button>
|
||||
) : (
|
||||
<div className={'cursor-pointer flex items-center gap-2'}>
|
||||
<span>{isCustomRange ? customRange : selectedValue?.label}</span>
|
||||
<DownOutlined />
|
||||
</div>
|
||||
)}
|
||||
</Dropdown>
|
||||
{isCustom && (
|
||||
<OutsideClickDetectingDiv
|
||||
onClickOutside={(e: any) => {
|
||||
if (
|
||||
e.target.parentElement.parentElement.classList.contains(
|
||||
'rc-time-picker-panel-select'
|
||||
) ||
|
||||
e.target.parentElement.parentElement.classList[0]?.includes(
|
||||
'-menu'
|
||||
) ||
|
||||
e.target.className.includes('ant-picker')
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
setIsCustom(false);
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={cn('absolute top-0 mt-10 z-40', { 'right-0': right })}
|
||||
style={{
|
||||
width: '520px',
|
||||
fontSize: '14px',
|
||||
textAlign: 'left',
|
||||
}}
|
||||
>
|
||||
<DateRangePopup
|
||||
timezone={timezone}
|
||||
onApply={onApplyDateRange}
|
||||
onCancel={() => setIsCustom(false)}
|
||||
selectedDateRange={period.range}
|
||||
/>
|
||||
</div>
|
||||
</OutsideClickDetectingDiv>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={'relative'}>
|
||||
<Dropdown menu={{ items: menuItems, onClick: onChange, selectedKeys: [selectedValue?.value!] }} trigger={['click']}>
|
||||
{useButtonStyle ? (
|
||||
<Button type="text">
|
||||
<span>{isCustomRange ? customRange : selectedValue?.label}</span>
|
||||
<DownOutlined />
|
||||
</Button>
|
||||
) : (
|
||||
<div className={'cursor-pointer flex items-center gap-2'}>
|
||||
<span>{isCustomRange ? customRange : selectedValue?.label}</span>
|
||||
<DownOutlined />
|
||||
</div>
|
||||
)}
|
||||
</Dropdown>
|
||||
<div className="relative">
|
||||
<Select
|
||||
plain
|
||||
value={selectedValue}
|
||||
options={options}
|
||||
onChange={({ value }: any) => onChange(value.value)}
|
||||
components={{
|
||||
SingleValue: ({ children, ...props }: any) => {
|
||||
return (
|
||||
<components.SingleValue {...props}>
|
||||
{isCustomRange ? customRange : children}
|
||||
</components.SingleValue>
|
||||
);
|
||||
},
|
||||
}}
|
||||
period={period}
|
||||
right={true}
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
{isCustom && (
|
||||
<OutsideClickDetectingDiv
|
||||
onClickOutside={(e: any) => {
|
||||
|
|
@ -86,8 +152,7 @@ const SelectDateRange: React.FC<Props> = (props: Props) => {
|
|||
) ||
|
||||
e.target.parentElement.parentElement.classList[0]?.includes(
|
||||
'-menu'
|
||||
) ||
|
||||
e.target.className.includes('ant-picker')
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -97,7 +162,7 @@ const SelectDateRange: React.FC<Props> = (props: Props) => {
|
|||
<div
|
||||
className={cn('absolute top-0 mt-10 z-40', { 'right-0': right })}
|
||||
style={{
|
||||
width: '770px',
|
||||
width: '520px',
|
||||
fontSize: '14px',
|
||||
textAlign: 'left'
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import React from 'react'
|
||||
import stl from './installDocs.module.css'
|
||||
import cn from 'classnames'
|
||||
import { CopyButton } from 'UI';
|
||||
import Highlight from 'react-highlight'
|
||||
import { CopyButton, CodeBlock } from 'UI';
|
||||
|
||||
const installationCommand = 'npm i @openreplay/tracker'
|
||||
const usageCode = `import Tracker from '@openreplay/tracker';
|
||||
|
|
@ -40,9 +39,7 @@ function InstallDocs({ site }) {
|
|||
{/* <CopyButton content={installationCommand} className={cn(stl.codeCopy, 'mt-2 mr-2')} /> */}
|
||||
<div className={ cn(stl.snippetWrapper, '') }>
|
||||
<CopyButton content={installationCommand} className={cn(stl.codeCopy, 'mt-2 mr-2')} />
|
||||
<Highlight className="cli">
|
||||
{installationCommand}
|
||||
</Highlight>
|
||||
<CodeBlock code={installationCommand} language={'bash'} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -51,9 +48,7 @@ function InstallDocs({ site }) {
|
|||
<div className={ '' }>
|
||||
<div className={ cn(stl.snippetWrapper, '') }>
|
||||
<CopyButton content={_usageCode} className={cn(stl.codeCopy, 'mt-2 mr-2')} />
|
||||
<Highlight className="cli">
|
||||
{_usageCode}
|
||||
</Highlight>
|
||||
<CodeBlock code={_usageCode} language={'js'} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import React from 'react'
|
||||
import cn from 'classnames'
|
||||
import { Segmented } from 'antd';
|
||||
import { CopyButton } from 'UI';
|
||||
import Highlight from 'react-highlight'
|
||||
import { CopyButton, CodeBlock } from 'UI';
|
||||
import stl from './InstallDocs/installDocs.module.css'
|
||||
import { usageCode as iosUsageCode, installationCommand as iosInstallCommand } from "../../Onboarding/components/OnboardingTabs/InstallDocs/MobileInstallDocs";
|
||||
import { usageCode as androidUsageCode, installationCommand as androidInstallCommand } from "../../Onboarding/components/OnboardingTabs/InstallDocs/AndroidInstallDocs";
|
||||
|
|
@ -32,9 +31,7 @@ function InstallMobileDocs({ site, ingestPoint }: any) {
|
|||
<div className={ '' }>
|
||||
<div className={ cn(stl.snippetWrapper, '') }>
|
||||
<CopyButton content={installationCommand} className={cn(stl.codeCopy, 'mt-2 mr-2')} />
|
||||
<Highlight className="cli">
|
||||
{installationCommand}
|
||||
</Highlight>
|
||||
<CodeBlock code={installationCommand} language={'bash'} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -43,9 +40,7 @@ function InstallMobileDocs({ site, ingestPoint }: any) {
|
|||
<div className={ '' }>
|
||||
<div className={ cn(stl.snippetWrapper, '') }>
|
||||
<CopyButton content={_usageCode} className={cn(stl.codeCopy, 'mt-2 mr-2')} />
|
||||
<Highlight className="cli">
|
||||
{_usageCode}
|
||||
</Highlight>
|
||||
<CodeBlock code={_usageCode} language={isIos ? 'swift' : 'kt'} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
20
frontend/app/components/ui/CodeBlock/CodeBlock.tsx
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import React, { useEffect } from "react";
|
||||
import Prism from "prismjs";
|
||||
|
||||
interface IProps {
|
||||
code: string;
|
||||
language: string;
|
||||
}
|
||||
|
||||
const CodeBlock = ({ code, language }: IProps) => {
|
||||
useEffect(() => {
|
||||
Prism.highlightAll(false);
|
||||
}, []);
|
||||
return (
|
||||
<pre>
|
||||
<code children={code} className={`language-${language}`} />
|
||||
</pre>
|
||||
);
|
||||
};
|
||||
|
||||
export default CodeBlock;
|
||||
1
frontend/app/components/ui/CodeBlock/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { default } from './CodeBlock';
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
import React from 'react'
|
||||
import Highlight from 'react-highlight'
|
||||
import stl from './highlightCode.module.css'
|
||||
import { CopyButton } from 'UI'
|
||||
import { CopyButton, CodeBlock } from 'UI'
|
||||
|
||||
function HighlightCode({ className = 'js', text = ''}) {
|
||||
return (
|
||||
|
|
@ -9,9 +8,7 @@ function HighlightCode({ className = 'js', text = ''}) {
|
|||
<div className="absolute mt-1 mr-2 right-0">
|
||||
<CopyButton content={text} />
|
||||
</div>
|
||||
<Highlight className={className}>
|
||||
{text}
|
||||
</Highlight>
|
||||
<CodeBlock code={text} language={className} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
19
frontend/app/components/ui/Icons/fetch_request.tsx
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
|
||||
/* Auto-generated, do not edit */
|
||||
import React from 'react';
|
||||
|
||||
interface Props {
|
||||
size?: number | string;
|
||||
width?: number | string;
|
||||
height?: number | string;
|
||||
fill?: string;
|
||||
}
|
||||
|
||||
function Fetch_request(props: Props) {
|
||||
const { size = 14, width = size, height = size, fill = '' } = props;
|
||||
return (
|
||||
<svg fill="none" viewBox="0 0.6 24 24" width={ `${ width }px` } height={ `${ height }px` } ><rect y=".6" width="24" height="24" rx="12" fill="#EBF4F5"/><path d="m16.5 14.6-2 2-2-2M14.5 16.6v-8M7.5 10.6l2-2 2 2M9.5 8.6v8" stroke="#24959A" strokeLinecap="round" strokeLinejoin="round"/></svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default Fetch_request;
|
||||
|
|
@ -1,12 +1,8 @@
|
|||
|
||||
/* Auto-generated, do not edit */
|
||||
export { default as Activity } from './activity';
|
||||
export { default as Alarm_clock } from './alarm_clock';
|
||||
export { default as Alarm_plus } from './alarm_plus';
|
||||
export { default as All_sessions } from './all_sessions';
|
||||
export { default as Analytics } from './analytics';
|
||||
export { default as Anchor } from './anchor';
|
||||
export { default as Arrow_alt_square_right } from './arrow_alt_square_right';
|
||||
export { default as Arrow_bar_left } from './arrow_bar_left';
|
||||
export { default as Arrow_clockwise } from './arrow_clockwise';
|
||||
export { default as Arrow_counterclockwise } from './arrow_counterclockwise';
|
||||
|
|
@ -15,11 +11,8 @@ export { default as Arrow_down_up } from './arrow_down_up';
|
|||
export { default as Arrow_down } from './arrow_down';
|
||||
export { default as Arrow_repeat } from './arrow_repeat';
|
||||
export { default as Arrow_right_short } from './arrow_right_short';
|
||||
export { default as Arrow_square_left } from './arrow_square_left';
|
||||
export { default as Arrow_square_right } from './arrow_square_right';
|
||||
export { default as Arrow_up_short } from './arrow_up_short';
|
||||
export { default as Arrow_up } from './arrow_up';
|
||||
export { default as Arrows_angle_extend } from './arrows_angle_extend';
|
||||
export { default as Avatar_icn_avatar1 } from './avatar_icn_avatar1';
|
||||
export { default as Avatar_icn_avatar10 } from './avatar_icn_avatar10';
|
||||
export { default as Avatar_icn_avatar11 } from './avatar_icn_avatar11';
|
||||
|
|
@ -48,12 +41,10 @@ export { default as Bar_chart_line } from './bar_chart_line';
|
|||
export { default as Bar_pencil } from './bar_pencil';
|
||||
export { default as Battery_charging } from './battery_charging';
|
||||
export { default as Battery } from './battery';
|
||||
export { default as Bell_fill } from './bell_fill';
|
||||
export { default as Bell_plus } from './bell_plus';
|
||||
export { default as Bell_slash } from './bell_slash';
|
||||
export { default as Bell } from './bell';
|
||||
export { default as Binoculars } from './binoculars';
|
||||
export { default as Book_doc } from './book_doc';
|
||||
export { default as Book } from './book';
|
||||
export { default as Bookmark } from './bookmark';
|
||||
export { default as Broadcast } from './broadcast';
|
||||
|
|
@ -68,32 +59,19 @@ export { default as Browser_opera } from './browser_opera';
|
|||
export { default as Browser_safari } from './browser_safari';
|
||||
export { default as Buildings } from './buildings';
|
||||
export { default as Bullhorn } from './bullhorn';
|
||||
export { default as Business_time } from './business_time';
|
||||
export { default as Calendar_alt } from './calendar_alt';
|
||||
export { default as Calendar_check } from './calendar_check';
|
||||
export { default as Calendar_day } from './calendar_day';
|
||||
export { default as Calendar } from './calendar';
|
||||
export { default as Call } from './call';
|
||||
export { default as Camera_alt } from './camera_alt';
|
||||
export { default as Camera_video_off } from './camera_video_off';
|
||||
export { default as Camera_video } from './camera_video';
|
||||
export { default as Camera } from './camera';
|
||||
export { default as Card_checklist } from './card_checklist';
|
||||
export { default as Card_list } from './card_list';
|
||||
export { default as Card_text } from './card_text';
|
||||
export { default as Caret_down_fill } from './caret_down_fill';
|
||||
export { default as Caret_left_fill } from './caret_left_fill';
|
||||
export { default as Caret_right_fill } from './caret_right_fill';
|
||||
export { default as Caret_up_fill } from './caret_up_fill';
|
||||
export { default as Chat_dots } from './chat_dots';
|
||||
export { default as Chat_left_text } from './chat_left_text';
|
||||
export { default as Chat_right_text } from './chat_right_text';
|
||||
export { default as Chat_square_quote } from './chat_square_quote';
|
||||
export { default as Check_circle_fill } from './check_circle_fill';
|
||||
export { default as Check_circle } from './check_circle';
|
||||
export { default as Check } from './check';
|
||||
export { default as Chevron_double_left } from './chevron_double_left';
|
||||
export { default as Chevron_double_right } from './chevron_double_right';
|
||||
export { default as Chevron_down } from './chevron_down';
|
||||
export { default as Chevron_left } from './chevron_left';
|
||||
export { default as Chevron_right } from './chevron_right';
|
||||
|
|
@ -103,44 +81,24 @@ export { default as Circle } from './circle';
|
|||
export { default as Click_hesitation } from './click_hesitation';
|
||||
export { default as Click_rage } from './click_rage';
|
||||
export { default as Clipboard_check } from './clipboard_check';
|
||||
export { default as Clipboard_list_check } from './clipboard_list_check';
|
||||
export { default as Clock_history } from './clock_history';
|
||||
export { default as Clock } from './clock';
|
||||
export { default as Close } from './close';
|
||||
export { default as Cloud_fog2_fill } from './cloud_fog2_fill';
|
||||
export { default as Code } from './code';
|
||||
export { default as Cog } from './cog';
|
||||
export { default as Cogs } from './cogs';
|
||||
export { default as Collection_play } from './collection_play';
|
||||
export { default as Collection } from './collection';
|
||||
export { default as Color_apple } from './color_apple';
|
||||
export { default as Color_browser_tor } from './color_browser_Tor';
|
||||
export { default as Color_browser_applebot } from './color_browser_applebot';
|
||||
export { default as Color_browser_chrome } from './color_browser_chrome';
|
||||
export { default as Color_browser_chrome_mobile } from './color_browser_chrome_mobile';
|
||||
export { default as Color_browser_chrome_mobile_ios } from './color_browser_chrome_mobile_ios';
|
||||
export { default as Color_browser_duck_duck_go } from './color_browser_duck_duck_go';
|
||||
export { default as Color_browser_duckduckgo_mobile } from './color_browser_duckduckgo_mobile';
|
||||
export { default as Color_browser_edge } from './color_browser_edge';
|
||||
export { default as Color_browser_edge_mobile } from './color_browser_edge_mobile';
|
||||
export { default as Color_browser_facebook } from './color_browser_facebook';
|
||||
export { default as Color_browser_firefox } from './color_browser_firefox';
|
||||
export { default as Color_browser_firefox_ios } from './color_browser_firefox_ios';
|
||||
export { default as Color_browser_firefox_mobile } from './color_browser_firefox_mobile';
|
||||
export { default as Color_browser_google } from './color_browser_google';
|
||||
export { default as Color_browser_googlebot } from './color_browser_googlebot';
|
||||
export { default as Color_browser_huawei_browser } from './color_browser_huawei_browser';
|
||||
export { default as Color_browser_internet_explorer } from './color_browser_internet_explorer';
|
||||
export { default as Color_browser_miui_browser } from './color_browser_miui_browser';
|
||||
export { default as Color_browser_mobile_safari } from './color_browser_mobile_safari';
|
||||
export { default as Color_browser_mobile_safari_ui } from './color_browser_mobile_safari_ui';
|
||||
export { default as Color_browser_opera } from './color_browser_opera';
|
||||
export { default as Color_browser_safari } from './color_browser_safari';
|
||||
export { default as Color_browser_samsung_internet } from './color_browser_samsung_internet';
|
||||
export { default as Color_browser_uc_browser } from './color_browser_uc_browser';
|
||||
export { default as Color_browser_unknown } from './color_browser_unknown';
|
||||
export { default as Color_browser_whale } from './color_browser_whale';
|
||||
export { default as Color_browser_yandex_browser } from './color_browser_yandex_browser';
|
||||
export { default as Color_chrome } from './color_chrome';
|
||||
export { default as Color_country_de } from './color_country_de';
|
||||
export { default as Color_country_fr } from './color_country_fr';
|
||||
|
|
@ -150,7 +108,6 @@ export { default as Color_country_us } from './color_country_us';
|
|||
export { default as Color_de } from './color_de';
|
||||
export { default as Color_device_desktop } from './color_device_desktop';
|
||||
export { default as Color_device_mobile } from './color_device_mobile';
|
||||
export { default as Color_device_other_phone } from './color_device_other_phone';
|
||||
export { default as Color_device_tablet } from './color_device_tablet';
|
||||
export { default as Color_device_unkown } from './color_device_unkown';
|
||||
export { default as Color_edge } from './color_edge';
|
||||
|
|
@ -176,15 +133,10 @@ export { default as Color_microsoft } from './color_microsoft';
|
|||
export { default as Color_opera } from './color_opera';
|
||||
export { default as Color_os_android } from './color_os_android';
|
||||
export { default as Color_os_apple } from './color_os_apple';
|
||||
export { default as Color_os_blackberry } from './color_os_blackberry';
|
||||
export { default as Color_os_chrome_os } from './color_os_chrome_os';
|
||||
export { default as Color_os_elementary } from './color_os_elementary';
|
||||
export { default as Color_os_fedora } from './color_os_fedora';
|
||||
export { default as Color_os_freebsd } from './color_os_freebsd';
|
||||
export { default as Color_os_gnome } from './color_os_gnome';
|
||||
export { default as Color_os_ios } from './color_os_ios';
|
||||
export { default as Color_os_linux } from './color_os_linux';
|
||||
export { default as Color_os_linux_mint } from './color_os_linux_mint';
|
||||
export { default as Color_os_macos } from './color_os_macos';
|
||||
export { default as Color_os_microsoft } from './color_os_microsoft';
|
||||
export { default as Color_os_ubuntu } from './color_os_ubuntu';
|
||||
|
|
@ -192,7 +144,6 @@ export { default as Color_os_unkown } from './color_os_unkown';
|
|||
export { default as Color_safari } from './color_safari';
|
||||
export { default as Color_ubuntu } from './color_ubuntu';
|
||||
export { default as Color_us } from './color_us';
|
||||
export { default as Columns_gap_filled } from './columns_gap_filled';
|
||||
export { default as Columns_gap } from './columns_gap';
|
||||
export { default as Console_error } from './console_error';
|
||||
export { default as Console_exception } from './console_exception';
|
||||
|
|
@ -203,7 +154,6 @@ export { default as Controller } from './controller';
|
|||
export { default as Cookies } from './cookies';
|
||||
export { default as Copy } from './copy';
|
||||
export { default as Credit_card_2_back } from './credit_card_2_back';
|
||||
export { default as Credit_card_front } from './credit_card_front';
|
||||
export { default as Cross } from './cross';
|
||||
export { default as Cubes } from './cubes';
|
||||
export { default as Cursor_trash } from './cursor_trash';
|
||||
|
|
@ -225,10 +175,8 @@ export { default as Db_icons_icn_card_webvitals } from './db_icons_icn_card_webV
|
|||
export { default as Desktop } from './desktop';
|
||||
export { default as Device } from './device';
|
||||
export { default as Diagram_3 } from './diagram_3';
|
||||
export { default as Dice_3 } from './dice_3';
|
||||
export { default as Dizzy } from './dizzy';
|
||||
export { default as Door_closed } from './door_closed';
|
||||
export { default as Doublecheck } from './doublecheck';
|
||||
export { default as Download } from './download';
|
||||
export { default as Drag } from './drag';
|
||||
export { default as Edit } from './edit';
|
||||
|
|
@ -255,12 +203,12 @@ export { default as Event_view } from './event_view';
|
|||
export { default as Exclamation_circle_fill } from './exclamation_circle_fill';
|
||||
export { default as Exclamation_circle } from './exclamation_circle';
|
||||
export { default as Exclamation_triangle } from './exclamation_triangle';
|
||||
export { default as Expand_wide } from './expand_wide';
|
||||
export { default as Explosion } from './explosion';
|
||||
export { default as External_link_alt } from './external_link_alt';
|
||||
export { default as Eye_slash_fill } from './eye_slash_fill';
|
||||
export { default as Eye_slash } from './eye_slash';
|
||||
export { default as Eye } from './eye';
|
||||
export { default as Fetch_request } from './fetch_request';
|
||||
export { default as Fetch } from './fetch';
|
||||
export { default as Fflag_multi } from './fflag_multi';
|
||||
export { default as Fflag_single } from './fflag_single';
|
||||
|
|
@ -338,27 +286,16 @@ export { default as Funnel_mouse } from './funnel_mouse';
|
|||
export { default as Funnel_patch_exclamation_fill } from './funnel_patch_exclamation_fill';
|
||||
export { default as Funnel_sd_card } from './funnel_sd_card';
|
||||
export { default as Funnel_fill } from './funnel_fill';
|
||||
export { default as Funnel_new } from './funnel_new';
|
||||
export { default as Funnel } from './funnel';
|
||||
export { default as Gear_fill } from './gear_fill';
|
||||
export { default as Gear } from './gear';
|
||||
export { default as Geo_alt_fill_custom } from './geo_alt_fill_custom';
|
||||
export { default as Github } from './github';
|
||||
export { default as Graph_up_arrow } from './graph_up_arrow';
|
||||
export { default as Graph_up } from './graph_up';
|
||||
export { default as Grid_1x2 } from './grid_1x2';
|
||||
export { default as Grid_3x3 } from './grid_3x3';
|
||||
export { default as Grid_check } from './grid_check';
|
||||
export { default as Grid_horizontal } from './grid_horizontal';
|
||||
export { default as Grid } from './grid';
|
||||
export { default as Grip_horizontal } from './grip_horizontal';
|
||||
export { default as Hash } from './hash';
|
||||
export { default as Hdd_stack } from './hdd_stack';
|
||||
export { default as Headset } from './headset';
|
||||
export { default as Heart_rate } from './heart_rate';
|
||||
export { default as High_engagement } from './high_engagement';
|
||||
export { default as History } from './history';
|
||||
export { default as Hourglass_start } from './hourglass_start';
|
||||
export { default as Ic_errors } from './ic_errors';
|
||||
export { default as Ic_network } from './ic_network';
|
||||
export { default as Ic_rage } from './ic_rage';
|
||||
|
|
@ -407,16 +344,13 @@ export { default as Integrations_zustand } from './integrations_zustand';
|
|||
export { default as Journal_code } from './journal_code';
|
||||
export { default as Key } from './key';
|
||||
export { default as Keyboard } from './keyboard';
|
||||
export { default as Layer_group } from './layer_group';
|
||||
export { default as Layers_half } from './layers_half';
|
||||
export { default as Lightbulb_on } from './lightbulb_on';
|
||||
export { default as Lightbulb } from './lightbulb';
|
||||
export { default as Link_45deg } from './link_45deg';
|
||||
export { default as List_alt } from './list_alt';
|
||||
export { default as List_arrow } from './list_arrow';
|
||||
export { default as List_ul } from './list_ul';
|
||||
export { default as List } from './list';
|
||||
export { default as Lock_alt } from './lock_alt';
|
||||
export { default as Low_disc_space } from './low_disc_space';
|
||||
export { default as Magic } from './magic';
|
||||
export { default as Map_marker_alt } from './map_marker_alt';
|
||||
|
|
@ -468,33 +402,25 @@ export { default as Play_hover } from './play_hover';
|
|||
export { default as Play } from './play';
|
||||
export { default as Plug } from './plug';
|
||||
export { default as Plus_circle } from './plus_circle';
|
||||
export { default as Plus_lg } from './plus_lg';
|
||||
export { default as Plus } from './plus';
|
||||
export { default as Pointer_sessions_search } from './pointer_sessions_search';
|
||||
export { default as Prev1 } from './prev1';
|
||||
export { default as Pulse } from './pulse';
|
||||
export { default as Puzzle_piece } from './puzzle_piece';
|
||||
export { default as Puzzle } from './puzzle';
|
||||
export { default as Question_circle } from './question_circle';
|
||||
export { default as Question_lg } from './question_lg';
|
||||
export { default as Quote_left } from './quote_left';
|
||||
export { default as Quote_right } from './quote_right';
|
||||
export { default as Quotes } from './quotes';
|
||||
export { default as Record_btn } from './record_btn';
|
||||
export { default as Record_circle_fill } from './record_circle_fill';
|
||||
export { default as Record_circle } from './record_circle';
|
||||
export { default as Record2 } from './record2';
|
||||
export { default as Redo_back } from './redo_back';
|
||||
export { default as Redo } from './redo';
|
||||
export { default as Redux } from './redux';
|
||||
export { default as Referrer } from './referrer';
|
||||
export { default as Remote_control } from './remote_control';
|
||||
export { default as Replay_10 } from './replay_10';
|
||||
export { default as Resources_icon } from './resources_icon';
|
||||
export { default as Safe_fill } from './safe_fill';
|
||||
export { default as Safe } from './safe';
|
||||
export { default as Sandglass } from './sandglass';
|
||||
export { default as Search } from './search';
|
||||
export { default as Search_notification } from './search_notification';
|
||||
export { default as Server } from './server';
|
||||
export { default as Share_alt } from './share_alt';
|
||||
export { default as Shield_lock } from './shield_lock';
|
||||
|
|
@ -502,8 +428,6 @@ export { default as Side_menu_closed } from './side_menu_closed';
|
|||
export { default as Side_menu_open } from './side_menu_open';
|
||||
export { default as Signpost_split } from './signpost_split';
|
||||
export { default as Signup } from './signup';
|
||||
export { default as Skip_forward_fill } from './skip_forward_fill';
|
||||
export { default as Skip_forward } from './skip_forward';
|
||||
export { default as Slack } from './slack';
|
||||
export { default as Slash_circle } from './slash_circle';
|
||||
export { default as Sleep } from './sleep';
|
||||
|
|
@ -513,7 +437,6 @@ export { default as Social_trello } from './social_trello';
|
|||
export { default as Sparkles } from './sparkles';
|
||||
export { default as Speedometer2 } from './speedometer2';
|
||||
export { default as Spinner } from './spinner';
|
||||
export { default as Star_solid } from './star_solid';
|
||||
export { default as Star } from './star';
|
||||
export { default as Step_forward } from './step_forward';
|
||||
export { default as Stickies } from './stickies';
|
||||
|
|
@ -521,17 +444,9 @@ export { default as Stop_record_circle } from './stop_record_circle';
|
|||
export { default as Stopwatch } from './stopwatch';
|
||||
export { default as Store } from './store';
|
||||
export { default as Sync_alt } from './sync_alt';
|
||||
export { default as Table_new } from './table_new';
|
||||
export { default as Table } from './table';
|
||||
export { default as Tablet_android } from './tablet_android';
|
||||
export { default as Tachometer_slow } from './tachometer_slow';
|
||||
export { default as Tachometer_slowest } from './tachometer_slowest';
|
||||
export { default as Tags } from './tags';
|
||||
export { default as Team_funnel } from './team_funnel';
|
||||
export { default as Telephone_fill } from './telephone_fill';
|
||||
export { default as Telephone } from './telephone';
|
||||
export { default as Terminal } from './terminal';
|
||||
export { default as Text_paragraph } from './text_paragraph';
|
||||
export { default as Thermometer_sun } from './thermometer_sun';
|
||||
export { default as Toggles } from './toggles';
|
||||
export { default as Tools } from './tools';
|
||||
|
|
@ -543,14 +458,8 @@ export { default as User_friends } from './user_friends';
|
|||
export { default as User_switch } from './user_switch';
|
||||
export { default as Users } from './users';
|
||||
export { default as Vendors_graphql } from './vendors_graphql';
|
||||
export { default as Vendors_mobx } from './vendors_mobx';
|
||||
export { default as Vendors_ngrx } from './vendors_ngrx';
|
||||
export { default as Vendors_redux } from './vendors_redux';
|
||||
export { default as Vendors_vuex } from './vendors_vuex';
|
||||
export { default as Web_vitals } from './web_vitals';
|
||||
export { default as Wifi } from './wifi';
|
||||
export { default as Window_alt } from './window_alt';
|
||||
export { default as Window_restore } from './window_restore';
|
||||
export { default as Window_x } from './window_x';
|
||||
export { default as Window } from './window';
|
||||
export { default as Zoom_in } from './zoom_in';
|
||||
|
|
|
|||
19
frontend/app/components/ui/Icons/referrer.tsx
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
|
||||
/* Auto-generated, do not edit */
|
||||
import React from 'react';
|
||||
|
||||
interface Props {
|
||||
size?: number | string;
|
||||
width?: number | string;
|
||||
height?: number | string;
|
||||
fill?: string;
|
||||
}
|
||||
|
||||
function Referrer(props: Props) {
|
||||
const { size = 14, width = size, height = size, fill = '' } = props;
|
||||
return (
|
||||
<svg fill="none" viewBox="0 0.6 24 24" width={ `${ width }px` } height={ `${ height }px` } ><rect y=".6" width="24" height="24" rx="12" fill="#EBF4F5"/><path d="M10.5 8.1h-2a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1Z" fill="#fff" stroke="#24959A" strokeLinecap="round" strokeLinejoin="round"/><path d="M9.5 12.1v2a1 1 0 0 0 1 1h2" stroke="#24959A" strokeLinecap="round" strokeLinejoin="round"/><path d="M15.5 13.1h-2a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1Z" fill="#fff" stroke="#24959A" strokeLinecap="round" strokeLinejoin="round"/></svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default Referrer;
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
import React from 'react';
|
||||
import { Icon } from 'UI';
|
||||
import { InfoCircleOutlined } from '@ant-design/icons'
|
||||
import styles from './noContent.module.css';
|
||||
|
||||
interface Props {
|
||||
|
|
@ -21,7 +20,7 @@ export default function NoContent(props: Props) {
|
|||
children
|
||||
) : (
|
||||
<div className={`${styles.wrapper} ${size && styles[size]}`} style={style}>
|
||||
{icon && <Icon icon={icon} size={iconSize} />}
|
||||
{icon && <Icon name={icon} size={iconSize} />}
|
||||
{title && <div className='flex'>{title}</div>}
|
||||
{subtext && <div className={styles.subtext}>{subtext}</div>}
|
||||
{image && <div className="mt-4 flex justify-center">{image} </div>}
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
import React from 'react';
|
||||
import { Progress } from 'semantic-ui-react';
|
||||
|
||||
export default ({
|
||||
percent, ...props
|
||||
}) => (
|
||||
<Progress
|
||||
percent={ percent }
|
||||
{ ...props }
|
||||
/>
|
||||
);
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
import { storiesOf } from '@storybook/react';
|
||||
import Progress from '.';
|
||||
|
||||
storiesOf('Progress', module)
|
||||
.add('Pure', () => (
|
||||
<Progress />
|
||||
))
|
||||
|
||||
|
|
@ -1 +0,0 @@
|
|||
export { default } from './Progress';
|
||||
|
|
@ -3,7 +3,6 @@ export { default as Link } from './Link';
|
|||
// export { default as Dropdown } from './Dropdown';
|
||||
export { default as Button } from './Button';
|
||||
export { default as Label } from './Label';
|
||||
export { default as Progress } from './Progress';
|
||||
export { default as SlideModal } from './SlideModal';
|
||||
export { default as NoContent } from './NoContent';
|
||||
export { default as LinkStyledInput } from './LinkStyledInput';
|
||||
|
|
@ -59,3 +58,4 @@ export { default as Message } from './Message';
|
|||
export { default as Popover } from './Popover';
|
||||
export { default as Switch } from './Switch';
|
||||
export { default as Divider } from './Divider';
|
||||
export { default as CodeBlock } from './CodeBlock'
|
||||
|
|
@ -1,10 +1,8 @@
|
|||
import origMoment from "moment";
|
||||
import { extendMoment } from "moment-range";
|
||||
export const moment = extendMoment(origMoment);
|
||||
import { DateTime } from "luxon";
|
||||
import { DateTime, Interval } from 'luxon';
|
||||
|
||||
import { TIMEZONE } from 'App/constants/storageKeys';
|
||||
|
||||
export const CUSTOM_RANGE = "CUSTOM_RANGE";
|
||||
export const CUSTOM_RANGE = 'CUSTOM_RANGE';
|
||||
|
||||
const DATE_RANGE_LABELS = {
|
||||
// LAST_30_MINUTES: '30 Minutes',
|
||||
|
|
@ -21,94 +19,90 @@ const DATE_RANGE_LABELS = {
|
|||
|
||||
const DATE_RANGE_VALUES = {};
|
||||
Object.keys(DATE_RANGE_LABELS).forEach((key) => {
|
||||
DATE_RANGE_VALUES[key] = key;
|
||||
DATE_RANGE_VALUES[key] = key;
|
||||
});
|
||||
|
||||
export { DATE_RANGE_VALUES };
|
||||
export const dateRangeValues = Object.keys(DATE_RANGE_VALUES);
|
||||
|
||||
export const DATE_RANGE_OPTIONS = Object.keys(DATE_RANGE_LABELS).map((key) => {
|
||||
return {
|
||||
label: DATE_RANGE_LABELS[key],
|
||||
value: key,
|
||||
};
|
||||
return {
|
||||
label: DATE_RANGE_LABELS[key],
|
||||
value: key,
|
||||
};
|
||||
});
|
||||
|
||||
export function getDateRangeFromTs(start, end) {
|
||||
return moment.range(moment(start), moment(end));
|
||||
}
|
||||
|
||||
export function getDateRangeLabel(value) {
|
||||
return DATE_RANGE_LABELS[value];
|
||||
return DATE_RANGE_LABELS[value];
|
||||
}
|
||||
|
||||
export function getDateRangeFromValue(value) {
|
||||
const tz = JSON.parse(localStorage.getItem(TIMEZONE));
|
||||
const offset = tz ? tz.label.slice(-6) : 0;
|
||||
const tz = JSON.parse(localStorage.getItem(TIMEZONE));
|
||||
const offset = tz.value
|
||||
|
||||
switch (value) {
|
||||
case DATE_RANGE_VALUES.LAST_30_MINUTES:
|
||||
return moment.range(
|
||||
moment().utcOffset(offset).startOf("hour").subtract(30, "minutes"),
|
||||
moment().utcOffset(offset).startOf("hour")
|
||||
);
|
||||
case DATE_RANGE_VALUES.YESTERDAY:
|
||||
return moment.range(
|
||||
moment().utcOffset(offset).subtract(1, "days").startOf("day"),
|
||||
moment().utcOffset(offset).subtract(1, "days").endOf("day")
|
||||
);
|
||||
case DATE_RANGE_VALUES.TODAY:
|
||||
return moment.range(moment().utcOffset(offset).startOf("day"), moment().utcOffset(offset).endOf("day"));
|
||||
case DATE_RANGE_VALUES.LAST_24_HOURS:
|
||||
return moment.range(moment().utcOffset(offset).subtract(24, "hours"), moment().utcOffset(offset));
|
||||
case DATE_RANGE_VALUES.LAST_7_DAYS:
|
||||
return moment.range(
|
||||
moment().utcOffset(offset).subtract(7, "days").startOf("day"),
|
||||
moment().utcOffset(offset).endOf("day")
|
||||
);
|
||||
case DATE_RANGE_VALUES.LAST_30_DAYS:
|
||||
return moment.range(
|
||||
moment().utcOffset(offset).subtract(30, "days").startOf("day"),
|
||||
moment().utcOffset(offset).endOf("day")
|
||||
);
|
||||
case DATE_RANGE_VALUES.THIS_MONTH:
|
||||
return moment().utcOffset(offset).range("month");
|
||||
case DATE_RANGE_VALUES.LAST_MONTH:
|
||||
return moment().utcOffset(offset).subtract(1, "months").range("month");
|
||||
case DATE_RANGE_VALUES.THIS_YEAR:
|
||||
return moment().utcOffset(offset).range("year");
|
||||
case DATE_RANGE_VALUES.CUSTOM_RANGE:
|
||||
return moment.range(moment().utcOffset(offset), moment().utcOffset(offset));
|
||||
}
|
||||
return null;
|
||||
const now = DateTime.now().setZone(offset);
|
||||
|
||||
switch (value) {
|
||||
// case DATE_RANGE_VALUES.LAST_30_MINUTES:
|
||||
// return Interval.fromDateTimes(
|
||||
// now.minus({ minutes: 30 }).startOf('minute'),
|
||||
// now.startOf('minute')
|
||||
// );
|
||||
// case DATE_RANGE_VALUES.YESTERDAY:
|
||||
// return Interval.fromDateTimes(
|
||||
// now.minus({ days: 1 }).startOf('day'),
|
||||
// now.minus({ days: 1 }).endOf('day')
|
||||
// );
|
||||
// case DATE_RANGE_VALUES.TODAY:
|
||||
// return Interval.fromDateTimes(now.startOf('day'), now.endOf('day'));
|
||||
case DATE_RANGE_VALUES.LAST_24_HOURS:
|
||||
return Interval.fromDateTimes(now.minus({ hours: 24 }), now);
|
||||
case DATE_RANGE_VALUES.LAST_7_DAYS:
|
||||
const range = Interval.fromDateTimes(
|
||||
now.minus({ days: 7 }).startOf('day'),
|
||||
now.endOf('day')
|
||||
);
|
||||
console.log(range, now.minus({ days: 7}))
|
||||
return Interval.fromDateTimes(
|
||||
now.minus({ days: 7 }).startOf('day'),
|
||||
now.endOf('day')
|
||||
);
|
||||
case DATE_RANGE_VALUES.LAST_30_DAYS:
|
||||
return Interval.fromDateTimes(
|
||||
now.minus({ days: 30 }).startOf('day'),
|
||||
now.endOf('day')
|
||||
);
|
||||
// case DATE_RANGE_VALUES.THIS_MONTH:
|
||||
// return Interval.fromDateTimes(now.startOf('month'), now.endOf('month'));
|
||||
// case DATE_RANGE_VALUES.LAST_MONTH:
|
||||
// const lastMonth = now.minus({ months: 1 });
|
||||
// return Interval.fromDateTimes(
|
||||
// lastMonth.startOf('month'),
|
||||
// lastMonth.endOf('month')
|
||||
// );
|
||||
// case DATE_RANGE_VALUES.THIS_YEAR:
|
||||
// return Interval.fromDateTimes(now.startOf('year'), now.endOf('year'));
|
||||
// case DATE_RANGE_VALUES.CUSTOM_RANGE:
|
||||
// return Interval.fromDateTimes(now, now);
|
||||
default:
|
||||
throw new Error('Invalid date range value');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given date is today/yesterday else return in specified format.
|
||||
* @param {Date} date Date to be cheked.
|
||||
* @param {DateTime} date Date to be checked.
|
||||
* @param {String} format Returning date format.
|
||||
* @return {String} Formated date string.
|
||||
* @return {String} Formatted date string.
|
||||
*/
|
||||
export const checkForRecent = (date, format) => {
|
||||
const d = new Date();
|
||||
// Today
|
||||
if (date.hasSame(d, "day")) return "Today";
|
||||
const now = DateTime.now();
|
||||
// Today
|
||||
if (date.hasSame(now, 'day')) return 'Today';
|
||||
|
||||
// Yesterday
|
||||
if (date.hasSame(d.setDate(d.getDate() - 1), "day")) return "Yesterday";
|
||||
// Yesterday
|
||||
if (date.hasSame(now.minus({ days: 1 }), 'day')) return 'Yesterday';
|
||||
|
||||
// Formatted
|
||||
return date.toFormat(format);
|
||||
};
|
||||
|
||||
export const overPastString = (period) => {
|
||||
if (period.rangeName === DATE_RANGE_VALUES.CUSTOM_RANGE) {
|
||||
const format = "LLL dd, yyyy HH:mm";
|
||||
const { startTimestamp, endTimestamp } = period.toTimestamps();
|
||||
const start = DateTime.fromMillis(startTimestamp).toFormat(format);
|
||||
const end = DateTime.fromMillis(endTimestamp).toFormat(format);
|
||||
return ` between ${start} - ${end}`;
|
||||
}
|
||||
|
||||
return ' over the ' + DATE_RANGE_LABELS[period.rangeName];
|
||||
// Formatted
|
||||
return date.toFormat(format);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -53,8 +53,8 @@ const REMOVE_SUCCESS = success(REMOVE);
|
|||
const range = getDateRangeFromValue(LAST_7_DAYS);
|
||||
const defaultDateFilters = {
|
||||
rangeValue: LAST_7_DAYS,
|
||||
startDate: range.start.unix() * 1000,
|
||||
endDate: range.end.unix() * 1000
|
||||
startDate: range.start.ts,
|
||||
endDate: range.end.ts
|
||||
}
|
||||
|
||||
const initialState = Map({
|
||||
|
|
|
|||
|
|
@ -60,11 +60,12 @@ const CLEAR_CURRENT_SESSION = 'sessions/CLEAR_CURRENT_SESSION';
|
|||
const PREFETCH_SESSION = 'sessions/PREFETCH_SESSION';
|
||||
|
||||
const range = getDateRangeFromValue(LAST_7_DAYS);
|
||||
|
||||
const defaultDateFilters = {
|
||||
url: '',
|
||||
rangeValue: LAST_7_DAYS,
|
||||
startDate: range.start.unix() * 1000,
|
||||
endDate: range.end.unix() * 1000,
|
||||
startDate: range.start.ts,
|
||||
endDate: range.end.ts,
|
||||
};
|
||||
|
||||
const initObj = {
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ export const login = params => ({
|
|||
});
|
||||
|
||||
export const loginSuccess = data => ({
|
||||
types: LOGIN.SUCCESS,
|
||||
type: LOGIN.SUCCESS,
|
||||
data
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
import { useMemo } from 'react'
|
||||
import { CellMeasurerCache, CellMeasurerCacheParams } from 'react-virtualized';
|
||||
|
||||
export default function useCellMeasurerCache(options?: CellMeasurerCacheParams) {
|
||||
return useMemo(() => new CellMeasurerCache({
|
||||
fixedWidth: true,
|
||||
...options
|
||||
}), [])
|
||||
}
|
||||
|
|
@ -407,6 +407,14 @@ export default class DashboardStore {
|
|||
this.showAlertModal = val;
|
||||
}
|
||||
|
||||
upPendingRequests = () => {
|
||||
this.pendingRequests += 1;
|
||||
}
|
||||
|
||||
downPendingRequests = () => {
|
||||
this.pendingRequests -= 1;
|
||||
}
|
||||
|
||||
fetchMetricChartData(
|
||||
metric: Widget,
|
||||
data: any,
|
||||
|
|
@ -422,7 +430,7 @@ export default class DashboardStore {
|
|||
}
|
||||
|
||||
return new Promise(async (resolve, reject) => {
|
||||
this.pendingRequests += 1;
|
||||
this.upPendingRequests()
|
||||
|
||||
if (metric.metricType === 'table' && metric.metricOf === 'jsException') {
|
||||
params.limit = 5;
|
||||
|
|
@ -435,7 +443,7 @@ export default class DashboardStore {
|
|||
reject(error);
|
||||
} finally {
|
||||
setTimeout(() => {
|
||||
this.pendingRequests -= 1;
|
||||
this.downPendingRequests()
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -101,8 +101,8 @@ const range = getDateRangeFromValue(LAST_7_DAYS);
|
|||
const defaultDateFilters = {
|
||||
url: '',
|
||||
rangeValue: LAST_7_DAYS,
|
||||
startDate: range.start.unix() * 1000,
|
||||
endDate: range.end.unix() * 1000,
|
||||
startDate: range.start.ts,
|
||||
endDate: range.end.ts,
|
||||
};
|
||||
|
||||
export default class SessionStore {
|
||||
|
|
|
|||
|
|
@ -116,6 +116,18 @@ class UserIconProvider implements IconProvider {
|
|||
}
|
||||
}
|
||||
|
||||
class ReferrerIconProvider implements IconProvider {
|
||||
getIcon(obj: any): React.ReactNode {
|
||||
return <Icon name="referrer" size={24} />;
|
||||
}
|
||||
}
|
||||
|
||||
class FetchIconProvider implements IconProvider {
|
||||
getIcon(obj: any): React.ReactNode {
|
||||
return <Icon name="fetch-request" size={24} />;
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
BrowserIconProvider,
|
||||
CountryIconProvider,
|
||||
|
|
@ -123,7 +135,9 @@ export {
|
|||
UrlIconProvider,
|
||||
DeviceIconProvider,
|
||||
OsIconProvider,
|
||||
UserIconProvider
|
||||
UserIconProvider,
|
||||
ReferrerIconProvider,
|
||||
FetchIconProvider
|
||||
};
|
||||
export type { IconProvider };
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { makeAutoObservable, runInAction } from 'mobx';
|
||||
import moment from 'moment';
|
||||
import { SKIP_TO_ISSUE, TIMEZONE, SHOWN_TIMEZONE, DURATION_FILTER, MOUSE_TRAIL } from 'App/constants/storageKeys';
|
||||
import { DateTime } from 'luxon'
|
||||
|
||||
export type Timezone = {
|
||||
label: string;
|
||||
|
|
@ -76,16 +76,14 @@ export default class SessionSettings {
|
|||
shownTimezone: 'user' | 'local';
|
||||
|
||||
constructor() {
|
||||
// compatibility fix for old timezone storage
|
||||
// TODO: remove after a while (1.7.1?)
|
||||
const userTimezoneOffset = moment().format('Z');
|
||||
const userTimezoneOffset = DateTime.local().toFormat('Z');
|
||||
const defaultTimezone = this.defaultTimezones.find((tz) =>
|
||||
tz.value.includes('UTC' + userTimezoneOffset.slice(0, 3))
|
||||
) || { label: 'Local', value: `UTC${userTimezoneOffset}` };
|
||||
|
||||
this.timezoneFix(defaultTimezone);
|
||||
// @ts-ignore
|
||||
this.timezone = JSON.parse(localStorage.getItem(TIMEZONE)) || defaultTimezone;
|
||||
|
||||
const savedTz = localStorage.getItem(TIMEZONE)
|
||||
this.timezone = savedTz ? JSON.parse(savedTz) : defaultTimezone;
|
||||
if (localStorage.getItem(MOUSE_TRAIL) === null) {
|
||||
localStorage.setItem(MOUSE_TRAIL, 'true');
|
||||
}
|
||||
|
|
@ -112,12 +110,6 @@ export default class SessionSettings {
|
|||
this.conditionalCapture = all;
|
||||
};
|
||||
|
||||
timezoneFix(defaultTimezone: Record<string, string>) {
|
||||
if (localStorage.getItem(TIMEZONE) === '[object Object]' || !localStorage.getItem(TIMEZONE)) {
|
||||
localStorage.setItem(TIMEZONE, JSON.stringify(defaultTimezone));
|
||||
}
|
||||
}
|
||||
|
||||
updateKey = (key: string, value: any) => {
|
||||
runInAction(() => {
|
||||
// @ts-ignore
|
||||
|
|
|
|||
|
|
@ -1,13 +1,20 @@
|
|||
import { numberWithCommas } from 'App/utils';
|
||||
import React from 'react';
|
||||
|
||||
import { countries } from 'App/constants';
|
||||
import { numberWithCommas } from 'App/utils';
|
||||
|
||||
import {
|
||||
BrowserIconProvider,
|
||||
CountryIconProvider, DeviceIconProvider,
|
||||
CountryIconProvider,
|
||||
DeviceIconProvider,
|
||||
IconProvider,
|
||||
IssueIconProvider, OsIconProvider,
|
||||
UrlIconProvider, UserIconProvider
|
||||
IssueIconProvider,
|
||||
OsIconProvider,
|
||||
ReferrerIconProvider,
|
||||
UrlIconProvider,
|
||||
UserIconProvider,
|
||||
FetchIconProvider,
|
||||
} from './IconProvider';
|
||||
import React from 'react';
|
||||
|
||||
interface NameFormatter {
|
||||
format(name: string): string;
|
||||
|
|
@ -15,7 +22,10 @@ interface NameFormatter {
|
|||
|
||||
class BaseFormatter implements NameFormatter {
|
||||
format(name: string): string {
|
||||
return name?.replace(/_/g, ' ').replace(/\w\S*/g, (w) => (w.replace(/^\w/, (c) => c.toUpperCase()))).trim();
|
||||
return name
|
||||
?.replace(/_/g, ' ')
|
||||
.replace(/\w\S*/g, (w) => w.replace(/^\w/, (c) => c.toUpperCase()))
|
||||
.trim();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -42,7 +52,13 @@ class IssueFormatter extends BaseFormatter {
|
|||
|
||||
class UserNameFormatter extends BaseFormatter {
|
||||
format(name: string): string {
|
||||
if (name === null || name === undefined || name === '' || name === 'null' || name === 'undefined') {
|
||||
if (
|
||||
name === null ||
|
||||
name === undefined ||
|
||||
name === '' ||
|
||||
name === 'null' ||
|
||||
name === 'undefined'
|
||||
) {
|
||||
return 'Anonymous';
|
||||
}
|
||||
|
||||
|
|
@ -67,26 +83,55 @@ export class SessionsByRow {
|
|||
return this;
|
||||
}
|
||||
|
||||
private getFormatters(metricType: string): { nameFormatter: NameFormatter; iconProvider: IconProvider } {
|
||||
private getFormatters(metricType: string): {
|
||||
nameFormatter: NameFormatter;
|
||||
iconProvider: IconProvider;
|
||||
} {
|
||||
switch (metricType) {
|
||||
case 'userBrowser':
|
||||
return { nameFormatter: new BrowserFormatter(), iconProvider: new BrowserIconProvider() };
|
||||
return {
|
||||
nameFormatter: new BrowserFormatter(),
|
||||
iconProvider: new BrowserIconProvider(),
|
||||
};
|
||||
case 'userCountry':
|
||||
return { nameFormatter: new CountryFormatter(), iconProvider: new CountryIconProvider() };
|
||||
return {
|
||||
nameFormatter: new CountryFormatter(),
|
||||
iconProvider: new CountryIconProvider(),
|
||||
};
|
||||
case 'issue':
|
||||
return { nameFormatter: new IssueFormatter(), iconProvider: new IssueIconProvider() };
|
||||
return {
|
||||
nameFormatter: new IssueFormatter(),
|
||||
iconProvider: new IssueIconProvider(),
|
||||
};
|
||||
case 'location':
|
||||
return { nameFormatter: new BaseFormatter(), iconProvider: new UrlIconProvider() };
|
||||
return {
|
||||
nameFormatter: new BaseFormatter(),
|
||||
iconProvider: new UrlIconProvider(),
|
||||
};
|
||||
case 'userDevice':
|
||||
return { nameFormatter: new BaseFormatter(), iconProvider: new DeviceIconProvider() };
|
||||
return {
|
||||
nameFormatter: new BaseFormatter(),
|
||||
iconProvider: new DeviceIconProvider(),
|
||||
};
|
||||
case 'platform':
|
||||
return { nameFormatter: new BaseFormatter(), iconProvider: new OsIconProvider() };
|
||||
return {
|
||||
nameFormatter: new BaseFormatter(),
|
||||
iconProvider: new OsIconProvider(),
|
||||
};
|
||||
case 'userId':
|
||||
return { nameFormatter: new UserNameFormatter(), iconProvider: new UserIconProvider() };
|
||||
case 'referrer':
|
||||
return { nameFormatter: new BaseFormatter(), iconProvider: new UrlIconProvider() };
|
||||
case 'fetch':
|
||||
return {
|
||||
nameFormatter: new BaseFormatter(),
|
||||
iconProvider: new FetchIconProvider(),
|
||||
};
|
||||
default:
|
||||
return { nameFormatter: new BaseFormatter(), iconProvider: new DefaultIconProvider() };
|
||||
return {
|
||||
nameFormatter: new BaseFormatter(),
|
||||
iconProvider: new DefaultIconProvider(),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
frontend/app/styles/import.css
vendored
|
|
@ -1,8 +1,6 @@
|
|||
@import 'react-toastify/dist/ReactToastify.css';
|
||||
@import "react-daterange-picker/dist/css/react-calendar.css";
|
||||
@import 'rc-time-picker/assets/index.css';
|
||||
@import 'highlight.js/styles/github-gist.css';
|
||||
@import 'react-tippy/dist/tippy.css';
|
||||
@import 'react-daterange-picker.css';
|
||||
@import 'rc-time-picker.css';
|
||||
/*@import 'antd/dist/reset.css';*/
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
@import "./theme";
|
||||
@import "./global";
|
||||
@import "./react-tippy-themes";
|
||||
@import "./reset.css";
|
||||
@import "./import.css";
|
||||
@import "./main.css";
|
||||
|
|
|
|||
|
|
@ -336,3 +336,11 @@ svg {
|
|||
--json-boolean: #0184bc;
|
||||
--json-null: #0184bc;
|
||||
}
|
||||
|
||||
.react-daterange-picker__wrapper {
|
||||
display: none!important;
|
||||
}
|
||||
.react-daterange-picker__calendar {
|
||||
position: relative!important;
|
||||
inset: 0!important;
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" class="bi bi-alarm" viewBox="0 0 16 16">
|
||||
<path d="M8.5 5.5a.5.5 0 0 0-1 0v3.362l-1.429 2.38a.5.5 0 1 0 .858.515l1.5-2.5A.5.5 0 0 0 8.5 9V5.5z"/>
|
||||
<path d="M6.5 0a.5.5 0 0 0 0 1H7v1.07a7.001 7.001 0 0 0-3.273 12.474l-.602.602a.5.5 0 0 0 .707.708l.746-.746A6.97 6.97 0 0 0 8 16a6.97 6.97 0 0 0 3.422-.892l.746.746a.5.5 0 0 0 .707-.708l-.601-.602A7.001 7.001 0 0 0 9 2.07V1h.5a.5.5 0 0 0 0-1h-3zm1.038 3.018a6.093 6.093 0 0 1 .924 0 6 6 0 1 1-.924 0zM0 3.5c0 .753.333 1.429.86 1.887A8.035 8.035 0 0 1 4.387 1.86 2.5 2.5 0 0 0 0 3.5zM13.5 1c-.753 0-1.429.333-1.887.86a8.035 8.035 0 0 1 3.527 3.527A2.5 2.5 0 0 0 13.5 1z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 669 B |
|
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M344 272h-72v-72a8 8 0 0 0-8-8h-16a8 8 0 0 0-8 8v72h-72a8 8 0 0 0-8 8v16a8 8 0 0 0 8 8h72v72a8 8 0 0 0 8 8h16a8 8 0 0 0 8-8v-72h72a8 8 0 0 0 8-8v-16a8 8 0 0 0-8-8zM32 112a80.09 80.09 0 0 1 80-80 79.23 79.23 0 0 1 50 18 253.22 253.22 0 0 1 34.44-10.8C175.89 15.42 145.86 0 112 0A112.14 112.14 0 0 0 0 112c0 25.86 9.17 49.41 24 68.39a255.93 255.93 0 0 1 17.4-31.64A78.94 78.94 0 0 1 32 112zM400 0c-33.86 0-63.89 15.42-84.44 39.25A253.22 253.22 0 0 1 350 50.05a79.23 79.23 0 0 1 50-18 80.09 80.09 0 0 1 80 80 78.94 78.94 0 0 1-9.36 36.75A255.93 255.93 0 0 1 488 180.39c14.79-19 24-42.53 24-68.39A112.14 112.14 0 0 0 400 0zM256 64C132.29 64 32 164.29 32 288a222.89 222.89 0 0 0 54.84 146.54L34.34 487a8 8 0 0 0 0 11.32l11.31 11.31a8 8 0 0 0 11.32 0l52.49-52.5a223.21 223.21 0 0 0 293.08 0L455 509.66a8 8 0 0 0 11.32 0l11.31-11.31a8 8 0 0 0 0-11.32l-52.5-52.49A222.89 222.89 0 0 0 480 288c0-123.71-100.29-224-224-224zm0 416c-105.87 0-192-86.13-192-192S150.13 96 256 96s192 86.13 192 192-86.13 192-192 192z"/></svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
|
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 27.3 21.7"><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><g id="Symbols"><g id="Watch-Sessions"><g id="tv-alt"><path id="Combined-Shape" d="M22.86,20.34a.34.34,0,0,1,.34.34h0v.68a.34.34,0,0,1-.34.34H4.44a.35.35,0,0,1-.35-.34h0v-.68a.35.35,0,0,1,.35-.34H22.86ZM25.93,0A1.36,1.36,0,0,1,27.3,1.36h0V16.27a1.36,1.36,0,0,1-1.37,1.36H1.37A1.36,1.36,0,0,1,0,16.27H0V1.36A1.36,1.36,0,0,1,1.37,0H25.93Zm0,1.36H1.37V16.27H25.93ZM12.5,6.24a1,1,0,0,1,.5.14l3,1.76a1,1,0,0,1,.36,1.36,1,1,0,0,1-.36.36l-3,1.76a1,1,0,0,1-1.36-.36,1,1,0,0,1-.14-.5V7.24A1,1,0,0,1,12.5,6.24Z"/></g></g></g></g></g></svg>
|
||||
|
Before Width: | Height: | Size: 667 B |
|
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48H48C21.5 32 0 53.5 0 80zm400-16c8.8 0 16 7.2 16 16v352c0 8.8-7.2 16-16 16H48c-8.8 0-16-7.2-16-16V80c0-8.8 7.2-16 16-16h352zm-208 64v64H88c-13.2 0-24 10.8-24 24v80c0 13.2 10.8 24 24 24h104v64c0 28.4 34.5 42.8 54.6 22.6l128-128c12.5-12.5 12.5-32.8 0-45.3l-128-128c-20.1-20-54.6-5.8-54.6 22.7zm160 128L224 384v-96H96v-64h128v-96l128 128z"/></svg>
|
||||
|
Before Width: | Height: | Size: 493 B |
|
|
@ -1,3 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" class="bi bi-arrow-left-square" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M15 2a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V2zM0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2zm11.5 5.5a.5.5 0 0 1 0 1H5.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L5.707 7.5H11.5z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 403 B |
|
|
@ -1,3 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" class="bi bi-arrow-right-square" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M15 2a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V2zM0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2zm4.5 5.5a.5.5 0 0 0 0 1h5.793l-2.147 2.146a.5.5 0 0 0 .708.708l3-3a.5.5 0 0 0 0-.708l-3-3a.5.5 0 1 0-.708.708L10.293 7.5H4.5z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 404 B |
|
|
@ -1,3 +0,0 @@
|
|||
<svg viewBox="0 0 27 27" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.80392 17.1429C9.64551 16.9846 9.43069 16.8956 9.2067 16.8956C8.98271 16.8956 8.76789 16.9846 8.60948 17.1429L1.68946 24.0629V19.3865C1.68946 19.1625 1.60046 18.9476 1.44204 18.7892C1.28363 18.6308 1.06876 18.5418 0.844729 18.5418C0.620693 18.5418 0.405833 18.6308 0.247415 18.7892C0.088998 18.9476 0 19.1625 0 19.3865V26.1021C0 26.3262 0.088998 26.541 0.247415 26.6994C0.405833 26.8579 0.620693 26.9469 0.844729 26.9469H7.56032C7.78436 26.9469 7.99922 26.8579 8.15764 26.6994C8.31605 26.541 8.40505 26.3262 8.40505 26.1021C8.40505 25.8781 8.31605 25.6632 8.15764 25.5048C7.99922 25.3464 7.78436 25.2574 7.56032 25.2574H2.8839L9.80392 18.3374C9.96229 18.179 10.0512 17.9641 10.0512 17.7402C10.0512 17.5162 9.96229 17.3013 9.80392 17.1429ZM17.1429 9.80392C17.3013 9.96229 17.5162 10.0512 17.7402 10.0512C17.9641 10.0512 18.179 9.96229 18.3374 9.80392L25.2574 2.8839V7.56032C25.2574 7.78436 25.3464 7.99922 25.5048 8.15764C25.6632 8.31605 25.8781 8.40505 26.1021 8.40505C26.3262 8.40505 26.541 8.31605 26.6994 8.15764C26.8579 7.99922 26.9469 7.78436 26.9469 7.56032V0.844729C26.9469 0.620693 26.8579 0.405833 26.6994 0.247415C26.541 0.088998 26.3262 0 26.1021 0H19.3865C19.1625 3.3384e-09 18.9476 0.088998 18.7892 0.247415C18.6308 0.405833 18.5418 0.620693 18.5418 0.844729C18.5418 1.06876 18.6308 1.28363 18.7892 1.44204C18.9476 1.60046 19.1625 1.68946 19.3865 1.68946H24.0629L17.1429 8.60948C16.9846 8.76789 16.8956 8.98271 16.8956 9.2067C16.8956 9.43069 16.9846 9.64551 17.1429 9.80392Z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.6 KiB |
|
|
@ -1,3 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" class="bi bi-bell-fill" viewBox="0 0 16 16">
|
||||
<path d="M8 16a2 2 0 0 0 2-2H6a2 2 0 0 0 2 2zm.995-14.901a1 1 0 1 0-1.99 0A5.002 5.002 0 0 0 3 6c0 1.098-.5 6-2 7h14c-1.5-1-2-5.902-2-7 0-2.42-1.72-4.44-4.005-4.901z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 262 B |
|
|
@ -1,10 +0,0 @@
|
|||
<svg viewBox="0 0 17 17" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_2633_13173)">
|
||||
<path d="M1.5 3.328C2.385 2.958 3.654 2.559 4.888 2.435C6.218 2.301 7.346 2.498 8 3.187V12.933C7.065 12.403 5.88 12.33 4.787 12.44C3.607 12.56 2.417 12.901 1.5 13.251V3.328ZM9 3.187C9.654 2.498 10.782 2.301 12.112 2.435C13.346 2.559 14.615 2.958 15.5 3.328V13.251C14.582 12.901 13.393 12.559 12.213 12.441C11.119 12.33 9.935 12.402 9 12.933V3.187ZM8.5 2.283C7.515 1.436 6.087 1.31 4.787 1.44C3.273 1.593 1.745 2.112 0.793 2.545C0.705649 2.58473 0.631575 2.64875 0.579621 2.72943C0.527667 2.81011 0.500027 2.90404 0.5 3V14C0.500023 14.0837 0.521037 14.166 0.561117 14.2394C0.601197 14.3128 0.659062 14.375 0.729411 14.4203C0.79976 14.4656 0.880345 14.4925 0.963783 14.4985C1.04722 14.5046 1.13085 14.4896 1.207 14.455C2.089 14.055 3.51 13.574 4.887 13.435C6.296 13.293 7.477 13.522 8.11 14.312C8.15685 14.3704 8.21622 14.4175 8.28372 14.4499C8.35122 14.4823 8.42513 14.4991 8.5 14.4991C8.57487 14.4991 8.64878 14.4823 8.71628 14.4499C8.78378 14.4175 8.84315 14.3704 8.89 14.312C9.523 13.522 10.704 13.293 12.112 13.435C13.49 13.574 14.912 14.055 15.793 14.455C15.8692 14.4896 15.9528 14.5046 16.0362 14.4985C16.1197 14.4925 16.2002 14.4656 16.2706 14.4203C16.3409 14.375 16.3988 14.3128 16.4389 14.2394C16.479 14.166 16.5 14.0837 16.5 14V3C16.5 2.90404 16.4723 2.81011 16.4204 2.72943C16.3684 2.64875 16.2944 2.58473 16.207 2.545C15.255 2.112 13.727 1.593 12.213 1.44C10.913 1.309 9.485 1.436 8.5 2.283Z" />
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_2633_13173">
|
||||
<rect width="16" height="16" fill="white" transform="translate(0.5 0.5)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.6 KiB |
|
|
@ -1,3 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" class="bi bi-hourglass-split" viewBox="0 0 16 16">
|
||||
<path d="M2.5 15a.5.5 0 1 1 0-1h1v-1a4.5 4.5 0 0 1 2.557-4.06c.29-.139.443-.377.443-.59v-.7c0-.213-.154-.451-.443-.59A4.5 4.5 0 0 1 3.5 3V2h-1a.5.5 0 0 1 0-1h11a.5.5 0 0 1 0 1h-1v1a4.5 4.5 0 0 1-2.557 4.06c-.29.139-.443.377-.443.59v.7c0 .213.154.451.443.59A4.5 4.5 0 0 1 12.5 13v1h1a.5.5 0 0 1 0 1h-11zm2-13v1c0 .537.12 1.045.337 1.5h6.326c.216-.455.337-.963.337-1.5V2h-7zm3 6.35c0 .701-.478 1.236-1.011 1.492A3.5 3.5 0 0 0 4.5 13s.866-1.299 3-1.48V8.35zm1 0v3.17c2.134.181 3 1.48 3 1.48a3.5 3.5 0 0 0-1.989-3.158C8.978 9.586 8.5 9.052 8.5 8.351z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 650 B |
|
|
@ -1,4 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" class="bi bi-calendar4-week" viewBox="0 0 16 16">
|
||||
<path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM2 2a1 1 0 0 0-1 1v1h14V3a1 1 0 0 0-1-1H2zm13 3H1v9a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V5z"/>
|
||||
<path d="M11 7.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5v-1zm-3 0a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5v-1zm-2 3a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5v-1zm-3 0a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5v-1z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 676 B |
|
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M400 64h-48V12c0-6.627-5.373-12-12-12h-8c-6.627 0-12 5.373-12 12v52H128V12c0-6.627-5.373-12-12-12h-8c-6.627 0-12 5.373-12 12v52H48C21.49 64 0 85.49 0 112v352c0 26.51 21.49 48 48 48h352c26.51 0 48-21.49 48-48V112c0-26.51-21.49-48-48-48zM48 96h352c8.822 0 16 7.178 16 16v48H32v-48c0-8.822 7.178-16 16-16zm352 384H48c-8.822 0-16-7.178-16-16V192h384v272c0 8.822-7.178 16-16 16zm-66.467-194.937l-134.791 133.71c-4.7 4.663-12.288 4.642-16.963-.046l-67.358-67.552c-4.683-4.697-4.672-12.301.024-16.985l8.505-8.48c4.697-4.683 12.301-4.672 16.984.024l50.442 50.587 117.782-116.837c4.709-4.671 12.313-4.641 16.985.068l8.458 8.527c4.672 4.709 4.641 12.313-.068 16.984z"/></svg>
|
||||
|
Before Width: | Height: | Size: 736 B |
|
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M400 64h-48V8c0-4.4-3.6-8-8-8h-16c-4.4 0-8 3.6-8 8v56H128V8c0-4.4-3.6-8-8-8h-16c-4.4 0-8 3.6-8 8v56H48C21.5 64 0 85.5 0 112v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48zm16 400c0 8.8-7.2 16-16 16H48c-8.8 0-16-7.2-16-16V192h384v272zm0-304H32v-48c0-8.8 7.2-16 16-16h352c8.8 0 16 7.2 16 16v48zM112 384h96c8.8 0 16-7.2 16-16v-96c0-8.8-7.2-16-16-16h-96c-8.8 0-16 7.2-16 16v96c0 8.8 7.2 16 16 16zm16-96h64v64h-64v-64z"/></svg>
|
||||
|
Before Width: | Height: | Size: 521 B |
|
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M256 408c-66.2 0-120-53.8-120-120s53.8-120 120-120 120 53.8 120 120-53.8 120-120 120zm0-208c-48.5 0-88 39.5-88 88s39.5 88 88 88 88-39.5 88-88-39.5-88-88-88zm-32 88c0-17.6 14.4-32 32-32 8.8 0 16-7.2 16-16s-7.2-16-16-16c-35.3 0-64 28.7-64 64 0 8.8 7.2 16 16 16s16-7.2 16-16zM324.3 64c3.3 0 6.3 2.1 7.5 5.2l22.1 58.8H464c8.8 0 16 7.2 16 16v288c0 8.8-7.2 16-16 16H48c-8.8 0-16-7.2-16-16V144c0-8.8 7.2-16 16-16h110.2l20.1-53.6c2.3-6.2 8.3-10.4 15-10.4h131m0-32h-131c-20 0-37.9 12.4-44.9 31.1L136 96H48c-26.5 0-48 21.5-48 48v288c0 26.5 21.5 48 48 48h416c26.5 0 48-21.5 48-48V144c0-26.5-21.5-48-48-48h-88l-14.3-38c-5.8-15.7-20.7-26-37.4-26z"/></svg>
|
||||
|
Before Width: | Height: | Size: 713 B |
|
|
@ -1,4 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" class="bi bi-card-checklist" viewBox="0 0 16 16">
|
||||
<path d="M14.5 3a.5.5 0 0 1 .5.5v9a.5.5 0 0 1-.5.5h-13a.5.5 0 0 1-.5-.5v-9a.5.5 0 0 1 .5-.5h13zm-13-1A1.5 1.5 0 0 0 0 3.5v9A1.5 1.5 0 0 0 1.5 14h13a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 14.5 2h-13z"/>
|
||||
<path d="M7 5.5a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5zm-1.496-.854a.5.5 0 0 1 0 .708l-1.5 1.5a.5.5 0 0 1-.708 0l-.5-.5a.5.5 0 1 1 .708-.708l.146.147 1.146-1.147a.5.5 0 0 1 .708 0zM7 9.5a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5zm-1.496-.854a.5.5 0 0 1 0 .708l-1.5 1.5a.5.5 0 0 1-.708 0l-.5-.5a.5.5 0 0 1 .708-.708l.146.147 1.146-1.147a.5.5 0 0 1 .708 0z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 687 B |
|
|
@ -1,4 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" class="bi bi-card-list" viewBox="0 0 16 16">
|
||||
<path d="M14.5 3a.5.5 0 0 1 .5.5v9a.5.5 0 0 1-.5.5h-13a.5.5 0 0 1-.5-.5v-9a.5.5 0 0 1 .5-.5h13zm-13-1A1.5 1.5 0 0 0 0 3.5v9A1.5 1.5 0 0 0 1.5 14h13a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 14.5 2h-13z"/>
|
||||
<path d="M5 8a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7A.5.5 0 0 1 5 8zm0-2.5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm0 5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm-1-5a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0zM4 8a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0zm0 2.5a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 595 B |
|
|
@ -1,3 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" class="bi bi-caret-left-fill" viewBox="0 0 16 16">
|
||||
<path d="m3.86 8.753 5.482 4.796c.646.566 1.658.106 1.658-.753V3.204a1 1 0 0 0-1.659-.753l-5.48 4.796a1 1 0 0 0 0 1.506z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 223 B |
|
|
@ -1,3 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" class="bi bi-caret-up-fill" viewBox="0 0 16 16">
|
||||
<path d="m7.247 4.86-4.796 5.481c-.566.647-.106 1.659.753 1.659h9.592a1 1 0 0 0 .753-1.659l-4.796-5.48a1 1 0 0 0-1.506 0z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 222 B |
|
|
@ -1,4 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" class="bi bi-chat-dots" viewBox="0 0 16 16">
|
||||
<path d="M5 8a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm4 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 1a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/>
|
||||
<path d="M2.165 15.803l.02-.004c1.83-.363 2.948-.842 3.468-1.105A9.06 9.06 0 0 0 8 15c4.418 0 8-3.134 8-7s-3.582-7-8-7-8 3.134-8 7c0 1.76.743 3.37 1.97 4.6a10.437 10.437 0 0 1-.524 2.318l-.003.011a10.722 10.722 0 0 1-.244.637c-.079.186.074.394.273.362a21.673 21.673 0 0 0 .693-.125zm.8-3.108a1 1 0 0 0-.287-.801C1.618 10.83 1 9.468 1 8c0-3.192 3.004-6 7-6s7 2.808 7 6c0 3.193-3.004 6-7 6a8.06 8.06 0 0 1-2.088-.272 1 1 0 0 0-.711.074c-.387.196-1.24.57-2.634.893a10.97 10.97 0 0 0 .398-2z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 698 B |
|
|
@ -1,4 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" class="bi bi-chat-right-text" viewBox="0 0 16 16">
|
||||
<path d="M2 1a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h9.586a2 2 0 0 1 1.414.586l2 2V2a1 1 0 0 0-1-1H2zm12-1a2 2 0 0 1 2 2v12.793a.5.5 0 0 1-.854.353l-2.853-2.853a1 1 0 0 0-.707-.293H2a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2h12z"/>
|
||||
<path d="M3 3.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zM3 6a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9A.5.5 0 0 1 3 6zm0 2.5a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 504 B |
|
|
@ -1,4 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" class="bi bi-chevron-double-left" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M8.354 1.646a.5.5 0 0 1 0 .708L2.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z"/>
|
||||
<path fill-rule="evenodd" d="M12.354 1.646a.5.5 0 0 1 0 .708L6.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 404 B |
|
|
@ -1,4 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" class="bi bi-chevron-double-right" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M3.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L9.293 8 3.646 2.354a.5.5 0 0 1 0-.708z"/>
|
||||
<path fill-rule="evenodd" d="M7.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L13.293 8 7.646 2.354a.5.5 0 0 1 0-.708z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 407 B |
|
|
@ -1,4 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" class="bi bi-card-checklist" viewBox="0 0 16 16">
|
||||
<path d="M14.5 3a.5.5 0 0 1 .5.5v9a.5.5 0 0 1-.5.5h-13a.5.5 0 0 1-.5-.5v-9a.5.5 0 0 1 .5-.5h13zm-13-1A1.5 1.5 0 0 0 0 3.5v9A1.5 1.5 0 0 0 1.5 14h13a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 14.5 2h-13z"/>
|
||||
<path d="M7 5.5a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5zm-1.496-.854a.5.5 0 0 1 0 .708l-1.5 1.5a.5.5 0 0 1-.708 0l-.5-.5a.5.5 0 1 1 .708-.708l.146.147 1.146-1.147a.5.5 0 0 1 .708 0zM7 9.5a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5zm-1.496-.854a.5.5 0 0 1 0 .708l-1.5 1.5a.5.5 0 0 1-.708 0l-.5-.5a.5.5 0 0 1 .708-.708l.146.147 1.146-1.147a.5.5 0 0 1 .708 0z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 688 B |
|
|
@ -1,3 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" class="bi bi-cloud-fog2-fill" viewBox="0 0 16 16">
|
||||
<path d="M8.5 3a5.001 5.001 0 0 1 4.905 4.027A3 3 0 0 1 13 13h-1.5a.5.5 0 0 0 0-1H1.05a3.51 3.51 0 0 1-.713-1H9.5a.5.5 0 0 0 0-1H.035a3.53 3.53 0 0 1 0-1H7.5a.5.5 0 0 0 0-1H.337a3.5 3.5 0 0 1 3.57-1.977A5.001 5.001 0 0 1 8.5 3z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 330 B |
|
|
@ -1,13 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="2 2 28 28">
|
||||
<path d="M2 16C2 8.26801 8.26801 2 16 2C23.732 2 30 8.26801 30 16C30 23.732 23.732 30 16 30C8.26801 30 2 23.732 2 16Z" fill="#59316B"/>
|
||||
<path d="M17.0341 5.64229L16.4629 7.96739C17.272 6.32521 18.5572 5.0895 20.0329 4C18.9539 5.28452 17.9703 6.56916 17.3673 7.85369C18.3828 6.39022 19.7473 5.57729 21.2863 5.04069C19.2395 6.91062 17.6148 8.91715 16.3772 10.9334L15.3936 10.4944C15.5679 8.88465 16.1614 7.23589 17.0341 5.64229V5.64229Z" fill="#ABCD03"/>
|
||||
<path d="M14.4072 10.067L16.2795 10.863C16.2795 11.3509 16.2408 12.8391 16.5385 13.278C19.6523 17.3878 19.1284 25.626 15.9077 25.8373C11.0031 25.8373 9.13263 22.4228 9.13263 19.2846C9.13263 16.4227 12.4804 14.5203 14.4796 12.8293C14.9873 12.374 14.8992 11.3679 14.4072 10.067V10.067Z" fill="#FFFCDB"/>
|
||||
<path d="M16.28 10.8344L16.9548 11.1871C16.8914 11.6423 16.9865 12.6506 17.4306 12.9106C19.3982 14.1626 21.2545 15.5284 21.9844 16.8943C24.5865 21.7074 20.1597 26.1625 16.3359 25.7397C18.4144 24.1625 19.0174 20.9268 18.2399 17.3983C17.9226 16.0161 17.4306 14.7641 16.5579 13.3494C16.1799 12.655 16.3119 11.7938 16.28 10.8344Z" fill="white"/>
|
||||
<path d="M15.9552 10.7156L17.3514 10.9107C16.9389 12.309 18.1607 13.2846 18.5573 13.5124C19.4458 14.0165 20.3026 14.5367 20.9849 15.1708C22.2702 16.3741 23 18.0652 23 19.8538C23 21.6261 22.2066 23.3334 20.8739 24.4716C19.6204 25.5448 17.891 26.0001 16.2091 26.0001C15.1619 26.0001 14.2258 25.9514 13.2104 25.6098C10.894 24.813 9.16445 22.7806 9.02167 20.3414C8.89469 18.439 9.30723 16.9918 10.7512 15.4797C11.4968 14.6829 13.0042 13.7724 14.0356 13.0407C14.5434 12.6829 15.0828 11.6747 14.0514 9.77238L14.2577 9.60974L15.7862 10.6589L14.4958 10.1138C14.6068 10.2765 14.9083 11.0082 14.9719 11.2195C15.1147 11.8211 15.0512 12.4067 14.9242 12.6667C14.2738 13.87 13.1631 14.1952 12.354 14.8781C10.9259 16.0813 9.37101 17.0407 9.54551 20.3414C9.62486 21.9674 10.8625 23.9512 12.7187 24.878C13.766 25.3985 14.9719 25.6098 16.1936 25.6748C17.2883 25.7236 19.3827 25.0569 20.5251 24.0813C21.7468 23.0407 22.4291 21.4634 22.4291 19.8538C22.4291 18.2277 21.7944 16.683 20.6044 15.5935C19.9221 14.9594 18.7957 14.1952 18.0976 13.7886C17.3995 13.3821 16.5268 12.2439 16.8123 11.1545L15.9552 10.7156Z" fill="black"/>
|
||||
<path d="M15.5268 13.1219C15.3841 13.87 15.2254 15.2195 14.5907 15.7236C14.3209 15.9186 14.0512 16.1139 13.7656 16.3089C12.6232 17.1058 11.4808 17.8536 10.9573 19.7723C10.8462 20.1789 10.9415 20.6179 11.0367 21.0243C11.3223 22.195 12.1315 23.4634 12.7661 24.2114C12.7661 24.2439 12.8931 24.3252 12.8931 24.3577C13.4167 24.992 13.5754 25.1708 15.5587 25.626L15.511 25.8537C14.321 25.5286 13.3374 25.2359 12.7185 24.5041C12.7185 24.4879 12.6074 24.3739 12.6074 24.3739C11.9411 23.5934 11.1318 22.2927 10.8304 21.0732C10.7193 20.5853 10.6242 20.2114 10.7511 19.7072C11.2905 17.7236 12.4647 16.943 13.6547 16.1138C13.9244 15.9349 14.2417 15.7722 14.4955 15.5609C14.9873 15.187 15.257 14.0487 15.5268 13.1219V13.1219Z" fill="black"/>
|
||||
<path d="M16.0342 16.2113C16.0501 17.0569 15.9696 17.481 16.1758 18.0828C16.3027 18.4404 16.7313 18.9282 16.8583 19.3998C17.0328 20.0341 17.2229 20.7332 17.2069 21.156C17.2069 21.6439 17.1771 22.554 16.9709 23.5297C16.8136 24.3358 16.4512 25.0276 15.8418 25.4197C15.2175 25.288 14.4846 25.0631 14.0519 24.6831C13.2111 23.9351 12.4663 22.6845 12.371 21.595C12.2918 20.7007 13.0998 19.3819 14.2262 18.7153C15.1782 18.1462 15.3996 17.4976 15.6058 16.4569C15.3202 17.3674 15.0521 18.1307 14.1318 18.6185C12.799 19.3339 12.1152 20.5349 12.1786 21.6731C12.2738 23.1365 12.8456 24.128 13.9721 24.9249C14.4481 25.2664 15.3373 25.6272 15.8926 25.7248V25.6504C16.3137 25.5696 16.859 24.8607 17.1306 23.9017C17.3687 23.04 17.4625 21.937 17.4465 21.2378C17.4306 20.8313 17.2556 19.951 16.9382 19.1543C16.7637 18.7153 16.4956 18.2764 16.321 17.9674C16.1308 17.6582 16.1295 16.9917 16.0342 16.2113Z" fill="black"/>
|
||||
<path d="M15.9398 19.3998C15.9556 19.9689 16.1787 20.6981 16.2738 21.4461C16.3533 21.999 16.3188 22.5543 16.3029 23.0422C16.2872 23.607 16.1036 24.6188 15.8527 25.1109C15.6161 24.9997 15.5236 24.8729 15.3698 24.6681C15.1795 24.3917 15.0503 24.1152 14.9233 23.7901C14.8281 23.5461 14.7169 23.2669 14.6692 22.9418C14.6057 22.454 14.6235 21.6909 15.1629 20.9103C15.5754 20.2924 15.67 20.2454 15.8128 19.53C15.6222 20.1641 15.4802 20.2288 15.0358 20.7652C14.5441 21.3507 14.4622 22.2129 14.4622 22.912C14.4622 23.2048 14.5761 23.5296 14.6873 23.8384C14.8142 24.1637 14.9231 24.4875 15.0976 24.7314C15.3599 25.1267 15.6956 25.3516 15.86 25.3936C15.861 25.3939 15.8625 25.3934 15.8636 25.3936C15.8671 25.3945 15.8711 25.3967 15.8745 25.3974V25.3788C16.1823 25.027 16.3676 24.6776 16.4299 24.3258C16.5093 23.9031 16.5275 23.4794 16.5752 22.9753C16.6227 22.5525 16.5882 21.983 16.4771 21.3977C16.3186 20.666 16.0509 19.9199 15.9398 19.3998L15.9398 19.3998Z" fill="black"/>
|
||||
<path d="M15.9869 12.4391C16.0028 13.2845 16.0663 14.8619 16.2884 15.4797C16.3518 15.6911 16.9389 16.6179 17.3513 17.7398C17.637 18.5204 17.7004 19.2358 17.748 19.4471C17.9384 20.374 17.7004 21.935 17.383 23.4146C17.2244 24.2114 16.6849 25.2032 16.0661 25.5935L15.9393 25.8211C16.2884 25.8048 17.1451 24.9431 17.4465 23.8699C17.9543 22.0488 18.1606 21.2032 17.9226 19.187C17.8909 18.9917 17.8116 18.3252 17.5101 17.6097C17.0658 16.5202 16.4312 15.4796 16.3519 15.2682C16.209 14.9268 16.0186 13.4472 15.9869 12.4391V12.4391Z" fill="black"/>
|
||||
<path d="M16.2846 11.2827C16.2375 12.1516 16.2249 12.4716 16.3835 13.1057C16.558 13.8049 17.4466 14.813 17.8115 15.9675C18.5097 18.1789 18.3352 21.0732 17.8273 23.3333C17.6371 24.1299 16.7325 25.2846 15.8282 25.6584L16.4946 25.821C16.8595 25.8047 17.7955 24.9105 18.1605 23.8861C18.7475 22.2763 18.8586 20.3577 18.6206 18.3414C18.6047 18.1463 18.2873 16.4065 17.9859 15.6748C17.5575 14.5854 16.7958 13.6097 16.7166 13.3985C16.5739 13.0407 16.2604 12.2979 16.2846 11.2827Z" fill="black"/>
|
||||
<rect x="15.7802" y="10.6713" width="0.492005" height="15.0036" fill="black"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 5.8 KiB |
|
|
@ -1,11 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 32 32">
|
||||
<g clip-path="url(#clip0_450_13887)">
|
||||
<path d="M32 16C32 24.832 24.84 32 16 32C7.16 32 0 24.832 0 16C0 7.16 7.16 0 16 0C24.84 0 32 7.16 32 16Z" fill="#283544"/>
|
||||
<path d="M22.5621 12.4574C22.4857 12.502 20.6671 13.4425 20.6671 15.5279C20.7528 17.9061 22.9621 18.7401 23 18.7401C22.9621 18.7847 22.6665 19.8763 21.7907 21.0205C21.0956 22.0062 20.3242 23 19.1528 23C18.0385 23 17.6385 22.3431 16.3528 22.3431C14.972 22.3431 14.5813 23 13.5242 23C12.3528 23 11.5242 21.953 10.7913 20.9766C9.8391 19.6986 9.02978 17.6931 9.00121 15.7675C8.98195 14.7471 9.19189 13.744 9.72481 12.8921C10.477 11.7026 11.8198 10.8952 13.2863 10.8686C14.4099 10.8333 15.4099 11.5875 16.0956 11.5875C16.7528 11.5875 17.9814 10.8686 19.3714 10.8686C19.9714 10.8692 21.5714 11.0376 22.5621 12.4574ZM16.0006 10.6649C15.8006 9.73303 16.3528 8.80119 16.8671 8.20677C17.5242 7.48792 18.5621 7 19.4571 7C19.5143 7.93185 19.1522 8.84575 18.505 9.51136C17.9242 10.2302 16.9242 10.7714 16.0006 10.6649Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_450_13887">
|
||||
<rect width="32" height="32" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
|
|
@ -1,16 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="2.04 2 28 28">
|
||||
<path d="M16.0006 2.00382C16.0006 2.00382 24.2528 1.63483 28.6279 9.8999H15.2984C15.2984 9.8999 12.7829 9.81911 10.6341 12.8599C10.0168 14.1363 9.35332 15.451 10.0979 18.042C9.02529 16.2313 4.40344 8.21234 4.40344 8.21234C4.40344 8.21234 7.66344 2.33057 16.0005 2.00382H16.0006Z" fill="#EF3F36"/>
|
||||
<path d="M28.1995 22.9856C28.1995 22.9856 24.3916 30.2935 15.0245 29.9321C16.1819 27.9369 21.6911 18.4302 21.6911 18.4302C21.6911 18.4302 23.0221 16.3005 21.4519 12.9253C20.6532 11.7528 19.8392 10.5265 17.2159 9.87287C19.3262 9.85377 28.6047 9.87287 28.6047 9.87287C28.6047 9.87287 32.0806 15.6278 28.1995 22.9856Z" fill="#FCD900"/>
|
||||
<path d="M3.85931 23.0433C3.85931 23.0433 -0.588992 16.1044 4.41095 8.20068C5.56452 10.1959 11.0737 19.7027 11.0737 19.7027C11.0737 19.7027 12.262 21.917 15.9772 22.2475C17.3932 22.1437 18.8669 22.0553 20.7497 20.1217C19.7117 21.9516 15.0551 29.9476 15.0551 29.9476C15.0551 29.9476 8.31134 30.0706 3.8592 23.0433H3.85931Z" fill="#61BC5B"/>
|
||||
<path d="M15.0208 30.0013L16.8957 22.2053C16.8957 22.2053 18.9559 22.0437 20.6844 20.1562C19.6118 22.0362 15.0208 30.0013 15.0208 30.0013V30.0013Z" fill="#5AB055"/>
|
||||
<path d="M9.71973 16.089C9.71973 12.6523 12.5168 9.86523 15.9658 9.86523C19.4148 9.86523 22.2119 12.6523 22.2119 16.089C22.2119 19.5257 19.4148 22.3127 15.9658 22.3127C12.5168 22.3089 9.71973 19.5257 9.71973 16.089V16.089Z" fill="white"/>
|
||||
<path d="M10.7653 16.0891C10.7653 13.2291 13.0917 10.9071 15.9659 10.9071C18.8363 10.9071 21.1665 13.2252 21.1665 16.0891C21.1665 18.9493 18.8402 21.2713 15.9659 21.2713C13.0955 21.2713 10.7653 18.9493 10.7653 16.0891V16.0891Z" fill="url(#paint0_linear_449_13214)"/>
|
||||
<path d="M28.6008 9.87685L20.8809 12.1334C20.8809 12.1334 19.7158 10.4303 17.212 9.87685C19.3841 9.86528 28.6008 9.87685 28.6008 9.87685V9.87685Z" fill="#EACA05"/>
|
||||
<path d="M9.94747 17.7576C8.86325 15.8854 4.40344 8.21228 4.40344 8.21228L10.121 13.8479C10.121 13.8479 9.53453 15.0512 9.75453 16.7734L9.94736 17.7576H9.94747Z" fill="#DF3A32"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_449_13214" x1="15.9657" y1="10.9803" x2="15.9657" y2="20.9593" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#86BBE5"/>
|
||||
<stop offset="1" stop-color="#1072BA"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.2 KiB |
|
|
@ -1,16 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="2.04 2 28 28">
|
||||
<path d="M16.0007 2.00382C16.0007 2.00382 24.2529 1.63483 28.628 9.8999H15.2985C15.2985 9.8999 12.783 9.81911 10.6342 12.8599C10.0169 14.1363 9.35338 15.451 10.098 18.042C9.02535 16.2313 4.4035 8.21234 4.4035 8.21234C4.4035 8.21234 7.6635 2.33057 16.0006 2.00382H16.0007Z" fill="#EF3F36"/>
|
||||
<path d="M28.1996 22.9856C28.1996 22.9856 24.3917 30.2935 15.0246 29.9321C16.182 27.9369 21.6911 18.4302 21.6911 18.4302C21.6911 18.4302 23.0222 16.3005 21.452 12.9253C20.6533 11.7528 19.8392 10.5265 17.2159 9.87287C19.3263 9.85377 28.6047 9.87287 28.6047 9.87287C28.6047 9.87287 32.0806 15.6278 28.1996 22.9856Z" fill="#FCD900"/>
|
||||
<path d="M3.85937 23.0433C3.85937 23.0433 -0.588931 16.1044 4.41101 8.20068C5.56459 10.1959 11.0738 19.7027 11.0738 19.7027C11.0738 19.7027 12.2621 21.917 15.9773 22.2475C17.3933 22.1437 18.867 22.0553 20.7498 20.1217C19.7118 21.9516 15.0551 29.9476 15.0551 29.9476C15.0551 29.9476 8.3114 30.0706 3.85926 23.0433H3.85937Z" fill="#61BC5B"/>
|
||||
<path d="M15.0208 30.0013L16.8957 22.2053C16.8957 22.2053 18.9559 22.0437 20.6844 20.1562C19.6118 22.0362 15.0208 30.0013 15.0208 30.0013V30.0013Z" fill="#5AB055"/>
|
||||
<path d="M9.71985 16.089C9.71985 12.6523 12.517 9.86523 15.9659 9.86523C19.4149 9.86523 22.212 12.6523 22.212 16.089C22.212 19.5257 19.4149 22.3127 15.9659 22.3127C12.517 22.3089 9.71985 19.5257 9.71985 16.089V16.089Z" fill="white"/>
|
||||
<path d="M10.7653 16.0891C10.7653 13.2291 13.0918 10.9071 15.966 10.9071C18.8363 10.9071 21.1666 13.2252 21.1666 16.0891C21.1666 18.9493 18.8403 21.2713 15.966 21.2713C13.0956 21.2713 10.7653 18.9493 10.7653 16.0891V16.0891Z" fill="url(#paint0_linear_449_13361)"/>
|
||||
<path d="M28.6008 9.87685L20.881 12.1334C20.881 12.1334 19.7159 10.4303 17.2121 9.87685C19.3841 9.86528 28.6008 9.87685 28.6008 9.87685V9.87685Z" fill="#EACA05"/>
|
||||
<path d="M9.94753 17.7576C8.86331 15.8854 4.4035 8.21228 4.4035 8.21228L10.1211 13.8479C10.1211 13.8479 9.53459 15.0512 9.75459 16.7734L9.94742 17.7576H9.94753Z" fill="#DF3A32"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_449_13361" x1="15.9657" y1="10.9803" x2="15.9657" y2="20.9593" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#86BBE5"/>
|
||||
<stop offset="1" stop-color="#1072BA"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.2 KiB |
|
|
@ -1,41 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 32 32">
|
||||
<g clip-path="url(#clip0_450_13857)">
|
||||
<path d="M31.0754 15.8762C31.0754 24.5004 24.2938 31.492 15.928 31.492C7.56283 31.492 0.78125 24.5007 0.78125 15.8762C0.78125 7.25176 7.56283 0.260742 15.928 0.260742C24.2938 0.26101 31.0754 7.25203 31.0754 15.8762Z" fill="white"/>
|
||||
<path d="M29.9672 15.9833C29.9672 23.7041 23.7084 29.964 15.9871 29.964C8.26569 29.964 2.0069 23.7041 2.0069 15.9833C2.0069 8.26244 8.26569 2.00312 15.9871 2.00312C23.7084 2.00312 29.9672 8.26244 29.9672 15.9833ZM31.9655 15.9833C31.9655 24.8073 24.8111 31.9617 15.9871 31.9617C7.16306 31.9617 0.00866699 24.8073 0.00866699 15.9833C0.00866699 7.15927 7.16306 0.00488281 15.9871 0.00488281C24.8111 0.00488281 31.9655 7.159 31.9655 15.9833ZM30.6472 15.9833C30.6472 7.88722 24.0829 1.32365 15.9871 1.32365C7.89154 1.32365 1.3269 7.88749 1.3269 15.9833C1.3269 24.0791 7.8918 30.6429 15.9871 30.6429C24.0829 30.6429 30.6472 24.0791 30.6472 15.9833Z" fill="url(#paint0_linear_450_13857)"/>
|
||||
<mask id="mask0_450_13857" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="1" y="1" width="30" height="29">
|
||||
<path d="M30.0221 15.9455C30.0221 23.6843 23.7266 29.9795 15.987 29.9795C8.24877 29.9795 1.9541 23.6835 1.9541 15.9455C1.9541 8.20781 8.24958 1.9126 15.987 1.9126C23.7266 1.91233 30.0221 8.20781 30.0221 15.9455Z" fill="white"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_450_13857)">
|
||||
<path d="M21.6017 36.3896C21.1194 34.1707 18.3177 29.1479 17.2552 27.0241C16.1933 24.9002 15.129 21.9059 15.6137 19.9744C15.7013 19.623 14.6935 16.9461 14.9833 16.7568C17.2373 15.2864 17.8308 16.9169 18.7331 16.2578C19.1986 15.9169 19.8285 16.5382 19.99 15.9742C20.5679 13.9473 19.1849 10.4141 17.6417 8.8696C17.1368 8.36636 16.3634 8.05032 15.4908 7.8824C15.1549 7.42361 14.6137 6.98224 13.8469 6.57568C12.9931 6.12119 11.1362 5.52099 10.1731 5.3611C9.50573 5.25129 9.35494 5.43797 9.06998 5.48457C9.33566 5.50813 10.5963 6.13109 10.8416 6.16725C10.5963 6.33303 9.8756 6.15948 9.41574 6.36598C9.18407 6.4707 9.01079 6.86868 9.0124 7.05696C10.3274 6.92412 12.38 7.05268 13.5922 7.59261C12.6275 7.70242 11.1603 7.82481 10.5294 8.15638C8.69529 9.12296 7.88512 11.3796 8.36801 14.0841C8.85117 16.7825 10.9761 26.6314 11.6521 29.9203C12.3283 33.2046 10.2037 35.3274 8.85197 35.9073L10.3004 36.0045L9.81801 37.0669C11.5546 37.2595 13.4859 36.681 13.4859 36.681C13.1007 37.7429 10.4927 38.1305 10.4927 38.1305C10.4927 38.1305 11.749 38.5156 13.7757 37.7429C15.8044 36.9708 17.0594 36.4874 17.0594 36.4874L18.0247 38.9977L19.8603 37.1642L20.6325 39.0954C20.6357 39.0952 22.0846 38.6112 21.6017 36.3896Z" fill="#D5D7D8"/>
|
||||
<path d="M22.1851 35.9391C21.7043 33.7191 18.9026 28.6963 17.8391 26.5717C16.7761 24.4465 15.7142 21.453 16.1976 19.5222C16.287 19.1717 16.2886 17.7364 16.58 17.546C18.8324 16.0745 18.6723 17.4967 19.5759 16.8376C20.0419 16.4974 20.415 16.0863 20.577 15.522C21.1566 13.4941 19.772 9.96199 18.2274 8.41692C17.7242 7.91367 16.9504 7.59684 16.0781 7.42972C15.7428 6.96986 15.2021 6.52956 14.4361 6.12247C12.9923 5.35569 11.2024 5.04956 9.54403 5.35033C9.80917 5.37443 10.4161 5.92267 10.6603 5.95909C10.2905 6.20978 9.307 6.17764 9.31343 6.73471C10.6301 6.60294 12.0728 6.81104 13.2863 7.3499C12.3216 7.45971 11.4236 7.69781 10.7926 8.03098C8.95696 8.99568 8.47433 10.9267 8.95695 13.6323C9.44091 16.3362 11.5661 26.1846 12.2394 29.4679C12.9162 32.7509 10.7926 34.8747 9.44091 35.4543L10.8893 35.5505L10.407 36.6145C12.1435 36.8068 14.0748 36.2283 14.0748 36.2283C13.6897 37.2921 11.0816 37.6759 11.0816 37.6759C11.0816 37.6759 12.3366 38.0624 14.3646 37.2892C16.3942 36.517 17.6503 36.0344 17.6503 36.0344L18.615 38.5447L20.4506 36.7101L21.2244 38.6414C21.222 38.643 22.6696 38.1596 22.1851 35.9391Z" fill="white"/>
|
||||
<path d="M11.084 13.7673C11.0839 13.6341 11.1102 13.5021 11.1612 13.379C11.2122 13.2559 11.2869 13.144 11.3812 13.0499C11.4754 12.9557 11.5873 12.881 11.7104 12.83C11.8336 12.7791 11.9655 12.7529 12.0988 12.7531C12.2319 12.7531 12.3638 12.7793 12.4868 12.8303C12.6098 12.8813 12.7216 12.956 12.8157 13.0502C12.9098 13.1444 12.9845 13.2562 13.0354 13.3792C13.0863 13.5023 13.1125 13.6341 13.1125 13.7673C13.1126 13.9005 13.0864 14.0323 13.0355 14.1554C12.9846 14.2784 12.9099 14.3903 12.8158 14.4845C12.7216 14.5786 12.6099 14.6534 12.4868 14.7043C12.3638 14.7553 12.2319 14.7816 12.0988 14.7816C11.9655 14.7817 11.8335 14.7556 11.7103 14.7047C11.5872 14.6538 11.4753 14.5791 11.381 14.4849C11.2867 14.3907 11.212 14.2788 11.161 14.1557C11.1101 14.0326 11.0839 13.9006 11.084 13.7673Z" fill="#2D4F8E"/>
|
||||
<path d="M12.2855 13.4293C12.2855 13.3595 12.3132 13.2926 12.3626 13.2433C12.4119 13.194 12.4788 13.1663 12.5485 13.1663C12.6183 13.1663 12.6852 13.194 12.7345 13.2433C12.7838 13.2926 12.8115 13.3595 12.8115 13.4293C12.8115 13.4991 12.7837 13.5661 12.7343 13.6155C12.6849 13.6649 12.6179 13.6927 12.548 13.6928C12.4783 13.6925 12.4115 13.6646 12.3623 13.6152C12.3131 13.5658 12.2855 13.499 12.2855 13.4293Z" fill="white"/>
|
||||
<path d="M18.0062 13.1657C18.0066 12.9349 18.0985 12.7136 18.2617 12.5504C18.425 12.3873 18.6464 12.2955 18.8772 12.2953C19.0496 12.2952 19.2182 12.3462 19.3616 12.442C19.505 12.5377 19.6168 12.6739 19.6828 12.8332C19.7488 12.9925 19.7661 13.1678 19.7325 13.3369C19.6988 13.506 19.6157 13.6613 19.4938 13.7832C19.3718 13.9051 19.2164 13.9881 19.0473 14.0216C18.8781 14.0552 18.7029 14.0378 18.5436 13.9717C18.3843 13.9056 18.2483 13.7937 18.1526 13.6502C18.057 13.5068 18.006 13.3382 18.0062 13.1657Z" fill="#2D4F8E"/>
|
||||
<path d="M19.0392 12.8759C19.0392 12.7519 19.1407 12.6504 19.2636 12.6504C19.3914 12.6504 19.4897 12.7519 19.4897 12.8759C19.49 12.9056 19.4843 12.9351 19.473 12.9627C19.4618 12.9902 19.4451 13.0152 19.4241 13.0362C19.403 13.0572 19.378 13.0738 19.3504 13.085C19.3229 13.0962 19.2934 13.1018 19.2636 13.1014C19.2341 13.1013 19.2048 13.0954 19.1776 13.0841C19.1503 13.0727 19.1255 13.0561 19.1047 13.0351C19.0839 13.0142 19.0673 12.9894 19.0561 12.962C19.0449 12.9347 19.0391 12.9054 19.0392 12.8759Z" fill="white"/>
|
||||
<path d="M12.3869 10.8284C12.3869 10.8284 11.6226 10.4826 10.8793 10.9497C10.1375 11.4163 10.1648 11.8933 10.1648 11.8933C10.1648 11.8933 9.77028 11.014 10.8218 10.5833C11.8743 10.1521 12.3869 10.8284 12.3869 10.8284Z" fill="url(#paint1_linear_450_13857)"/>
|
||||
<path d="M19.4019 10.7588C19.4019 10.7588 18.8526 10.4449 18.4262 10.4503C17.551 10.4618 17.3115 10.8488 17.3115 10.8488C17.3115 10.8488 17.4586 9.92614 18.5794 10.1112C19.1863 10.2122 19.4019 10.7588 19.4019 10.7588Z" fill="url(#paint2_linear_450_13857)"/>
|
||||
</g>
|
||||
<path d="M15.2028 17.6787C15.3043 17.0651 16.8898 15.9044 18.0122 15.8342C19.1374 15.7635 19.4879 15.7793 20.4253 15.5549C21.3649 15.3304 23.7825 14.7278 24.4515 14.4188C25.1222 14.1092 27.9606 14.572 25.9597 15.6877C25.0935 16.1722 22.7605 17.0619 21.0928 17.5593C19.4272 18.0577 18.4172 17.0834 17.8631 17.9024C17.4222 18.5537 17.7736 19.4456 19.7641 19.6306C22.4522 19.8797 25.0295 18.4201 25.3131 19.1954C25.5981 19.9708 23.0031 20.9384 21.4224 20.9692C19.8447 20.9989 16.6619 19.9258 16.1857 19.5934C15.7076 19.2616 15.0705 18.4873 15.2028 17.6787Z" fill="#FDD20A"/>
|
||||
<path d="M16.4196 26.0608C16.4196 26.0608 12.6433 24.0465 12.5817 24.8636C12.5179 25.6821 12.5817 29.0173 13.0217 29.2696C13.4625 29.5208 16.6092 27.6337 16.6092 27.6337L16.4196 26.0608ZM17.8664 25.9338C17.8664 25.9338 20.4469 23.9827 21.0144 24.1086C21.5797 24.2369 21.7059 28.2628 21.2021 28.4541C20.6983 28.6402 17.745 27.4321 17.745 27.4321L17.8664 25.9338Z" fill="#65BC46"/>
|
||||
<path d="M15.5052 26.274C15.5052 27.5947 15.3156 28.1619 15.8828 28.2873C16.4482 28.4139 17.5179 28.2873 17.8963 28.036C18.2739 27.7846 17.9584 26.086 17.8336 25.7689C17.7064 25.4553 15.5052 25.7079 15.5052 26.274Z" fill="#43A244"/>
|
||||
<path d="M15.7452 25.9804C15.7452 27.3016 15.5559 27.8686 16.1228 27.9942C16.6877 28.1214 17.7576 27.9942 18.1363 27.743C18.514 27.491 18.1985 25.7935 18.0726 25.4756C17.9465 25.1617 15.7452 25.4145 15.7452 25.9804Z" fill="#65BC46"/>
|
||||
<path d="M19.3377 29.4683C18.2071 29.7557 17.045 29.9008 15.8785 29.9001C14.6157 29.9001 13.3926 29.7295 12.2278 29.415L12.2412 29.5257C13.4273 29.845 14.6504 30.0067 15.8788 30.0067C17.0869 30.0067 18.2597 29.8532 19.3787 29.5653L19.3377 29.4683Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_450_13857" x1="15.9871" y1="31.9617" x2="15.9871" y2="0.00514948" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#D14427"/>
|
||||
<stop offset="1" stop-color="#E55225"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_450_13857" x1="10.0922" y1="11.1667" x2="12.3869" y2="11.1667" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.006" stop-color="#6176B9"/>
|
||||
<stop offset="0.691" stop-color="#394A9F"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint2_linear_450_13857" x1="17.3115" y1="10.4677" x2="19.4016" y2="10.4677" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.006" stop-color="#6176B9"/>
|
||||
<stop offset="0.691" stop-color="#394A9F"/>
|
||||
</linearGradient>
|
||||
<clipPath id="clip0_450_13857">
|
||||
<rect width="32" height="32" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 8.8 KiB |
|
|
@ -1,41 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 32 32">
|
||||
<g clip-path="url(#clip0_450_13825)">
|
||||
<path d="M31.0754 15.8762C31.0754 24.5004 24.2938 31.492 15.928 31.492C7.56283 31.492 0.78125 24.5007 0.78125 15.8762C0.78125 7.25176 7.56283 0.260742 15.928 0.260742C24.2938 0.26101 31.0754 7.25203 31.0754 15.8762Z" fill="white"/>
|
||||
<path d="M29.9672 15.9833C29.9672 23.7041 23.7084 29.964 15.9871 29.964C8.26569 29.964 2.0069 23.7041 2.0069 15.9833C2.0069 8.26244 8.26569 2.00312 15.9871 2.00312C23.7084 2.00312 29.9672 8.26244 29.9672 15.9833ZM31.9655 15.9833C31.9655 24.8073 24.8111 31.9617 15.9871 31.9617C7.16306 31.9617 0.00866699 24.8073 0.00866699 15.9833C0.00866699 7.15927 7.16306 0.00488281 15.9871 0.00488281C24.8111 0.00488281 31.9655 7.159 31.9655 15.9833ZM30.6472 15.9833C30.6472 7.88722 24.0829 1.32365 15.9871 1.32365C7.89154 1.32365 1.3269 7.88749 1.3269 15.9833C1.3269 24.0791 7.8918 30.6429 15.9871 30.6429C24.0829 30.6429 30.6472 24.0791 30.6472 15.9833Z" fill="url(#paint0_linear_450_13825)"/>
|
||||
<mask id="mask0_450_13825" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="1" y="1" width="30" height="29">
|
||||
<path d="M30.0221 15.9455C30.0221 23.6843 23.7266 29.9795 15.987 29.9795C8.24877 29.9795 1.9541 23.6835 1.9541 15.9455C1.9541 8.20781 8.24958 1.9126 15.987 1.9126C23.7266 1.91233 30.0221 8.20781 30.0221 15.9455Z" fill="white"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_450_13825)">
|
||||
<path d="M21.6017 36.3896C21.1194 34.1707 18.3177 29.1479 17.2552 27.0241C16.1933 24.9002 15.129 21.9059 15.6137 19.9744C15.7013 19.623 14.6935 16.9461 14.9833 16.7568C17.2373 15.2864 17.8308 16.9169 18.7331 16.2578C19.1986 15.9169 19.8285 16.5382 19.99 15.9742C20.5679 13.9473 19.1849 10.4141 17.6417 8.8696C17.1368 8.36636 16.3634 8.05032 15.4908 7.8824C15.1549 7.42361 14.6137 6.98224 13.8469 6.57568C12.9931 6.12119 11.1362 5.52099 10.1731 5.3611C9.50573 5.25129 9.35494 5.43797 9.06998 5.48457C9.33566 5.50813 10.5963 6.13109 10.8416 6.16725C10.5963 6.33303 9.8756 6.15948 9.41574 6.36598C9.18407 6.4707 9.01079 6.86868 9.0124 7.05696C10.3274 6.92412 12.38 7.05268 13.5922 7.59261C12.6275 7.70242 11.1603 7.82481 10.5294 8.15638C8.69529 9.12296 7.88512 11.3796 8.36801 14.0841C8.85117 16.7825 10.9761 26.6314 11.6521 29.9203C12.3283 33.2046 10.2037 35.3274 8.85197 35.9073L10.3004 36.0045L9.81801 37.0669C11.5546 37.2595 13.4859 36.681 13.4859 36.681C13.1007 37.7429 10.4927 38.1305 10.4927 38.1305C10.4927 38.1305 11.749 38.5156 13.7757 37.7429C15.8044 36.9708 17.0594 36.4874 17.0594 36.4874L18.0247 38.9977L19.8603 37.1642L20.6325 39.0954C20.6357 39.0952 22.0846 38.6112 21.6017 36.3896Z" fill="#D5D7D8"/>
|
||||
<path d="M22.1851 35.9391C21.7043 33.7191 18.9026 28.6963 17.8391 26.5717C16.7761 24.4465 15.7142 21.453 16.1976 19.5222C16.287 19.1717 16.2886 17.7364 16.58 17.546C18.8324 16.0745 18.6723 17.4967 19.5759 16.8376C20.0419 16.4974 20.415 16.0863 20.577 15.522C21.1566 13.4941 19.772 9.96199 18.2274 8.41692C17.7242 7.91367 16.9504 7.59684 16.0781 7.42972C15.7428 6.96986 15.2021 6.52956 14.4361 6.12247C12.9923 5.35569 11.2024 5.04956 9.54403 5.35033C9.80917 5.37443 10.4161 5.92267 10.6603 5.95909C10.2905 6.20978 9.307 6.17764 9.31343 6.73471C10.6301 6.60294 12.0728 6.81104 13.2863 7.3499C12.3216 7.45971 11.4236 7.69781 10.7926 8.03098C8.95696 8.99568 8.47433 10.9267 8.95695 13.6323C9.44091 16.3362 11.5661 26.1846 12.2394 29.4679C12.9162 32.7509 10.7926 34.8747 9.44091 35.4543L10.8893 35.5505L10.407 36.6145C12.1435 36.8068 14.0748 36.2283 14.0748 36.2283C13.6897 37.2921 11.0816 37.6759 11.0816 37.6759C11.0816 37.6759 12.3366 38.0624 14.3646 37.2892C16.3942 36.517 17.6503 36.0344 17.6503 36.0344L18.615 38.5447L20.4506 36.7101L21.2244 38.6414C21.222 38.643 22.6696 38.1596 22.1851 35.9391Z" fill="white"/>
|
||||
<path d="M11.084 13.7673C11.0839 13.6341 11.1102 13.5021 11.1612 13.379C11.2122 13.2559 11.2869 13.144 11.3812 13.0499C11.4754 12.9557 11.5873 12.881 11.7104 12.83C11.8336 12.7791 11.9655 12.7529 12.0988 12.7531C12.2319 12.7531 12.3638 12.7793 12.4868 12.8303C12.6098 12.8813 12.7216 12.956 12.8157 13.0502C12.9098 13.1444 12.9845 13.2562 13.0354 13.3792C13.0863 13.5023 13.1125 13.6341 13.1125 13.7673C13.1126 13.9005 13.0864 14.0323 13.0355 14.1554C12.9846 14.2784 12.9099 14.3903 12.8158 14.4845C12.7216 14.5786 12.6099 14.6534 12.4868 14.7043C12.3638 14.7553 12.2319 14.7816 12.0988 14.7816C11.9655 14.7817 11.8335 14.7556 11.7103 14.7047C11.5872 14.6538 11.4753 14.5791 11.381 14.4849C11.2867 14.3907 11.212 14.2788 11.161 14.1557C11.1101 14.0326 11.0839 13.9006 11.084 13.7673Z" fill="#2D4F8E"/>
|
||||
<path d="M12.2855 13.4293C12.2855 13.3595 12.3132 13.2926 12.3626 13.2433C12.4119 13.194 12.4788 13.1663 12.5485 13.1663C12.6183 13.1663 12.6852 13.194 12.7345 13.2433C12.7838 13.2926 12.8115 13.3595 12.8115 13.4293C12.8115 13.4991 12.7837 13.5661 12.7343 13.6155C12.6849 13.6649 12.6179 13.6927 12.548 13.6928C12.4783 13.6925 12.4115 13.6646 12.3623 13.6152C12.3131 13.5658 12.2855 13.499 12.2855 13.4293Z" fill="white"/>
|
||||
<path d="M18.0062 13.1657C18.0066 12.9349 18.0985 12.7136 18.2617 12.5504C18.425 12.3873 18.6464 12.2955 18.8772 12.2953C19.0496 12.2952 19.2182 12.3462 19.3616 12.442C19.505 12.5377 19.6168 12.6739 19.6828 12.8332C19.7488 12.9925 19.7661 13.1678 19.7325 13.3369C19.6988 13.506 19.6157 13.6613 19.4938 13.7832C19.3718 13.9051 19.2164 13.9881 19.0473 14.0216C18.8781 14.0552 18.7029 14.0378 18.5436 13.9717C18.3843 13.9056 18.2483 13.7937 18.1526 13.6502C18.057 13.5068 18.006 13.3382 18.0062 13.1657Z" fill="#2D4F8E"/>
|
||||
<path d="M19.0392 12.8759C19.0392 12.7519 19.1407 12.6504 19.2636 12.6504C19.3914 12.6504 19.4897 12.7519 19.4897 12.8759C19.49 12.9056 19.4843 12.9351 19.473 12.9627C19.4618 12.9902 19.4451 13.0152 19.4241 13.0362C19.403 13.0572 19.378 13.0738 19.3504 13.085C19.3229 13.0962 19.2934 13.1018 19.2636 13.1014C19.2341 13.1013 19.2048 13.0954 19.1776 13.0841C19.1503 13.0727 19.1255 13.0561 19.1047 13.0351C19.0839 13.0142 19.0673 12.9894 19.0561 12.962C19.0449 12.9347 19.0391 12.9054 19.0392 12.8759Z" fill="white"/>
|
||||
<path d="M12.3869 10.8284C12.3869 10.8284 11.6226 10.4826 10.8793 10.9497C10.1375 11.4163 10.1648 11.8933 10.1648 11.8933C10.1648 11.8933 9.77028 11.014 10.8218 10.5833C11.8743 10.1521 12.3869 10.8284 12.3869 10.8284Z" fill="url(#paint1_linear_450_13825)"/>
|
||||
<path d="M19.4019 10.7588C19.4019 10.7588 18.8526 10.4449 18.4262 10.4503C17.551 10.4618 17.3115 10.8488 17.3115 10.8488C17.3115 10.8488 17.4586 9.92614 18.5794 10.1112C19.1863 10.2122 19.4019 10.7588 19.4019 10.7588Z" fill="url(#paint2_linear_450_13825)"/>
|
||||
</g>
|
||||
<path d="M15.2028 17.6787C15.3043 17.0651 16.8898 15.9044 18.0122 15.8342C19.1374 15.7635 19.4879 15.7793 20.4253 15.5549C21.3649 15.3304 23.7825 14.7278 24.4515 14.4188C25.1222 14.1092 27.9606 14.572 25.9597 15.6877C25.0935 16.1722 22.7605 17.0619 21.0928 17.5593C19.4272 18.0577 18.4172 17.0834 17.8631 17.9024C17.4222 18.5537 17.7736 19.4456 19.7641 19.6306C22.4522 19.8797 25.0295 18.4201 25.3131 19.1954C25.5981 19.9708 23.0031 20.9384 21.4224 20.9692C19.8447 20.9989 16.6619 19.9258 16.1857 19.5934C15.7076 19.2616 15.0705 18.4873 15.2028 17.6787Z" fill="#FDD20A"/>
|
||||
<path d="M16.4196 26.0608C16.4196 26.0608 12.6433 24.0465 12.5817 24.8636C12.5179 25.6821 12.5817 29.0173 13.0217 29.2696C13.4625 29.5208 16.6092 27.6337 16.6092 27.6337L16.4196 26.0608ZM17.8664 25.9338C17.8664 25.9338 20.4469 23.9827 21.0144 24.1086C21.5797 24.2369 21.7059 28.2628 21.2021 28.4541C20.6983 28.6402 17.745 27.4321 17.745 27.4321L17.8664 25.9338Z" fill="#65BC46"/>
|
||||
<path d="M15.5052 26.274C15.5052 27.5947 15.3156 28.1619 15.8828 28.2873C16.4482 28.4139 17.5179 28.2873 17.8963 28.036C18.2739 27.7846 17.9584 26.086 17.8336 25.7689C17.7064 25.4553 15.5052 25.7079 15.5052 26.274Z" fill="#43A244"/>
|
||||
<path d="M15.7452 25.9804C15.7452 27.3016 15.5559 27.8686 16.1228 27.9942C16.6877 28.1214 17.7576 27.9942 18.1363 27.743C18.514 27.491 18.1985 25.7935 18.0726 25.4756C17.9465 25.1617 15.7452 25.4145 15.7452 25.9804Z" fill="#65BC46"/>
|
||||
<path d="M19.3377 29.4683C18.2071 29.7557 17.045 29.9008 15.8785 29.9001C14.6157 29.9001 13.3926 29.7295 12.2278 29.415L12.2412 29.5257C13.4273 29.845 14.6504 30.0067 15.8788 30.0067C17.0869 30.0067 18.2597 29.8532 19.3787 29.5653L19.3377 29.4683Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_450_13825" x1="15.9871" y1="31.9617" x2="15.9871" y2="0.00514948" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#D14427"/>
|
||||
<stop offset="1" stop-color="#E55225"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_450_13825" x1="10.0922" y1="11.1667" x2="12.3869" y2="11.1667" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.006" stop-color="#6176B9"/>
|
||||
<stop offset="0.691" stop-color="#394A9F"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint2_linear_450_13825" x1="17.3115" y1="10.4677" x2="19.4016" y2="10.4677" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.006" stop-color="#6176B9"/>
|
||||
<stop offset="0.691" stop-color="#394A9F"/>
|
||||
</linearGradient>
|
||||
<clipPath id="clip0_450_13825">
|
||||
<rect width="32" height="32" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 8.8 KiB |