Merge branch 'dev' into player-refactoring-phase-1
This commit is contained in:
commit
ee2eeadf56
63 changed files with 621 additions and 282 deletions
20
.github/workflows/workers-ee.yaml
vendored
20
.github/workflows/workers-ee.yaml
vendored
|
|
@ -161,16 +161,16 @@ jobs:
|
|||
# Deploy command
|
||||
helm template openreplay -n app openreplay -f vars.yaml -f /tmp/image_override.yaml --set ingress-nginx.enabled=false --set skipMigration=true | kubectl apply -f -
|
||||
|
||||
- name: Alert slack
|
||||
if: ${{ failure() }}
|
||||
uses: rtCamp/action-slack-notify@v2
|
||||
env:
|
||||
SLACK_CHANNEL: ee
|
||||
SLACK_TITLE: "Failed ${{ github.workflow }}"
|
||||
SLACK_COLOR: ${{ job.status }} # or a specific color like 'good' or '#ff00ff'
|
||||
SLACK_WEBHOOK: ${{ secrets.SLACK_WEB_HOOK }}
|
||||
SLACK_USERNAME: "OR Bot"
|
||||
SLACK_MESSAGE: 'Build failed :bomb:'
|
||||
#- name: Alert slack
|
||||
# if: ${{ failure() }}
|
||||
# uses: rtCamp/action-slack-notify@v2
|
||||
# env:
|
||||
# SLACK_CHANNEL: ee
|
||||
# SLACK_TITLE: "Failed ${{ github.workflow }}"
|
||||
# SLACK_COLOR: ${{ job.status }} # or a specific color like 'good' or '#ff00ff'
|
||||
# SLACK_WEBHOOK: ${{ secrets.SLACK_WEB_HOOK }}
|
||||
# SLACK_USERNAME: "OR Bot"
|
||||
# SLACK_MESSAGE: 'Build failed :bomb:'
|
||||
|
||||
|
||||
# - name: Debug Job
|
||||
|
|
|
|||
|
|
@ -91,9 +91,3 @@ Check out our [roadmap](https://www.notion.so/openreplay/Roadmap-889d2c3d968b478
|
|||
## License
|
||||
|
||||
This monorepo uses several licenses. See [LICENSE](/LICENSE) for more details.
|
||||
|
||||
## Contributors
|
||||
|
||||
<a href="https://github.com/openreplay/openreplay/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=openreplay/openreplay" />
|
||||
</a>
|
||||
|
|
|
|||
|
|
@ -213,8 +213,9 @@ def get_stages_and_events(filter_d, project_id) -> List[RealDictRow]:
|
|||
AND ISE.timestamp <= stages_t.stage{i + 1}_timestamp
|
||||
AND ISS.project_id=%(project_id)s
|
||||
AND ISE.session_id = stages_t.session_id
|
||||
AND ISS.type!='custom' -- ignore custom issues because they are massive
|
||||
{"AND ISS.type IN %(issueTypes)s" if len(filter_issues) > 0 else ""}
|
||||
LIMIT 20 -- remove the limit to get exact stats
|
||||
LIMIT 50 -- remove the limit to get exact stats
|
||||
) AS issues_t ON (TRUE)
|
||||
) AS stages_and_issues_t INNER JOIN sessions USING(session_id);
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -1,92 +0,0 @@
|
|||
chalice:
|
||||
env:
|
||||
jwt_secret: SetARandomStringHere
|
||||
clickhouse:
|
||||
enabled: false
|
||||
fromVersion: v1.6.0
|
||||
global:
|
||||
domainName: openreplay.local
|
||||
email:
|
||||
emailFrom: OpenReplay<do-not-reply@openreplay.com>
|
||||
emailHost: ""
|
||||
emailPassword: ""
|
||||
emailPort: "587"
|
||||
emailSslCert: ""
|
||||
emailSslKey: ""
|
||||
emailUseSsl: "false"
|
||||
emailUseTls: "true"
|
||||
emailUser: ""
|
||||
enterpriseEditionLicense: ""
|
||||
ingress:
|
||||
controller:
|
||||
config:
|
||||
enable-real-ip: true
|
||||
force-ssl-redirect: false
|
||||
max-worker-connections: 0
|
||||
proxy-body-size: 10m
|
||||
ssl-redirect: false
|
||||
extraArgs:
|
||||
default-ssl-certificate: app/openreplay-ssl
|
||||
ingressClass: openreplay
|
||||
ingressClassResource:
|
||||
name: openreplay
|
||||
service:
|
||||
externalTrafficPolicy: Local
|
||||
kafka:
|
||||
kafkaHost: kafka.db.svc.cluster.local
|
||||
kafkaPort: "9092"
|
||||
kafkaUseSsl: "false"
|
||||
zookeeperHost: databases-zookeeper.svc.cluster.local
|
||||
zookeeperNonTLSPort: 2181
|
||||
postgresql:
|
||||
postgresqlDatabase: postgres
|
||||
postgresqlHost: postgresql.db.svc.cluster.local
|
||||
postgresqlPassword: changeMePassword
|
||||
postgresqlPort: "5432"
|
||||
postgresqlUser: postgres
|
||||
redis:
|
||||
redisHost: redis-master.db.svc.cluster.local
|
||||
redisPort: "6379"
|
||||
s3:
|
||||
accessKey: changeMeMinioAccessKey
|
||||
assetsBucket: sessions-assets
|
||||
endpoint: http://minio.db.svc.cluster.local:9000
|
||||
recordingsBucket: mobs
|
||||
region: us-east-1
|
||||
secretKey: changeMeMinioPassword
|
||||
sourcemapsBucket: sourcemaps
|
||||
ingress-nginx:
|
||||
controller:
|
||||
config:
|
||||
enable-real-ip: true
|
||||
force-ssl-redirect: false
|
||||
max-worker-connections: 0
|
||||
proxy-body-size: 10m
|
||||
ssl-redirect: false
|
||||
extraArgs:
|
||||
default-ssl-certificate: app/openreplay-ssl
|
||||
ingressClass: openreplay
|
||||
ingressClassResource:
|
||||
name: openreplay
|
||||
service:
|
||||
externalTrafficPolicy: Local
|
||||
kafka:
|
||||
kafkaHost: kafka.db.svc.cluster.local
|
||||
kafkaPort: "9092"
|
||||
kafkaUseSsl: "false"
|
||||
zookeeperHost: databases-zookeeper.svc.cluster.local
|
||||
zookeeperNonTLSPort: 2181
|
||||
minio:
|
||||
global:
|
||||
minio:
|
||||
accessKey: changeMeMinioAccessKey
|
||||
secretKey: changeMeMinioPassword
|
||||
postgresql:
|
||||
postgresqlDatabase: postgres
|
||||
postgresqlHost: postgresql.db.svc.cluster.local
|
||||
postgresqlPassword: changeMePassword
|
||||
postgresqlPort: "5432"
|
||||
postgresqlUser: postgres
|
||||
redis:
|
||||
redisHost: redis-master.db.svc.cluster.local
|
||||
redisPort: "6379"
|
||||
|
|
@ -51,6 +51,7 @@ def get_projects(tenant_id, recording_state=False, gdpr=None, recorded=False, st
|
|||
AND users.deleted_at ISNULL
|
||||
AND users.tenant_id = %(tenant_id)s
|
||||
AND (roles.all_projects OR roles_projects.project_id = s.project_id)
|
||||
LIMIT 1
|
||||
) AS role_project ON (TRUE)"""
|
||||
extra_projection = ""
|
||||
extra_join = ""
|
||||
|
|
|
|||
|
|
@ -220,8 +220,9 @@ def get_stages_and_events(filter_d, project_id) -> List[RealDictRow]:
|
|||
AND ISE.timestamp <= stages_t.stage{i + 1}_timestamp
|
||||
AND ISS.project_id=%(project_id)s
|
||||
AND ISE.session_id = stages_t.session_id
|
||||
AND ISS.type!='custom' -- ignore custom issues because they are massive
|
||||
{"AND ISS.type IN %(issueTypes)s" if len(filter_issues) > 0 else ""}
|
||||
LIMIT 20 -- remove the limit to get exact stats
|
||||
LIMIT 50 -- remove the limit to get exact stats
|
||||
) AS issues_t ON (TRUE)
|
||||
) AS stages_and_issues_t INNER JOIN sessions USING(session_id);
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -23,4 +23,4 @@ MINIO_SECRET_KEY = ''
|
|||
|
||||
# APP and TRACKER VERSIONS
|
||||
VERSION = '1.9.0'
|
||||
TRACKER_VERSION = '4.1.6'
|
||||
TRACKER_VERSION = '4.1.7'
|
||||
|
|
|
|||
|
|
@ -3,18 +3,56 @@ import { connect } from 'react-redux';
|
|||
import { setAutoplayValues } from 'Duck/sessions';
|
||||
import { session as sessionRoute } from 'App/routes';
|
||||
import { Link, Icon, Toggler, Tooltip } from 'UI';
|
||||
import { withRouter, RouteComponentProps } from 'react-router-dom';
|
||||
import cn from 'classnames';
|
||||
import { fetchAutoplaySessions } from 'Duck/search';
|
||||
import { PlayerContext } from 'App/components/Session/playerContext';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
|
||||
function Autoplay(props) {
|
||||
const { previousId, nextId, disabled } = props;
|
||||
const { player, store } = React.useContext(PlayerContext)
|
||||
const PER_PAGE = 10;
|
||||
|
||||
interface Props extends RouteComponentProps {
|
||||
previousId: string;
|
||||
nextId: string;
|
||||
autoplay: boolean;
|
||||
defaultList: any;
|
||||
currentPage: number;
|
||||
total: number;
|
||||
setAutoplayValues?: () => void;
|
||||
toggleAutoplay?: () => void;
|
||||
latestRequestTime: any;
|
||||
sessionIds: any;
|
||||
fetchAutoplaySessions?: (page: number) => Promise<void>;
|
||||
}
|
||||
function Autoplay(props: Props) {
|
||||
const {
|
||||
previousId,
|
||||
nextId,
|
||||
currentPage,
|
||||
total,
|
||||
sessionIds,
|
||||
latestRequestTime,
|
||||
match: {
|
||||
// @ts-ignore
|
||||
params: { sessionId },
|
||||
},
|
||||
} = props;
|
||||
const { player, store } = React.useContext(PlayerContext)
|
||||
const { autoplay } = store.get()
|
||||
|
||||
const disabled = sessionIds.length === 0;
|
||||
|
||||
useEffect(() => {
|
||||
props.setAutoplayValues();
|
||||
if (latestRequestTime) {
|
||||
props.setAutoplayValues();
|
||||
const totalPages = Math.ceil(total / PER_PAGE);
|
||||
const index = sessionIds.indexOf(sessionId);
|
||||
|
||||
// check for the last page and load the next
|
||||
if (currentPage !== totalPages && index === sessionIds.length - 1) {
|
||||
props.fetchAutoplaySessions(currentPage + 1).then(props.setAutoplayValues);
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
|
@ -66,14 +104,14 @@ function Autoplay(props) {
|
|||
);
|
||||
}
|
||||
|
||||
const connectAutoplay = connect(
|
||||
(state) => ({
|
||||
export default connect(
|
||||
(state: any) => ({
|
||||
previousId: state.getIn(['sessions', 'previousId']),
|
||||
nextId: state.getIn(['sessions', 'nextId']),
|
||||
currentPage: state.getIn(['search', 'currentPage']) || 1,
|
||||
total: state.getIn(['sessions', 'total']) || 0,
|
||||
sessionIds: state.getIn(['sessions', 'sessionIds']) || [],
|
||||
latestRequestTime: state.getIn(['search', 'latestRequestTime']),
|
||||
}),
|
||||
{ setAutoplayValues }
|
||||
);
|
||||
|
||||
export default connectAutoplay(
|
||||
observer(Autoplay)
|
||||
);
|
||||
{ setAutoplayValues, fetchAutoplaySessions }
|
||||
)(withRouter(observer(Autoplay)))
|
||||
|
|
@ -50,7 +50,7 @@ function Step({ step, ind, isDefault }: { step: IStep; ind: number; isDefault?:
|
|||
>
|
||||
<div className="rounded-3xl px-4 bg-gray-lightest relative z-10">{ind + 1}</div>
|
||||
<div className="w-full">
|
||||
<div className="flex items-center w-full gap-2">
|
||||
<div className="flex items-start w-full gap-2">
|
||||
<div className="px-1 text-disabled-text">{durationFromMs(step.time)}</div>
|
||||
{/* @ts-ignore */}
|
||||
<Icon name={step.icon} size={16} color="gray-darkest" className="relative z-10" />
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ function XRay({ xrayProps, timePointer, stepPickRadius, clearEventSelection, set
|
|||
<>
|
||||
<div className="flex items-center justify-between my-2">
|
||||
<div className=" text-gray-dark py-2">
|
||||
XRAY
|
||||
X-RAY
|
||||
{timePointer > 0 ? (
|
||||
<span className="text-disabled-text ml-2">
|
||||
{Duration.fromMillis(selectedTime).toFormat('hh:mm:ss')}
|
||||
|
|
@ -79,14 +79,11 @@ function XRay({ xrayProps, timePointer, stepPickRadius, clearEventSelection, set
|
|||
</div>
|
||||
{!shouldShowPointerReset ? (
|
||||
<div
|
||||
className="flex items-center gap-2 rounded bg-active-blue px-2 py-1 whitespace-nowrap overflow-hidden text-clip"
|
||||
className="flex items-center gap-2 rounded bg-active-blue px-2 py-1 whitespace-nowrap overflow-hidden text-clip group"
|
||||
id="pdf-ignore"
|
||||
>
|
||||
<Icon name="info-circle" size={16} />
|
||||
<div>
|
||||
Click anywhere on <span className="font-semibold">X-RAY</span> to drilldown and add
|
||||
steps
|
||||
</div>
|
||||
<div>Click anywhere in the graph below to drilldown and add steps</div>
|
||||
</div>
|
||||
) : (
|
||||
<Button id="pdf-ignore" variant="text-primary" onClick={clearEventSelection}>
|
||||
|
|
@ -94,7 +91,11 @@ function XRay({ xrayProps, timePointer, stepPickRadius, clearEventSelection, set
|
|||
</Button>
|
||||
)}
|
||||
</div>
|
||||
<div className="relative cursor-pointer" onClick={pickEventRadius} ref={xrayContainer}>
|
||||
<div
|
||||
className="relative cursor-pointer group-hover:border-dotted hover:border-dotted group-hover:border-gray-dark hover:border-gray-dark border border-transparent"
|
||||
onClick={pickEventRadius}
|
||||
ref={xrayContainer}
|
||||
>
|
||||
<div
|
||||
id="pdf-ignore"
|
||||
style={{
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
export { default } from './LongTasks';
|
||||
export { default } from './LongTasks.DEPRECATED';
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ import Storage from '../Storage';
|
|||
import { ConnectedPerformance } from '../Performance';
|
||||
import GraphQL from '../GraphQL';
|
||||
import Exceptions from '../Exceptions/Exceptions';
|
||||
import LongTasks from '../LongTasks';
|
||||
import Inspector from '../Inspector';
|
||||
import Controls from './Controls';
|
||||
import Overlay from './Overlay';
|
||||
|
|
|
|||
|
|
@ -26,11 +26,7 @@ function NotePopup({
|
|||
|
||||
return (
|
||||
<GuidePopup
|
||||
title={
|
||||
<div className="color-gray-dark">
|
||||
Introducing <span className={''}>Notes</span>
|
||||
</div>
|
||||
}
|
||||
title="Introducing Notes"
|
||||
description={'Annotate session replays and share your feedback with the rest of your team.'}
|
||||
>
|
||||
<Button icon="quotes" variant="text" disabled={tooltipActive} onClick={toggleNotePopup}>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
max-width: 200px;
|
||||
&:hover {
|
||||
background-color: $active-blue;
|
||||
color: $teal !important;
|
||||
|
|
@ -34,4 +35,4 @@
|
|||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,19 +8,19 @@ import { filtersMap } from 'Types/filter/newFilter';
|
|||
export const getMatchingEntries = (searchQuery: string, filters: Record<string, any>) => {
|
||||
const matchingCategories: string[] = [];
|
||||
const matchingFilters: Record<string, any> = {};
|
||||
|
||||
if (searchQuery.length === 0) return {
|
||||
const lowerCaseQuery = searchQuery.toLowerCase();
|
||||
if (lowerCaseQuery.length === 0) return {
|
||||
matchingCategories: Object.keys(filters),
|
||||
matchingFilters: filters,
|
||||
};
|
||||
|
||||
Object.keys(filters).forEach(name => {
|
||||
if (name.toLocaleLowerCase().includes(searchQuery)) {
|
||||
if (name.toLocaleLowerCase().includes(lowerCaseQuery)) {
|
||||
matchingCategories.push(name);
|
||||
matchingFilters[name] = filters[name];
|
||||
} else {
|
||||
const filtersQuery = filters[name]
|
||||
.filter(filterOption => filterOption.label.toLocaleLowerCase().includes(searchQuery))
|
||||
.filter((filterOption: any) => filterOption.label.toLocaleLowerCase().includes(lowerCaseQuery))
|
||||
|
||||
if (filtersQuery.length > 0) matchingFilters[name] = filtersQuery
|
||||
filtersQuery.length > 0 && matchingCategories.push(name);
|
||||
|
|
@ -64,10 +64,10 @@ function FilterModal(props: Props) {
|
|||
// console.log(matchingFilters)
|
||||
return (
|
||||
<div className={stl.wrapper} style={{ width: '480px', maxHeight: '380px', overflowY: 'auto'}}>
|
||||
<div className={searchQuery && !isResultEmpty ? 'mb-6' : ''} style={{ columns: "auto 200px" }}>
|
||||
<div className={searchQuery && !isResultEmpty ? 'mb-6' : ''} style={{ columns: matchingCategories.length > 1 ? 'auto 200px' : 1 }}>
|
||||
{matchingCategories.map((key) => {
|
||||
return (
|
||||
<div className="mb-6" key={key}>
|
||||
<div className="mb-6 flex flex-col gap-2" key={key}>
|
||||
<div className="uppercase font-medium mb-1 color-gray-medium tracking-widest text-sm">{key}</div>
|
||||
<div>
|
||||
{matchingFilters[key] && matchingFilters[key].map((filter: any) => (
|
||||
|
|
|
|||
|
|
@ -40,13 +40,13 @@ export default function GuidePopup({ children, title, description }: IProps) {
|
|||
style={{ zIndex: INDEXES.POPUP_GUIDE_BG, opacity: '0.7' }}
|
||||
></div>
|
||||
<Tooltip
|
||||
offset={30}
|
||||
offset={20}
|
||||
className="!bg-white rounded text-center shadow !p-6"
|
||||
title={
|
||||
<div className="relative">
|
||||
<div className="font-bold">{title}</div>
|
||||
<div className="color-gray-medium w-80">{description}</div>
|
||||
<div className="w-10 h-10 bg-white rotate-45 absolute right-0 left-0 m-auto" style={{ top: '-38px'}} />
|
||||
<div className="font-bold text-figmaColors-text-primary">{title}</div>
|
||||
<div className="color-gray-dark w-80">{description}</div>
|
||||
<div className="w-4 h-4 bg-white rotate-45 absolute right-0 left-0 m-auto" style={{ top: '-28px'}} />
|
||||
</div>
|
||||
}
|
||||
open={true}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import SessionHeader from './components/SessionHeader';
|
|||
import NotesList from './components/Notes/NoteList';
|
||||
import { connect } from 'react-redux';
|
||||
import { fetchList as fetchMembers } from 'Duck/member';
|
||||
import LatestSessionsMessage from './components/LatestSessionsMessage';
|
||||
|
||||
function SessionListContainer({
|
||||
activeTab,
|
||||
|
|
@ -21,6 +22,7 @@ function SessionListContainer({
|
|||
<div className="widget-wrapper">
|
||||
<SessionHeader />
|
||||
<div className="border-b" />
|
||||
<LatestSessionsMessage />
|
||||
{activeTab !== 'notes' ? <SessionList /> : <NotesList members={members} />}
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { updateCurrentPage } from 'Duck/search';
|
||||
import { numberWithCommas } from 'App/utils'
|
||||
|
||||
interface Props {
|
||||
latestSessions: any;
|
||||
updateCurrentPage: (page: number) => void;
|
||||
}
|
||||
function LatestSessionsMessage(props: Props) {
|
||||
const { latestSessions = [] } = props;
|
||||
const count = latestSessions.length;
|
||||
return count > 0 ? (
|
||||
<div
|
||||
className="bg-amber-50 p-1 flex w-full border-b text-center justify-center link"
|
||||
style={{ backgroundColor: 'rgb(255 251 235)' }}
|
||||
onClick={() => props.updateCurrentPage(1)}
|
||||
>
|
||||
Show {numberWithCommas(count)} new Sessions
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
(state: any) => ({
|
||||
latestSessions: state.getIn(['search', 'latestList']),
|
||||
}),
|
||||
{ updateCurrentPage }
|
||||
)(LatestSessionsMessage);
|
||||
|
|
@ -0,0 +1 @@
|
|||
export { default } from './LatestSessionsMessage';
|
||||
|
|
@ -9,24 +9,25 @@ import {
|
|||
addFilterByKeyAndValue,
|
||||
updateCurrentPage,
|
||||
setScrollPosition,
|
||||
checkForLatestSessions,
|
||||
} from 'Duck/search';
|
||||
import useTimeout from 'App/hooks/useTimeout';
|
||||
import { numberWithCommas } from 'App/utils';
|
||||
import { fetchListActive as fetchMetadata } from 'Duck/customField';
|
||||
|
||||
enum NoContentType {
|
||||
Bookmarked,
|
||||
Vaulted,
|
||||
ToDate,
|
||||
Bookmarked,
|
||||
Vaulted,
|
||||
ToDate,
|
||||
}
|
||||
|
||||
const AUTOREFRESH_INTERVAL = 5 * 60 * 1000;
|
||||
const PER_PAGE = 10;
|
||||
let sessionTimeOut: any = null;
|
||||
interface Props {
|
||||
loading: boolean;
|
||||
list: any;
|
||||
currentPage: number;
|
||||
pageSize: number;
|
||||
total: number;
|
||||
filters: any;
|
||||
lastPlayedSessionId: string;
|
||||
|
|
@ -39,13 +40,15 @@ interface Props {
|
|||
fetchMetadata: () => void;
|
||||
activeTab: any;
|
||||
isEnterprise?: boolean;
|
||||
checkForLatestSessions: () => void;
|
||||
}
|
||||
function SessionList(props: Props) {
|
||||
const [noContentType, setNoContentType] = React.useState<NoContentType>(NoContentType.ToDate)
|
||||
const [noContentType, setNoContentType] = React.useState<NoContentType>(NoContentType.ToDate);
|
||||
const {
|
||||
loading,
|
||||
list,
|
||||
currentPage,
|
||||
pageSize,
|
||||
total,
|
||||
filters,
|
||||
lastPlayedSessionId,
|
||||
|
|
@ -60,19 +63,19 @@ function SessionList(props: Props) {
|
|||
const isVault = isBookmark && isEnterprise;
|
||||
const NO_CONTENT = React.useMemo(() => {
|
||||
if (isBookmark && !isEnterprise) {
|
||||
setNoContentType(NoContentType.Bookmarked)
|
||||
setNoContentType(NoContentType.Bookmarked);
|
||||
return {
|
||||
icon: ICONS.NO_BOOKMARKS,
|
||||
message: 'No sessions bookmarked.',
|
||||
};
|
||||
} else if (isVault) {
|
||||
setNoContentType(NoContentType.Vaulted)
|
||||
setNoContentType(NoContentType.Vaulted);
|
||||
return {
|
||||
icon: ICONS.NO_SESSIONS_IN_VAULT,
|
||||
message: 'No sessions found in vault.',
|
||||
};
|
||||
}
|
||||
setNoContentType(NoContentType.ToDate)
|
||||
setNoContentType(NoContentType.ToDate);
|
||||
return {
|
||||
icon: ICONS.NO_SESSIONS,
|
||||
message: 'No relevant sessions found for the selected time period.',
|
||||
|
|
@ -81,7 +84,7 @@ function SessionList(props: Props) {
|
|||
|
||||
useTimeout(() => {
|
||||
if (!document.hidden) {
|
||||
props.fetchSessions(null, true);
|
||||
props.checkForLatestSessions();
|
||||
}
|
||||
}, AUTOREFRESH_INTERVAL);
|
||||
|
||||
|
|
@ -107,7 +110,7 @@ function SessionList(props: Props) {
|
|||
|
||||
sessionTimeOut = setTimeout(function () {
|
||||
if (!document.hidden) {
|
||||
props.fetchSessions(null, true);
|
||||
props.checkForLatestSessions();
|
||||
}
|
||||
}, 5000);
|
||||
};
|
||||
|
|
@ -182,15 +185,15 @@ function SessionList(props: Props) {
|
|||
{total > 0 && (
|
||||
<div className="flex items-center justify-between p-5">
|
||||
<div>
|
||||
Showing <span className="font-medium">{(currentPage - 1) * PER_PAGE + 1}</span> to{' '}
|
||||
<span className="font-medium">{(currentPage - 1) * PER_PAGE + list.size}</span> of{' '}
|
||||
Showing <span className="font-medium">{(currentPage - 1) * pageSize + 1}</span> to{' '}
|
||||
<span className="font-medium">{(currentPage - 1) * pageSize + list.size}</span> of{' '}
|
||||
<span className="font-medium">{numberWithCommas(total)}</span> sessions.
|
||||
</div>
|
||||
<Pagination
|
||||
page={currentPage}
|
||||
totalPages={Math.ceil(total / PER_PAGE)}
|
||||
totalPages={Math.ceil(total / pageSize)}
|
||||
onPageChange={(page) => props.updateCurrentPage(page)}
|
||||
limit={PER_PAGE}
|
||||
limit={pageSize}
|
||||
debounceRequest={1000}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -210,7 +213,15 @@ export default connect(
|
|||
total: state.getIn(['sessions', 'total']) || 0,
|
||||
scrollY: state.getIn(['search', 'scrollY']),
|
||||
activeTab: state.getIn(['search', 'activeTab']),
|
||||
pageSize: state.getIn(['search', 'pageSize']),
|
||||
isEnterprise: state.getIn(['user', 'account', 'edition']) === 'ee',
|
||||
}),
|
||||
{ updateCurrentPage, addFilterByKeyAndValue, setScrollPosition, fetchSessions, fetchMetadata }
|
||||
{
|
||||
updateCurrentPage,
|
||||
addFilterByKeyAndValue,
|
||||
setScrollPosition,
|
||||
fetchSessions,
|
||||
fetchMetadata,
|
||||
checkForLatestSessions,
|
||||
}
|
||||
)(SessionList);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,10 @@ function XRayButton(props: Props) {
|
|||
const { player: Player } = React.useContext(PlayerContext);
|
||||
|
||||
const { isActive } = props;
|
||||
const [showGuide, setShowGuide] = useState(!localStorage.getItem(FEATURE_KEYS.XRAY));
|
||||
// const [showGuide, setShowGuide] = useState(!localStorage.getItem(FEATURE_KEYS.XRAY));
|
||||
const showGuide = false;
|
||||
const setShowGuide = (anyt: any) => anyt;
|
||||
|
||||
useEffect(() => {
|
||||
if (!showGuide) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -5,16 +5,18 @@ import { array, success, createListUpdater, mergeReducers } from './funcTools/to
|
|||
import Filter from 'Types/filter';
|
||||
import SavedFilter from 'Types/filter/savedFilter';
|
||||
import { errors as errorsRoute, isRoute } from 'App/routes';
|
||||
import { fetchList as fetchSessionList } from './sessions';
|
||||
import { fetchList as fetchSessionList, fetchAutoplayList } from './sessions';
|
||||
import { fetchList as fetchErrorsList } from './errors';
|
||||
import { FilterCategory, FilterKey } from 'Types/filter/filterType';
|
||||
import { filtersMap, liveFiltersMap, generateFilterOptions } from 'Types/filter/newFilter';
|
||||
import { DURATION_FILTER } from 'App/constants/storageKeys';
|
||||
import Period, { CUSTOM_RANGE } from 'Types/app/period';
|
||||
|
||||
const ERRORS_ROUTE = errorsRoute();
|
||||
|
||||
const name = 'search';
|
||||
const idKey = 'searchId';
|
||||
const PER_PAGE = 10;
|
||||
|
||||
const FETCH_LIST = fetchListType(name);
|
||||
const FETCH_FILTER_SEARCH = fetchListType(`${name}/FILTER_SEARCH`);
|
||||
|
|
@ -33,25 +35,30 @@ const SET_ACTIVE_TAB = `${name}/SET_ACTIVE_TAB`;
|
|||
const SET_SCROLL_POSITION = `${name}/SET_SCROLL_POSITION`;
|
||||
|
||||
const REFRESH_FILTER_OPTIONS = 'filters/REFRESH_FILTER_OPTIONS';
|
||||
const CHECK_LATEST = fetchListType(`${name}/CHECK_LATEST`);
|
||||
const UPDATE_LATEST_REQUEST_TIME = 'filters/UPDATE_LATEST_REQUEST_TIME'
|
||||
|
||||
function chartWrapper(chart = []) {
|
||||
return chart.map((point) => ({ ...point, count: Math.max(point.count, 0) }));
|
||||
}
|
||||
// function chartWrapper(chart = []) {
|
||||
// return chart.map((point) => ({ ...point, count: Math.max(point.count, 0) }));
|
||||
// }
|
||||
|
||||
const savedSearchIdKey = 'searchId';
|
||||
const updateItemInList = createListUpdater(savedSearchIdKey);
|
||||
const updateInstance = (state, instance) =>
|
||||
state.getIn(['savedSearch', savedSearchIdKey]) === instance[savedSearchIdKey] ? state.mergeIn(['savedSearch'], SavedFilter(instance)) : state;
|
||||
// const savedSearchIdKey = 'searchId';
|
||||
// const updateItemInList = createListUpdater(savedSearchIdKey);
|
||||
// const updateInstance = (state, instance) =>
|
||||
// state.getIn(['savedSearch', savedSearchIdKey]) === instance[savedSearchIdKey] ? state.mergeIn(['savedSearch'], SavedFilter(instance)) : state;
|
||||
|
||||
const initialState = Map({
|
||||
filterList: generateFilterOptions(filtersMap),
|
||||
filterListLive: generateFilterOptions(liveFiltersMap),
|
||||
list: List(),
|
||||
latestRequestTime: null,
|
||||
latestList: List(),
|
||||
alertMetricId: null,
|
||||
instance: new Filter({ filters: [] }),
|
||||
savedSearch: new SavedFilter({}),
|
||||
filterSearchList: {},
|
||||
currentPage: 1,
|
||||
pageSize: PER_PAGE,
|
||||
activeTab: { name: 'All', type: 'all' },
|
||||
scrollY: 0,
|
||||
});
|
||||
|
|
@ -73,6 +80,10 @@ function reducer(state = initialState, action = {}) {
|
|||
'list',
|
||||
List(data.map(SavedFilter)).sortBy((i) => i.searchId)
|
||||
);
|
||||
case UPDATE_LATEST_REQUEST_TIME:
|
||||
return state.set('latestRequestTime', Date.now()).set('latestList', [])
|
||||
case success(CHECK_LATEST):
|
||||
return state.set('latestList', action.data)
|
||||
case success(FETCH_FILTER_SEARCH):
|
||||
const groupedList = action.data.reduce((acc, item) => {
|
||||
const { projectId, type, value } = item;
|
||||
|
|
@ -131,52 +142,69 @@ export const filterMap = ({ category, value, key, operator, sourceOperator, sour
|
|||
filters: filters ? filters.map(filterMap) : [],
|
||||
});
|
||||
|
||||
|
||||
const getFilters = (state) => {
|
||||
const filter = state.getIn(['search', 'instance']).toData();
|
||||
const activeTab = state.getIn(['search', 'activeTab']);
|
||||
if (activeTab.type !== 'all' && activeTab.type !== 'bookmark' && activeTab.type !== 'vault') {
|
||||
const tmpFilter = filtersMap[FilterKey.ISSUE];
|
||||
tmpFilter.value = [activeTab.type];
|
||||
filter.filters = filter.filters.concat(tmpFilter);
|
||||
}
|
||||
|
||||
if (activeTab.type === 'bookmark' || activeTab.type === 'vault') {
|
||||
filter.bookmarked = true;
|
||||
}
|
||||
|
||||
filter.filters = filter.filters.map(filterMap);
|
||||
|
||||
// duration filter from local storage
|
||||
if (!filter.filters.find((f) => f.type === FilterKey.DURATION)) {
|
||||
const durationFilter = JSON.parse(localStorage.getItem(DURATION_FILTER) || '{"count": 0}');
|
||||
let durationValue = parseInt(durationFilter.count);
|
||||
if (durationValue > 0) {
|
||||
const value = [0];
|
||||
durationValue = durationFilter.countType === 'min' ? durationValue * 60 * 1000 : durationValue * 1000;
|
||||
if (durationFilter.operator === '<') {
|
||||
value[0] = durationValue;
|
||||
} else if (durationFilter.operator === '>') {
|
||||
value[1] = durationValue;
|
||||
}
|
||||
|
||||
filter.filters = filter.filters.concat({
|
||||
type: FilterKey.DURATION,
|
||||
operator: 'is',
|
||||
value,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
export const reduceThenFetchResource =
|
||||
(actionCreator) =>
|
||||
(...args) =>
|
||||
(dispatch, getState) => {
|
||||
dispatch(actionCreator(...args));
|
||||
const filter = getState().getIn(['search', 'instance']).toData();
|
||||
|
||||
const activeTab = getState().getIn(['search', 'activeTab']);
|
||||
|
||||
if (activeTab.type === 'notes') return;
|
||||
if (activeTab.type !== 'all' && activeTab.type !== 'bookmark' && activeTab.type !== 'vault') {
|
||||
const tmpFilter = filtersMap[FilterKey.ISSUE];
|
||||
tmpFilter.value = [activeTab.type];
|
||||
filter.filters = filter.filters.concat(tmpFilter);
|
||||
}
|
||||
|
||||
if (activeTab.type === 'bookmark' || activeTab.type === 'vault') {
|
||||
filter.bookmarked = true;
|
||||
}
|
||||
|
||||
filter.filters = filter.filters.map(filterMap);
|
||||
filter.limit = 10;
|
||||
|
||||
const filter = getFilters(getState());
|
||||
filter.limit = PER_PAGE;
|
||||
filter.page = getState().getIn(['search', 'currentPage']);
|
||||
|
||||
const forceFetch = filter.filters.length === 0 || args[1] === true;
|
||||
|
||||
// duration filter from local storage
|
||||
if (!filter.filters.find((f) => f.type === FilterKey.DURATION)) {
|
||||
const durationFilter = JSON.parse(localStorage.getItem(DURATION_FILTER) || '{"count": 0}');
|
||||
let durationValue = parseInt(durationFilter.count);
|
||||
if (durationValue > 0) {
|
||||
const value = [0];
|
||||
durationValue = durationFilter.countType === 'min' ? durationValue * 60 * 1000 : durationValue * 1000;
|
||||
if (durationFilter.operator === '<') {
|
||||
value[0] = durationValue;
|
||||
} else if (durationFilter.operator === '>') {
|
||||
value[1] = durationValue;
|
||||
}
|
||||
|
||||
filter.filters = filter.filters.concat({
|
||||
type: FilterKey.DURATION,
|
||||
operator: 'is',
|
||||
value,
|
||||
});
|
||||
}
|
||||
// reset the timestamps to latest
|
||||
if (filter.rangeValue !== CUSTOM_RANGE) {
|
||||
const period = new Period({ rangeName: filter.rangeValue })
|
||||
const newTimestamps = period.toJSON();
|
||||
filter.startDate = newTimestamps.startDate
|
||||
filter.endDate = newTimestamps.endDate
|
||||
}
|
||||
|
||||
dispatch(updateLatestRequestTime())
|
||||
return isRoute(ERRORS_ROUTE, window.location.pathname) ? dispatch(fetchErrorsList(filter)) : dispatch(fetchSessionList(filter, forceFetch));
|
||||
};
|
||||
|
||||
|
|
@ -353,3 +381,33 @@ export const setScrollPosition = (scrollPosition) => {
|
|||
scrollPosition,
|
||||
};
|
||||
};
|
||||
|
||||
export const updateLatestRequestTime = () => {
|
||||
return {
|
||||
type: UPDATE_LATEST_REQUEST_TIME
|
||||
}
|
||||
}
|
||||
|
||||
export const checkForLatestSessions = () => (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const filter = getFilters(state);
|
||||
const latestRequestTime = state.getIn(['search', 'latestRequestTime'])
|
||||
if (!!latestRequestTime) {
|
||||
const period = new Period({ rangeName: CUSTOM_RANGE, start: latestRequestTime, end: Date.now() })
|
||||
const newTimestamps = period.toJSON();
|
||||
filter.startDate = newTimestamps.startDate
|
||||
filter.endDate = newTimestamps.endDate
|
||||
}
|
||||
|
||||
return dispatch({
|
||||
types: array(CHECK_LATEST),
|
||||
call: (client) => client.post(`/sessions/search/ids`, filter),
|
||||
});
|
||||
}
|
||||
|
||||
export const fetchAutoplaySessions = (page) => (dispatch, getState) => {
|
||||
const filter = getFilters(getState());
|
||||
filter.page = page;
|
||||
filter.limit = PER_PAGE;
|
||||
return dispatch(fetchAutoplayList(filter));
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ import { getDateRangeFromValue } from 'App/dateRange';
|
|||
const name = 'sessions';
|
||||
const INIT = 'sessions/INIT';
|
||||
const FETCH_LIST = new RequestTypes('sessions/FETCH_LIST');
|
||||
const FETCH_AUTOPLAY_LIST = new RequestTypes('sessions/FETCH_AUTOPLAY_LIST');
|
||||
const FETCH = new RequestTypes('sessions/FETCH');
|
||||
const FETCH_FAVORITE_LIST = new RequestTypes('sessions/FETCH_FAVORITE_LIST');
|
||||
const FETCH_LIVE_LIST = new RequestTypes('sessions/FETCH_LIVE_LIST');
|
||||
|
|
@ -96,6 +97,10 @@ const reducer = (state = initialState, action = {}) => {
|
|||
list.filter(({ favorite }) => favorite)
|
||||
)
|
||||
.set('total', total);
|
||||
case FETCH_AUTOPLAY_LIST.SUCCESS:
|
||||
let sessionIds = state.get('sessionIds');
|
||||
sessionIds = sessionIds.concat(action.data.map(i => i.sessionId + ''))
|
||||
return state.set('sessionIds', sessionIds.filter((i, index) => sessionIds.indexOf(i) === index ))
|
||||
case SET_AUTOPLAY_VALUES: {
|
||||
const sessionIds = state.get('sessionIds');
|
||||
const currentSessionId = state.get('current').sessionId;
|
||||
|
|
@ -257,7 +262,7 @@ function init(session) {
|
|||
|
||||
export const fetchList =
|
||||
(params = {}, force = false) =>
|
||||
(dispatch, getState) => {
|
||||
(dispatch) => {
|
||||
if (!force) { // compare with the last fetched filter
|
||||
const oldFilters = getSessionFilter();
|
||||
if (compareJsonObjects(oldFilters, cleanSessionFilters(params))) {
|
||||
|
|
@ -273,6 +278,19 @@ export const fetchList =
|
|||
});
|
||||
};
|
||||
|
||||
export const fetchAutoplayList =
|
||||
(params = {}) =>
|
||||
(dispatch) => {
|
||||
setSessionFilter(cleanSessionFilters(params));
|
||||
return dispatch({
|
||||
types: FETCH_AUTOPLAY_LIST.toArray(),
|
||||
call: (client) => client.post('/sessions/search/ids', params),
|
||||
params: cleanParams(params),
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
export function fetchErrorStackList(sessionId, errorId) {
|
||||
return {
|
||||
types: FETCH_ERROR_STACK.toArray(),
|
||||
|
|
@ -436,4 +454,4 @@ export function updateLastPlayedSession(sessionId) {
|
|||
type: LAST_PLAYED_SESSION_ID,
|
||||
sessionId,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
import Record from 'Types/Record';
|
||||
import { List } from 'immutable';
|
||||
import Watchdog from 'Types/watchdog'
|
||||
|
||||
export const issues_types = List([
|
||||
{ 'type': 'all', 'visible': true, 'order': 0, 'name': 'All', 'icon': '' },
|
||||
{ 'type': 'js_exception', 'visible': true, 'order': 1, 'name': 'Errors', 'icon': 'funnel/exclamation-circle' },
|
||||
{ 'type': 'click_rage', 'visible': true, 'order': 2, 'name': 'Click Rage', 'icon': 'funnel/emoji-angry' },
|
||||
{ 'type': 'crash', 'visible': true, 'order': 3, 'name': 'Crashes', 'icon': 'funnel/file-earmark-break' },
|
||||
{ 'type': 'memory', 'visible': true, 'order': 4, 'name': 'High Memory', 'icon': 'funnel/sd-card' },
|
||||
{ 'type': 'bad_request', 'visible': true, 'order': 2, 'name': 'Bad Requests', 'icon': 'funnel/file-medical-alt' },
|
||||
{ 'type': 'click_rage', 'visible': true, 'order': 3, 'name': 'Click Rage', 'icon': 'funnel/emoji-angry' },
|
||||
{ 'type': 'crash', 'visible': true, 'order': 4, 'name': 'Crashes', 'icon': 'funnel/file-earmark-break' },
|
||||
// { 'type': 'memory', 'visible': true, 'order': 4, 'name': 'High Memory', 'icon': 'funnel/sd-card' },
|
||||
// { 'type': 'vault', 'visible': true, 'order': 5, 'name': 'Vault', 'icon': 'safe' },
|
||||
// { 'type': 'bookmark', 'visible': true, 'order': 5, 'name': 'Bookmarks', 'icon': 'safe' },
|
||||
// { 'type': 'bad_request', 'visible': true, 'order': 1, 'name': 'Bad Requests', 'icon': 'funnel/file-medical-alt' },
|
||||
|
|
|
|||
|
|
@ -143,5 +143,6 @@ clickhouse:
|
|||
postgreql:
|
||||
enabled: true
|
||||
|
||||
# For enterpriseEdition Only
|
||||
vault:
|
||||
enabled: false
|
||||
|
|
|
|||
|
|
@ -67,6 +67,8 @@ usr=`whoami`
|
|||
fi
|
||||
}
|
||||
|
||||
sleep 10
|
||||
|
||||
# ## Installing openssl
|
||||
# sudo apt update &> /dev/null
|
||||
# sudo apt install openssl -y &> /dev/null
|
||||
|
|
@ -106,6 +108,7 @@ sed_i_wrapper -i "s/accessKey: \"changeMeMinioAccessKey\"/accessKey: \"$(randomP
|
|||
sed_i_wrapper -i "s/secretKey: \"changeMeMinioPassword\"/secretKey: \"$(randomPass)\"/g" vars.yaml
|
||||
sed_i_wrapper -i "s/jwt_secret: \"SetARandomStringHere\"/jwt_secret: \"$(randomPass)\"/g" vars.yaml
|
||||
sed_i_wrapper -i "s/assistKey: \"SetARandomStringHere\"/assistKey: \"$(randomPass)\"/g" vars.yaml
|
||||
sed_i_wrapper -i "s/assistJWTSecret: \"SetARandomStringHere\"/assistJWTSecret: \"$(randomPass)\"/g" vars.yaml
|
||||
sed_i_wrapper -i "s/domainName: \"\"/domainName: \"${DOMAIN_NAME}\"/g" vars.yaml
|
||||
|
||||
info "Setting proper permission for shared folder"
|
||||
|
|
|
|||
|
|
@ -51,22 +51,47 @@ spec:
|
|||
value: "5432"
|
||||
- name: pg_dbname
|
||||
value: "{{ .Values.global.postgresql.postgresqlDatabase }}"
|
||||
- name: ch_host
|
||||
value: "{{ .Values.global.clickhouse.chHost }}"
|
||||
- name: ch_port
|
||||
value: "{{ .Values.global.clickhouse.service.webPort }}"
|
||||
- name: pg_user
|
||||
value: '{{ .Values.global.postgresql.postgresqlUser }}'
|
||||
- name: pg_password
|
||||
{{- if .Values.global.postgresql.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.postgresql.existingSecret }}
|
||||
key: postgresql-postgres-password
|
||||
{{- else }}
|
||||
value: '{{ .Values.global.postgresql.postgresqlPassword }}'
|
||||
{{- end}}
|
||||
- name: SITE_URL
|
||||
value: 'https://{{ .Values.global.domainName }}'
|
||||
- name: S3_HOST
|
||||
{{- if eq .Values.global.s3.endpoint "http://minio.db.svc.cluster.local:9000" }}
|
||||
{{- if contains "minio" .Values.global.s3.endpoint }}
|
||||
value: 'https://{{ .Values.global.domainName }}:{{ .Values.global.ingress.controller.service.ports.https}}'
|
||||
{{- else}}
|
||||
value: '{{ .Values.global.s3.endpoint }}'
|
||||
{{- end}}
|
||||
- name: S3_KEY
|
||||
{{- if .Values.global.s3.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.s3.existingSecret }}
|
||||
key: access-key
|
||||
{{- else }}
|
||||
value: {{ .Values.global.s3.accessKey }}
|
||||
{{- end }}
|
||||
- name: S3_SECRET
|
||||
{{- if .Values.global.s3.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.s3.existingSecret }}
|
||||
key: secret-key
|
||||
{{- else }}
|
||||
value: {{ .Values.global.s3.secretKey }}
|
||||
{{- end }}
|
||||
- name: AWS_DEFAULT_REGION
|
||||
value: '{{ .Values.global.s3.region }}'
|
||||
- name: EMAIL_HOST
|
||||
|
|
|
|||
|
|
@ -98,8 +98,6 @@ autoscaling:
|
|||
# targetMemoryUtilizationPercentage: 80
|
||||
|
||||
env:
|
||||
ch_host: clickhouse-openreplay-clickhouse.db.svc.cluster.local
|
||||
ch_port: 9000
|
||||
PYTHONUNBUFFERED: '0'
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -44,9 +44,23 @@ spec:
|
|||
{{- end}}
|
||||
env:
|
||||
- name: AWS_ACCESS_KEY_ID
|
||||
{{- if .Values.global.s3.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.s3.existingSecret }}
|
||||
key: access-key
|
||||
{{- else }}
|
||||
value: {{ .Values.global.s3.accessKey }}
|
||||
{{- end }}
|
||||
- name: AWS_SECRET_ACCESS_KEY
|
||||
{{- if .Values.global.s3.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.s3.existingSecret }}
|
||||
key: secret-key
|
||||
{{- else }}
|
||||
value: {{ .Values.global.s3.secretKey }}
|
||||
{{- end }}
|
||||
- name: S3_BUCKET_ASSETS
|
||||
value: {{ .Values.global.s3.assetsBucket }}
|
||||
- name: LICENSE_KEY
|
||||
|
|
@ -69,7 +83,7 @@ spec:
|
|||
# 4. Using AWS itself.
|
||||
# AWS uses bucketname.endpoint/object while others use endpoint/bucketname/object
|
||||
- name: ASSETS_ORIGIN
|
||||
{{- if eq .Values.global.s3.endpoint "http://minio.db.svc.cluster.local:9000" }}
|
||||
{{- if contains "minio" .Values.global.s3.endpoint }}
|
||||
# Local minio Installation
|
||||
value: 'https://{{ .Values.global.domainName }}:{{.Values.global.ingress.controller.service.ports.https}}/{{.Values.global.s3.assetsBucket}}'
|
||||
{{- else if contains "amazonaws.com" .Values.global.s3.endpoint }}
|
||||
|
|
|
|||
|
|
@ -50,15 +50,31 @@ spec:
|
|||
- name: AWS_DEFAULT_REGION
|
||||
value: "{{ .Values.global.s3.region }}"
|
||||
- name: S3_HOST
|
||||
{{- if eq .Values.global.s3.endpoint "http://minio.db.svc.cluster.local:9000" }}
|
||||
{{- if contains "minio" .Values.global.s3.endpoint }}
|
||||
value: 'https://{{ .Values.global.domainName }}:{{ .Values.global.ingress.controller.service.ports.https}}'
|
||||
{{- else}}
|
||||
value: '{{ .Values.global.s3.endpoint }}'
|
||||
{{- end}}
|
||||
- name: S3_KEY
|
||||
{{- if .Values.global.s3.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.s3.existingSecret }}
|
||||
key: access-key
|
||||
{{- else }}
|
||||
value: {{ .Values.global.s3.accessKey }}
|
||||
{{- end }}
|
||||
- name: S3_SECRET
|
||||
{{- if .Values.global.s3.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.s3.existingSecret }}
|
||||
key: secret-key
|
||||
{{- else }}
|
||||
value: {{ .Values.global.s3.secretKey }}
|
||||
{{- end }}
|
||||
- name: REDIS_URL
|
||||
value: {{ .Values.global.redis.redisHost }}
|
||||
{{- range $key, $val := .Values.env }}
|
||||
- name: {{ $key }}
|
||||
value: '{{ $val }}'
|
||||
|
|
|
|||
|
|
@ -94,7 +94,6 @@ autoscaling:
|
|||
# targetMemoryUtilizationPercentage: 80
|
||||
|
||||
env:
|
||||
REDIS_URL: "redis://redis-master.db.svc.cluster.local:6379"
|
||||
debug: 0
|
||||
uws: false
|
||||
redis: false
|
||||
|
|
|
|||
|
|
@ -43,6 +43,14 @@ spec:
|
|||
{{- .Values.healthCheck | toYaml | nindent 10}}
|
||||
{{- end}}
|
||||
env:
|
||||
- name: ch_host
|
||||
value: "{{ .Values.global.clickhouse.chHost }}"
|
||||
- name: ch_port
|
||||
value: "{{ .Values.global.clickhouse.service.webPort }}"
|
||||
- name: sourcemaps_reader
|
||||
value: "http://sourcemaps-reader-openreplay.{{.Release.Namespace}}.{{.Values.global.clusterDomain}}:9000/sourcemaps/%s/sourcemaps"
|
||||
- name: ASSIST_URL
|
||||
value: "http://assist-openreplay.{{.Release.Namespace}}.{{.Values.global.clusterDomain}}:9001/assist/%s"
|
||||
- name: ASSIST_JWT_SECRET
|
||||
value: {{ .Values.global.assistJWTSecret }}
|
||||
- name: ASSIST_KEY
|
||||
|
|
@ -60,19 +68,40 @@ spec:
|
|||
- name: pg_user
|
||||
value: '{{ .Values.global.postgresql.postgresqlUser }}'
|
||||
- name: pg_password
|
||||
{{- if .Values.global.postgresql.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.postgresql.existingSecret }}
|
||||
key: postgresql-postgres-password
|
||||
{{- else }}
|
||||
value: '{{ .Values.global.postgresql.postgresqlPassword }}'
|
||||
{{- end}}
|
||||
- name: SITE_URL
|
||||
value: 'https://{{ .Values.global.domainName }}'
|
||||
- name: S3_HOST
|
||||
{{- if eq .Values.global.s3.endpoint "http://minio.db.svc.cluster.local:9000" }}
|
||||
{{- if contains "minio" .Values.global.s3.endpoint }}
|
||||
value: 'https://{{ .Values.global.domainName }}:{{ .Values.global.ingress.controller.service.ports.https}}'
|
||||
{{- else}}
|
||||
value: '{{ .Values.global.s3.endpoint }}'
|
||||
{{- end}}
|
||||
- name: S3_KEY
|
||||
{{- if .Values.global.s3.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.s3.existingSecret }}
|
||||
key: access-key
|
||||
{{- else }}
|
||||
value: {{ .Values.global.s3.accessKey }}
|
||||
{{- end }}
|
||||
- name: S3_SECRET
|
||||
{{- if .Values.global.s3.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.s3.existingSecret }}
|
||||
key: secret-key
|
||||
{{- else }}
|
||||
value: {{ .Values.global.s3.secretKey }}
|
||||
{{- end }}
|
||||
- name: AWS_DEFAULT_REGION
|
||||
value: '{{ .Values.global.s3.region }}'
|
||||
- name: sessions_region
|
||||
|
|
|
|||
|
|
@ -91,8 +91,6 @@ autoscaling:
|
|||
# targetMemoryUtilizationPercentage: 80
|
||||
|
||||
env:
|
||||
ch_host: clickhouse-openreplay-clickhouse.db.svc.cluster.local
|
||||
ch_port: 9000
|
||||
captcha_server: ''
|
||||
captcha_key: ''
|
||||
async_Token: ''
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ spec:
|
|||
{{- .Values.healthCheck | toYaml | nindent 10}}
|
||||
{{- end}}
|
||||
env:
|
||||
- name: CLICKHOUSE_STRING
|
||||
value: '{{ .Values.global.clickhouse.chHost }}:{{.Values.global.clickhouse.service.webPort}}/{{.Values.env.ch_db}}'
|
||||
- name: LICENSE_KEY
|
||||
value: '{{ .Values.global.enterpriseEditionLicense }}'
|
||||
- name: REDIS_STRING
|
||||
|
|
@ -51,10 +53,19 @@ spec:
|
|||
value: '{{ .Values.global.kafka.kafkaHost }}:{{ .Values.global.kafka.kafkaPort }}'
|
||||
- name: KAFKA_USE_SSL
|
||||
value: '{{ .Values.global.kafka.kafkaUseSsl }}'
|
||||
- name: POSTGRES_STRING
|
||||
value: 'postgres://{{ .Values.global.postgresql.postgresqlUser }}:{{ .Values.global.postgresql.postgresqlPassword }}@{{ .Values.global.postgresql.postgresqlHost }}:{{ .Values.global.postgresql.postgresqlPort }}/{{ .Values.global.postgresql.postgresqlDatabase }}'
|
||||
- name: pg_password
|
||||
{{- if .Values.global.postgresql.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.postgresql.existingSecret }}
|
||||
key: postgresql-postgres-password
|
||||
{{- else }}
|
||||
value: '{{ .Values.global.postgresql.postgresqlPassword }}'
|
||||
{{- end}}
|
||||
- name: QUICKWIT_ENABLED
|
||||
value: '{{ .Values.global.quickwit.enabled }}'
|
||||
- name: POSTGRES_STRING
|
||||
value: 'postgres://{{ .Values.global.postgresql.postgresqlUser }}:$(pg_password)@{{ .Values.global.postgresql.postgresqlHost }}:{{ .Values.global.postgresql.postgresqlPort }}/{{ .Values.global.postgresql.postgresqlDatabase }}'
|
||||
{{- range $key, $val := .Values.env }}
|
||||
- name: {{ $key }}
|
||||
value: '{{ $val }}'
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ autoscaling:
|
|||
# targetMemoryUtilizationPercentage: 80
|
||||
|
||||
env:
|
||||
CLICKHOUSE_STRING: tcp://clickhouse-openreplay-clickhouse.db.svc.cluster.local:9000/default
|
||||
ch_db: default
|
||||
|
||||
|
||||
nodeSelector: {}
|
||||
|
|
|
|||
|
|
@ -51,8 +51,17 @@ spec:
|
|||
value: '{{ .Values.global.kafka.kafkaHost }}:{{ .Values.global.kafka.kafkaPort }}'
|
||||
- name: KAFKA_USE_SSL
|
||||
value: '{{ .Values.global.kafka.kafkaUseSsl }}'
|
||||
- name: pg_password
|
||||
{{- if .Values.global.postgresql.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.postgresql.existingSecret }}
|
||||
key: postgresql-postgres-password
|
||||
{{- else }}
|
||||
value: '{{ .Values.global.postgresql.postgresqlPassword }}'
|
||||
{{- end}}
|
||||
- name: POSTGRES_STRING
|
||||
value: 'postgres://{{ .Values.global.postgresql.postgresqlUser }}:{{ .Values.global.postgresql.postgresqlPassword }}@{{ .Values.global.postgresql.postgresqlHost }}:{{ .Values.global.postgresql.postgresqlPort }}/{{ .Values.global.postgresql.postgresqlDatabase }}'
|
||||
value: 'postgres://{{ .Values.global.postgresql.postgresqlUser }}:$(pg_password)@{{ .Values.global.postgresql.postgresqlHost }}:{{ .Values.global.postgresql.postgresqlPort }}/{{ .Values.global.postgresql.postgresqlDatabase }}'
|
||||
{{- range $key, $val := .Values.env }}
|
||||
- name: {{ $key }}
|
||||
value: '{{ $val }}'
|
||||
|
|
|
|||
|
|
@ -44,9 +44,23 @@ spec:
|
|||
{{- end}}
|
||||
env:
|
||||
- name: AWS_ACCESS_KEY_ID
|
||||
{{- if .Values.global.s3.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.s3.existingSecret }}
|
||||
key: access-key
|
||||
{{- else }}
|
||||
value: {{ .Values.global.s3.accessKey }}
|
||||
{{- end }}
|
||||
- name: AWS_SECRET_ACCESS_KEY
|
||||
{{- if .Values.global.s3.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.s3.existingSecret }}
|
||||
key: secret-key
|
||||
{{- else }}
|
||||
value: {{ .Values.global.s3.secretKey }}
|
||||
{{- end }}
|
||||
- name: AWS_REGION
|
||||
value: '{{ .Values.global.s3.region }}'
|
||||
- name: LICENSE_KEY
|
||||
|
|
@ -57,8 +71,17 @@ spec:
|
|||
value: '{{ .Values.global.kafka.kafkaHost }}:{{ .Values.global.kafka.kafkaPort }}'
|
||||
- name: KAFKA_USE_SSL
|
||||
value: '{{ .Values.global.kafka.kafkaUseSsl }}'
|
||||
- name: pg_password
|
||||
{{- if .Values.global.postgresql.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.postgresql.existingSecret }}
|
||||
key: postgresql-postgres-password
|
||||
{{- else }}
|
||||
value: '{{ .Values.global.postgresql.postgresqlPassword }}'
|
||||
{{- end}}
|
||||
- name: POSTGRES_STRING
|
||||
value: 'postgres://{{ .Values.global.postgresql.postgresqlUser }}:{{ .Values.global.postgresql.postgresqlPassword }}@{{ .Values.global.postgresql.postgresqlHost }}:{{ .Values.global.postgresql.postgresqlPort }}/{{ .Values.global.postgresql.postgresqlDatabase }}'
|
||||
value: 'postgres://{{ .Values.global.postgresql.postgresqlUser }}:$(pg_password)@{{ .Values.global.postgresql.postgresqlHost }}:{{ .Values.global.postgresql.postgresqlPort }}/{{ .Values.global.postgresql.postgresqlDatabase }}'
|
||||
# We need to check what is the object store endpoint.
|
||||
# There can be 4 options
|
||||
# 1. Using minio inside kube clster
|
||||
|
|
@ -67,7 +90,7 @@ spec:
|
|||
# 4. Using AWS itself.
|
||||
# AWS uses bucketname.endpoint/object while others use endpoint/bucketname/object
|
||||
- name: ASSETS_ORIGIN
|
||||
{{- if eq .Values.global.s3.endpoint "frontend://minio.db.svc.cluster.local:9000" }}
|
||||
{{- if contains "minio" .Values.global.s3.endpoint }}
|
||||
# Local minio Installation
|
||||
value: 'frontends://{{ .Values.global.domainName }}:{{.Values.global.ingress.controller.service.ports.https}}/{{.Values.global.s3.assetsBucket}}'
|
||||
{{- else if contains "amazonaws.com" .Values.global.s3.endpoint }}
|
||||
|
|
|
|||
|
|
@ -44,9 +44,23 @@ spec:
|
|||
{{- end}}
|
||||
env:
|
||||
- name: AWS_ACCESS_KEY_ID
|
||||
{{- if .Values.global.s3.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.s3.existingSecret }}
|
||||
key: access-key
|
||||
{{- else }}
|
||||
value: {{ .Values.global.s3.accessKey }}
|
||||
{{- end }}
|
||||
- name: AWS_SECRET_ACCESS_KEY
|
||||
{{- if .Values.global.s3.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.s3.existingSecret }}
|
||||
key: secret-key
|
||||
{{- else }}
|
||||
value: {{ .Values.global.s3.secretKey }}
|
||||
{{- end }}
|
||||
- name: AWS_REGION
|
||||
value: '{{ .Values.global.s3.region }}'
|
||||
- name: LICENSE_KEY
|
||||
|
|
@ -57,8 +71,17 @@ spec:
|
|||
value: '{{ .Values.global.kafka.kafkaHost }}:{{ .Values.global.kafka.kafkaPort }}'
|
||||
- name: KAFKA_USE_SSL
|
||||
value: '{{ .Values.global.kafka.kafkaUseSsl }}'
|
||||
- name: pg_password
|
||||
{{- if .Values.global.postgresql.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.postgresql.existingSecret }}
|
||||
key: postgresql-postgres-password
|
||||
{{- else }}
|
||||
value: '{{ .Values.global.postgresql.postgresqlPassword }}'
|
||||
{{- end}}
|
||||
- name: POSTGRES_STRING
|
||||
value: 'postgres://{{ .Values.global.postgresql.postgresqlUser }}:{{ .Values.global.postgresql.postgresqlPassword }}@{{ .Values.global.postgresql.postgresqlHost }}:{{ .Values.global.postgresql.postgresqlPort }}/{{ .Values.global.postgresql.postgresqlDatabase }}'
|
||||
value: 'postgres://{{ .Values.global.postgresql.postgresqlUser }}:$(pg_password)@{{ .Values.global.postgresql.postgresqlHost }}:{{ .Values.global.postgresql.postgresqlPort }}/{{ .Values.global.postgresql.postgresqlDatabase }}'
|
||||
# We need to check what is the object store endpoint.
|
||||
# There can be 4 options
|
||||
# 1. Using minio inside kube clster
|
||||
|
|
@ -67,7 +90,7 @@ spec:
|
|||
# 4. Using AWS itself.
|
||||
# AWS uses bucketname.endpoint/object while others use endpoint/bucketname/object
|
||||
- name: ASSETS_ORIGIN
|
||||
{{- if eq .Values.global.s3.endpoint "http://minio.db.svc.cluster.local:9000" }}
|
||||
{{- if contains "minio" .Values.global.s3.endpoint }}
|
||||
# Local minio Installation
|
||||
value: 'https://{{ .Values.global.domainName }}:{{.Values.global.ingress.controller.service.ports.https}}/{{.Values.global.s3.assetsBucket}}'
|
||||
{{- else if contains "amazonaws.com" .Values.global.s3.endpoint }}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ spec:
|
|||
path: /ingest/(.*)
|
||||
{{- end }}
|
||||
|
||||
{{- if eq .Values.global.s3.endpoint "http://minio.db.svc.cluster.local:9000" }}
|
||||
{{- if contains "minio" .Values.global.s3.endpoint }}
|
||||
## TODO:
|
||||
## Frontend service from minio will be migrated to nginx atomic container.
|
||||
## This ingress is just a workaround.
|
||||
|
|
@ -45,7 +45,7 @@ apiVersion: networking.k8s.io/v1
|
|||
kind: Ingress
|
||||
metadata:
|
||||
name: minio
|
||||
namespace: db
|
||||
namespace: "{{(split "." .Values.global.s3.endpoint)._1}}"
|
||||
spec:
|
||||
ingressClassName: "{{ tpl .Values.ingress.className . }}"
|
||||
rules:
|
||||
|
|
|
|||
|
|
@ -51,8 +51,17 @@ spec:
|
|||
value: '{{ .Values.global.kafka.kafkaHost }}:{{ .Values.global.kafka.kafkaPort }}'
|
||||
- name: KAFKA_USE_SSL
|
||||
value: '{{ .Values.global.kafka.kafkaUseSsl }}'
|
||||
- name: pg_password
|
||||
{{- if .Values.global.postgresql.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.postgresql.existingSecret }}
|
||||
key: postgresql-postgres-password
|
||||
{{- else }}
|
||||
value: '{{ .Values.global.postgresql.postgresqlPassword }}'
|
||||
{{- end}}
|
||||
- name: POSTGRES_STRING
|
||||
value: 'postgres://{{ .Values.global.postgresql.postgresqlUser }}:{{ .Values.global.postgresql.postgresqlPassword }}@{{ .Values.global.postgresql.postgresqlHost }}:{{ .Values.global.postgresql.postgresqlPort }}/{{ .Values.global.postgresql.postgresqlDatabase }}'
|
||||
value: 'postgres://{{ .Values.global.postgresql.postgresqlUser }}:$(pg_password)@{{ .Values.global.postgresql.postgresqlHost }}:{{ .Values.global.postgresql.postgresqlPort }}/{{ .Values.global.postgresql.postgresqlDatabase }}'
|
||||
{{- range $key, $val := .Values.env }}
|
||||
- name: {{ $key }}
|
||||
value: '{{ $val }}'
|
||||
|
|
|
|||
|
|
@ -46,7 +46,14 @@ spec:
|
|||
- name: ASSIST_KEY
|
||||
value: {{ .Values.global.assistKey }}
|
||||
- name: S3_KEY
|
||||
{{- if .Values.global.s3.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.s3.existingSecret }}
|
||||
key: access-key
|
||||
{{- else }}
|
||||
value: {{ .Values.global.s3.accessKey }}
|
||||
{{- end }}
|
||||
{{- range $key, $val := .Values.env }}
|
||||
- name: {{ $key }}
|
||||
value: '{{ $val }}'
|
||||
|
|
|
|||
|
|
@ -48,9 +48,8 @@ spec:
|
|||
env:
|
||||
- name: AWS_DEFAULT_REGION
|
||||
value: "{{ .Values.global.s3.region }}"
|
||||
{{- if eq .Values.global.s3.endpoint "http://minio.db.svc.cluster.local:9000" }}
|
||||
- name: QW_S3_ENDPOINT
|
||||
value: 'http://minio.db.svc.cluster.local:9000'
|
||||
value: '{{ .Values.global.s3.endpoint }}'
|
||||
{{- end}}
|
||||
- name: AWS_ACCESS_KEY_ID
|
||||
value: {{ .Values.global.s3.accessKey }}
|
||||
|
|
|
|||
|
|
@ -19,10 +19,8 @@ spec:
|
|||
env:
|
||||
- name: AWS_DEFAULT_REGION
|
||||
value: "{{ .Values.global.s3.region }}"
|
||||
{{- if eq .Values.global.s3.endpoint "http://minio.db.svc.cluster.local:9000" }}
|
||||
- name: QW_S3_ENDPOINT
|
||||
value: 'http://minio.db.svc.cluster.local:9000'
|
||||
{{- end}}
|
||||
value: '{{.Values.global.s3.endpoint}}'
|
||||
- name: AWS_ACCESS_KEY_ID
|
||||
value: {{ .Values.global.s3.accessKey }}
|
||||
- name: AWS_SECRET_ACCESS_KEY
|
||||
|
|
|
|||
|
|
@ -96,7 +96,6 @@ autoscaling:
|
|||
# targetMemoryUtilizationPercentage: 80
|
||||
|
||||
env:
|
||||
REDIS_URL: "redis://redis-master.db.svc.cluster.local:6379"
|
||||
debug: 0
|
||||
uws: false
|
||||
redis: false
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ spec:
|
|||
# 4. Using AWS itself.
|
||||
# AWS uses bucketname.endpoint/object while others use endpoint/bucketname/object
|
||||
- name: ASSETS_ORIGIN
|
||||
{{- if eq .Values.global.s3.endpoint "http://minio.db.svc.cluster.local:9000" }}
|
||||
{{- if contains "minio" .Values.global.s3.endpoint }}
|
||||
# Local minio Installation
|
||||
value: 'https://{{ .Values.global.domainName }}:{{.Values.global.ingress.controller.service.ports.https}}/{{.Values.global.s3.assetsBucket}}'
|
||||
{{- else if contains "amazonaws.com" .Values.global.s3.endpoint }}
|
||||
|
|
|
|||
|
|
@ -67,9 +67,9 @@ spec:
|
|||
# 4. Using AWS itself.
|
||||
# AWS uses bucketname.endpoint/object while others use endpoint/bucketname/object
|
||||
- name: ASSETS_ORIGIN
|
||||
{{- if eq .Values.global.s3.endpoint "sourcemapreader://minio.db.svc.cluster.local:9000" }}
|
||||
{{- if contains "minio" .Values.global.s3.endpoint }}
|
||||
# Local minio Installation
|
||||
value: 'sourcemapreaders://{{ .Values.global.domainName }}:{{.Values.global.controller.service.ports.https}}/{{.Values.global.s3.assetsBucket}}'
|
||||
value: 'sourcemapreaders://{{ .Values.global.domainName }}:{{.Values.global.ingress.controller.service.ports.https}}/{{.Values.global.s3.assetsBucket}}'
|
||||
{{- else if contains "amazonaws.com" .Values.global.s3.endpoint }}
|
||||
# AWS S3
|
||||
# Ref: sourcemapreaders://stackoverflow.com/questions/53634583/go-template-split-string-by-delimiter
|
||||
|
|
|
|||
|
|
@ -44,9 +44,23 @@ spec:
|
|||
{{- end}}
|
||||
env:
|
||||
- name: AWS_ACCESS_KEY_ID
|
||||
{{- if .Values.global.s3.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.s3.existingSecret }}
|
||||
key: access-key
|
||||
{{- else }}
|
||||
value: {{ .Values.global.s3.accessKey }}
|
||||
{{- end }}
|
||||
- name: AWS_SECRET_ACCESS_KEY
|
||||
{{- if .Values.global.s3.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.s3.existingSecret }}
|
||||
key: secret-key
|
||||
{{- else }}
|
||||
value: {{ .Values.global.s3.secretKey }}
|
||||
{{- end }}
|
||||
- name: AWS_ENDPOINT
|
||||
value: '{{ .Values.global.s3.endpoint }}'
|
||||
- name: AWS_REGION_WEB
|
||||
|
|
|
|||
|
|
@ -31,19 +31,40 @@ spec:
|
|||
- name: pg_user
|
||||
value: '{{ .Values.global.postgresql.postgresqlUser }}'
|
||||
- name: pg_password
|
||||
{{- if .Values.global.postgresql.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.postgresql.existingSecret }}
|
||||
key: postgresql-postgres-password
|
||||
{{- else }}
|
||||
value: '{{ .Values.global.postgresql.postgresqlPassword }}'
|
||||
{{- end}}
|
||||
- name: SITE_URL
|
||||
value: 'https://{{ .Values.global.domainName }}'
|
||||
- name: S3_HOST
|
||||
{{- if eq .Values.global.s3.endpoint "http://minio.db.svc.cluster.local:9000" }}
|
||||
{{- if contains "minio" .Values.global.s3.endpoint }}
|
||||
value: 'https://{{ .Values.global.domainName }}:{{ .Values.global.ingress.controller.service.ports.https}}'
|
||||
{{- else}}
|
||||
value: '{{ .Values.global.s3.endpoint }}'
|
||||
{{- end}}
|
||||
- name: S3_KEY
|
||||
{{- if .Values.global.s3.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.s3.existingSecret }}
|
||||
key: access-key
|
||||
{{- else }}
|
||||
value: {{ .Values.global.s3.accessKey }}
|
||||
{{- end }}
|
||||
- name: S3_SECRET
|
||||
{{- if .Values.global.s3.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.s3.existingSecret }}
|
||||
key: secret-key
|
||||
{{- else }}
|
||||
value: {{ .Values.global.s3.secretKey }}
|
||||
{{- end }}
|
||||
- name: AWS_DEFAULT_REGION
|
||||
value: '{{ .Values.global.s3.region }}'
|
||||
- name: sessions_region
|
||||
|
|
|
|||
|
|
@ -31,19 +31,40 @@ spec:
|
|||
- name: pg_user
|
||||
value: '{{ .Values.global.postgresql.postgresqlUser }}'
|
||||
- name: pg_password
|
||||
{{- if .Values.global.postgresql.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.postgresql.existingSecret }}
|
||||
key: postgresql-postgres-password
|
||||
{{- else }}
|
||||
value: '{{ .Values.global.postgresql.postgresqlPassword }}'
|
||||
{{- end}}
|
||||
- name: SITE_URL
|
||||
value: 'https://{{ .Values.global.domainName }}'
|
||||
- name: S3_HOST
|
||||
{{- if eq .Values.global.s3.endpoint "http://minio.db.svc.cluster.local:9000" }}
|
||||
{{- if contains "minio" .Values.global.s3.endpoint }}
|
||||
value: 'https://{{ .Values.global.domainName }}:{{ .Values.global.ingress.controller.service.ports.https}}'
|
||||
{{- else}}
|
||||
value: '{{ .Values.global.s3.endpoint }}'
|
||||
{{- end}}
|
||||
- name: S3_KEY
|
||||
{{- if .Values.global.s3.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.s3.existingSecret }}
|
||||
key: access-key
|
||||
{{- else }}
|
||||
value: {{ .Values.global.s3.accessKey }}
|
||||
{{- end }}
|
||||
- name: S3_SECRET
|
||||
{{- if .Values.global.s3.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.s3.existingSecret }}
|
||||
key: secret-key
|
||||
{{- else }}
|
||||
value: {{ .Values.global.s3.secretKey }}
|
||||
{{- end }}
|
||||
- name: AWS_DEFAULT_REGION
|
||||
value: '{{ .Values.global.s3.region }}'
|
||||
- name: sessions_region
|
||||
|
|
|
|||
|
|
@ -31,19 +31,40 @@ spec:
|
|||
- name: pg_user
|
||||
value: '{{ .Values.global.postgresql.postgresqlUser }}'
|
||||
- name: pg_password
|
||||
{{- if .Values.global.postgresql.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.postgresql.existingSecret }}
|
||||
key: postgresql-postgres-password
|
||||
{{- else }}
|
||||
value: '{{ .Values.global.postgresql.postgresqlPassword }}'
|
||||
{{- end}}
|
||||
- name: SITE_URL
|
||||
value: 'https://{{ .Values.global.domainName }}'
|
||||
- name: S3_HOST
|
||||
{{- if eq .Values.global.s3.endpoint "http://minio.db.svc.cluster.local:9000" }}
|
||||
{{- if contains "minio" .Values.global.s3.endpoint }}
|
||||
value: 'https://{{ .Values.global.domainName }}:{{ .Values.global.ingress.controller.service.ports.https}}'
|
||||
{{- else}}
|
||||
value: '{{ .Values.global.s3.endpoint }}'
|
||||
{{- end}}
|
||||
- name: S3_KEY
|
||||
{{- if .Values.global.s3.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.s3.existingSecret }}
|
||||
key: access-key
|
||||
{{- else }}
|
||||
value: {{ .Values.global.s3.accessKey }}
|
||||
{{- end }}
|
||||
- name: S3_SECRET
|
||||
{{- if .Values.global.s3.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.s3.existingSecret }}
|
||||
key: secret-key
|
||||
{{- else }}
|
||||
value: {{ .Values.global.s3.secretKey }}
|
||||
{{- end }}
|
||||
- name: AWS_DEFAULT_REGION
|
||||
value: '{{ .Values.global.s3.region }}'
|
||||
- name: sessions_region
|
||||
|
|
|
|||
|
|
@ -55,7 +55,6 @@ sessionsCleaner:
|
|||
# Common env values are from chalice for the crons
|
||||
chalice:
|
||||
env:
|
||||
ch_host: clickhouse-openreplay-clickhouse.db.svc.cluster.local
|
||||
ch_port: 9000
|
||||
captcha_server: ''
|
||||
captcha_key: ''
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ function migrate() {
|
|||
echo "Migrating clickhouse version $version"
|
||||
# For now, we can ignore the clickhouse db inject errors.
|
||||
# TODO: Better error handling in script
|
||||
clickhouse-client -h clickhouse-openreplay-clickhouse.db.svc.cluster.local --port 9000 --multiquery < ${clickhousedir}/${version}/${version}.sql || true
|
||||
clickhouse-client -h ${CH_HOST} --port ${CH_PORT} --multiquery < ${clickhousedir}/${version}/${version}.sql || true
|
||||
done
|
||||
}
|
||||
|
||||
|
|
@ -19,7 +19,7 @@ function init() {
|
|||
echo "Initializing clickhouse"
|
||||
for file in `ls ${clickhousedir}/create/*.sql`; do
|
||||
echo "Injecting $file"
|
||||
clickhouse-client -h clickhouse-openreplay-clickhouse.db.svc.cluster.local --port 9000 --multiquery < $file || true
|
||||
clickhouse-client -h ${CH_HOST} --port ${CH_PORT} --multiquery < $file || true
|
||||
done
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ cd /tmp
|
|||
|
||||
buckets=("mobs" "sessions-assets" "sourcemaps" "sessions-mobile-assets" "quickwit" "vault-data")
|
||||
|
||||
mc alias set minio http://minio.db.svc.cluster.local:9000 $MINIO_ACCESS_KEY $MINIO_SECRET_KEY
|
||||
|
||||
mc alias set minio $MINIO_HOST $MINIO_ACCESS_KEY $MINIO_SECRET_KEY
|
||||
|
||||
function init() {
|
||||
echo "Initializing minio"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ if [ "x$VERBOSE" == "x1" ]; then
|
|||
set -x
|
||||
fi
|
||||
|
||||
export VAULT_ADDR=http://databases-vault.db.svc.cluster.local:8200
|
||||
export VAULT_ADDR=${VAULT_ADDR}
|
||||
|
||||
|
||||
# Check vault is already initialized, if so return
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ spec:
|
|||
error_connection=1
|
||||
|
||||
while [ $exit_count -le 20 ];do
|
||||
nc -zv clickhouse-openreplay-clickhouse.db.svc.cluster.local 9000 -w 1
|
||||
nc -zv {{.Values.global.clickhouse.chHost}} 9000 -w 1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "[info] clickhouse is not up; retrying in 5 seconds"
|
||||
sleep 4
|
||||
|
|
@ -91,7 +91,14 @@ spec:
|
|||
- name: PGUSER
|
||||
value: "{{ .Values.global.postgresql.postgresqlUser }}"
|
||||
- name: PGPASSWORD
|
||||
value: "{{ .Values.global.postgresql.postgresqlPassword }}"
|
||||
{{- if .Values.global.postgresql.existingSecret }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.global.postgresql.existingSecret }}
|
||||
key: postgresql-postgres-password
|
||||
{{- else }}
|
||||
value: '{{ .Values.global.postgresql.postgresqlPassword }}'
|
||||
{{- end}}
|
||||
image: bitnami/postgresql:13.3.0-debian-10-r53
|
||||
command:
|
||||
- /bin/bash
|
||||
|
|
@ -103,7 +110,7 @@ spec:
|
|||
mountPath: /opt/openreplay
|
||||
- name: dbmigrationscript
|
||||
mountPath: /opt/migrations/
|
||||
{{- if eq .Values.global.s3.endpoint "http://minio.db.svc.cluster.local:9000" }}
|
||||
{{- if contains "minio" .Values.global.s3.endpoint }}
|
||||
- name: minio
|
||||
image: bitnami/minio:2020.10.9-debian-10-r6
|
||||
env:
|
||||
|
|
@ -119,6 +126,8 @@ spec:
|
|||
value: "{{ .Values.minio.global.minio.accessKey }}"
|
||||
- name: MINIO_SECRET_KEY
|
||||
value: "{{ .Values.minio.global.minio.secretKey }}"
|
||||
- name: MINIO_HOST
|
||||
value: "{{ .Values.global.s3.endpoint }}"
|
||||
command:
|
||||
- /bin/bash
|
||||
- /opt/migrations/dbops.sh
|
||||
|
|
@ -147,6 +156,8 @@ spec:
|
|||
value: "{{ .Values.global.postgresql.postgresqlUser }}"
|
||||
- name: PGPASSWORD
|
||||
value: "{{ .Values.global.postgresql.postgresqlPassword }}"
|
||||
- name: VAULT_ADDR
|
||||
value: "{{ .Values.global.vault.vaultHost }}"
|
||||
image: hashicorp/vault:1.12.0
|
||||
command:
|
||||
- /bin/sh
|
||||
|
|
@ -208,6 +219,10 @@ spec:
|
|||
value: "{{ .Values.fromVersion }}"
|
||||
- name: CHART_APP_VERSION
|
||||
value: "{{ .Chart.AppVersion }}"
|
||||
- name: CH_HOST
|
||||
value: "{{.Values.global.clickhouse.chHost}}"
|
||||
- name: CH_PORT
|
||||
value: "{{.Values.global.clickhouse.service.webPort}}"
|
||||
command:
|
||||
- /bin/bash
|
||||
- /opt/migrations/dbops.sh
|
||||
|
|
|
|||
|
|
@ -81,3 +81,26 @@ ingress-nginx:
|
|||
## repository:
|
||||
tag: "v1.3.0"
|
||||
digest: ""
|
||||
|
||||
# For enterpriseEdition Only
|
||||
vault: &vault
|
||||
vaultHost: databases-vault.db.svc.cluster.local:8200
|
||||
annotations:
|
||||
vault.hashicorp.com/agent-cache-enable: "true"
|
||||
vault.hashicorp.com/agent-inject: "true"
|
||||
vault.hashicorp.com/agent-inject-token: "true"
|
||||
vault.hashicorp.com/template-static-secret-render-interval: 2m
|
||||
# vault.hashicorp.com/log-level: debug
|
||||
vault.hashicorp.com/agent-run-as-same-user: "true"
|
||||
vault.hashicorp.com/agent-inject-command-processor.properties: |
|
||||
pkill -TERM openreplay
|
||||
vault.hashicorp.com/role: pgaccess
|
||||
vault.hashicorp.com/agent-inject-secret-processor.properties: database/creds/db-app
|
||||
vault.hashicorp.com/agent-inject-template-processor.properties: |
|
||||
{{- with secret "database/creds/db-app" -}}
|
||||
POSTGRES_STRING=postgres://{{.Data.username}}:{{.Data.password}}@postgresql.db.svc.cluster.local:5432/postgres
|
||||
{{- end -}}
|
||||
|
||||
global:
|
||||
vault: *vault
|
||||
clusterDomain: "svc.cluster.local"
|
||||
|
|
|
|||
|
|
@ -17,9 +17,12 @@ postgresql: &postgres
|
|||
# asdf
|
||||
# cpu: 2
|
||||
|
||||
clickhouse:
|
||||
clickhouse: &clickhouse
|
||||
# For enterpriseEdition
|
||||
enabled: false
|
||||
chHost: clickhouse-openreplay-clickhouse.db.svc.cluster.local
|
||||
service:
|
||||
webPort: 9000
|
||||
|
||||
quickwit: &quickwit
|
||||
# For enterpriseEdition
|
||||
|
|
@ -91,6 +94,7 @@ ingress-nginx: &ingress-nginx
|
|||
force-ssl-redirect: false
|
||||
proxy-body-size: 10m
|
||||
|
||||
|
||||
# Application specific variables
|
||||
global:
|
||||
ingress: *ingress-nginx
|
||||
|
|
@ -98,6 +102,8 @@ global:
|
|||
kafka: *kafka
|
||||
redis: *redis
|
||||
quickwit: *quickwit
|
||||
clickhouse: *clickhouse
|
||||
# Registry URL from where the OR images should be pulled.
|
||||
openReplayContainerRegistry: "public.ecr.aws/p1t3u8a3"
|
||||
# secret key to inject to assist and peers service
|
||||
assistKey: "SetARandomStringHere"
|
||||
|
|
@ -172,21 +178,3 @@ chalice:
|
|||
# cpu: 512m
|
||||
# memory: 2056Mi
|
||||
|
||||
# For enterpriseEdition Only
|
||||
vault:
|
||||
enabled: false
|
||||
annotations:
|
||||
vault.hashicorp.com/agent-cache-enable: "true"
|
||||
vault.hashicorp.com/agent-inject: "true"
|
||||
vault.hashicorp.com/agent-inject-token: "true"
|
||||
vault.hashicorp.com/template-static-secret-render-interval: 2m
|
||||
# vault.hashicorp.com/log-level: debug
|
||||
vault.hashicorp.com/agent-run-as-same-user: "true"
|
||||
vault.hashicorp.com/agent-inject-command-processor.properties: |
|
||||
pkill -TERM openreplay
|
||||
vault.hashicorp.com/role: pgaccess
|
||||
vault.hashicorp.com/agent-inject-secret-processor.properties: database/creds/db-app
|
||||
vault.hashicorp.com/agent-inject-template-processor.properties: |
|
||||
{{- with secret "database/creds/db-app" -}}
|
||||
POSTGRES_STRING=postgres://{{.Data.username}}:{{.Data.password}}@postgresql.db.svc.cluster.local:5432/postgres
|
||||
{{- end -}}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@openreplay/tracker",
|
||||
"description": "The OpenReplay tracker main package",
|
||||
"version": "4.1.7",
|
||||
"version": "4.1.8",
|
||||
"keywords": [
|
||||
"logging",
|
||||
"replay"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type Message from './messages.gen.js'
|
||||
import { Timestamp, Metadata, UserID } from './messages.gen.js'
|
||||
import { now, deprecationWarn } from '../utils.js'
|
||||
import { now, adjustTimeOrigin, deprecationWarn } from '../utils.js'
|
||||
import Nodes from './nodes.js'
|
||||
import Observer from './observer/top_observer.js'
|
||||
import Sanitizer from './sanitizer.js'
|
||||
|
|
@ -369,6 +369,7 @@ export default class App {
|
|||
this.sessionStorage.removeItem(this.options.session_reset_key)
|
||||
}
|
||||
}
|
||||
|
||||
private _start(startOpts: StartOptions = {}, resetByWorker = false): Promise<StartPromiseReturn> {
|
||||
if (!this.worker) {
|
||||
return Promise.resolve(UnsuccessfulStart('No worker found: perhaps, CSP is not set.'))
|
||||
|
|
@ -381,6 +382,7 @@ export default class App {
|
|||
)
|
||||
}
|
||||
this.activityState = ActivityState.Starting
|
||||
adjustTimeOrigin()
|
||||
|
||||
if (startOpts.sessionHash) {
|
||||
this.session.applySessionHash(startOpts.sessionHash)
|
||||
|
|
|
|||
|
|
@ -226,13 +226,13 @@ export default function (app: App, opts: Partial<Options>): void {
|
|||
paintBlocks === null
|
||||
? 0
|
||||
: calculateSpeedIndex(firstContentfulPaint || firstPaint, paintBlocks)
|
||||
const { domContentLoadedEventEnd, navigationStart } = performance.timing
|
||||
const timeToInteractive =
|
||||
interactiveWindowTickTime === null
|
||||
? Math.max(
|
||||
interactiveWindowStartTime,
|
||||
firstContentfulPaint,
|
||||
performance.timing.domContentLoadedEventEnd - performance.timing.navigationStart ||
|
||||
0,
|
||||
domContentLoadedEventEnd - navigationStart || 0,
|
||||
)
|
||||
: 0
|
||||
app.send(
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import type App from '../app/index.js'
|
||||
import { getTimeOrigin } from '../utils.js'
|
||||
import { SetPageLocation, SetViewportSize, SetPageVisibility } from '../app/messages.gen.js'
|
||||
|
||||
export default function (app: App): void {
|
||||
let url: string, width: number, height: number
|
||||
let navigationStart = performance.timing.navigationStart
|
||||
let navigationStart: number
|
||||
|
||||
const sendSetPageLocation = app.safe(() => {
|
||||
const { URL } = document
|
||||
|
|
@ -30,6 +31,7 @@ export default function (app: App): void {
|
|||
|
||||
app.attachStartCallback(() => {
|
||||
url = ''
|
||||
navigationStart = getTimeOrigin()
|
||||
width = height = -1
|
||||
sendSetPageLocation()
|
||||
sendSetViewportSize()
|
||||
|
|
|
|||
|
|
@ -6,12 +6,19 @@ export const IS_FIREFOX = IN_BROWSER && navigator.userAgent.match(/firefox|fxios
|
|||
|
||||
export const MAX_STR_LEN = 1e5
|
||||
|
||||
const navigationStart: number | false =
|
||||
IN_BROWSER && (performance.timing.navigationStart || performance.timeOrigin)
|
||||
// performance.now() is buggy in some browsers
|
||||
// Buggy to use `performance.timeOrigin || performance.timing.navigationStart`
|
||||
// https://github.com/mdn/content/issues/4713
|
||||
// Maybe move to timer/ticker
|
||||
let timeOrigin: number = IN_BROWSER ? Date.now() - performance.now() : 0
|
||||
export function adjustTimeOrigin() {
|
||||
timeOrigin = Date.now() - performance.now()
|
||||
}
|
||||
export function getTimeOrigin() {
|
||||
return timeOrigin
|
||||
}
|
||||
export const now: () => number =
|
||||
IN_BROWSER && performance.now() && navigationStart
|
||||
? () => Math.round(performance.now() + navigationStart)
|
||||
IN_BROWSER && !!performance.now
|
||||
? () => Math.round(performance.now() + timeOrigin)
|
||||
: () => Date.now()
|
||||
|
||||
export const stars: (str: string) => string =
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue