Compare commits

...

17 commits

Author SHA1 Message Date
nick-delirium
90510aa33b ui: fix double metric selection in list 2025-06-06 16:19:54 +02:00
GitHub Action
96a70f5d41 Increment frontend chart version to v1.22.42 2025-06-04 11:41:56 +02:00
rjshrjndrn
d4a13edcf0 fix(actions): frontend image with proper tag
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
2025-06-04 11:33:19 +02:00
GitHub Action
51fad91a22 Increment frontend chart version to v1.22.41 2025-06-04 10:48:50 +02:00
nick-delirium
36abcda1e1 ui: fix audioplayer start point 2025-06-04 10:39:08 +02:00
Mehdi Osman
dd5f464f73
Increment frontend chart version to v1.22.40 (#3479)
Co-authored-by: GitHub Action <action@github.com>
2025-06-03 16:22:12 +02:00
Delirium
f9ada41272
ui: recreate period on db visit (#3478) 2025-06-03 16:05:52 +02:00
rjshrjndrn
9e24a3583e feat(nginx): add integrations endpoint with CORS support
Add new /integrations/ location block that proxies requests to
integrations-openreplay:8080 service. Includes proper CORS headers
for cross-origin requests and WebSocket upgrade support.

- Rewrite /integrations/ path to root
- Configure proxy headers for forwarding
- Set connection timeouts for stability
- Add CORS headers for API access

Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
2025-06-02 10:55:50 +02:00
Taha Yassine Kraiem
0a3129d3cd fix(chalice): fixed JIRA integration 2025-05-30 15:25:41 +02:00
Mehdi Osman
99d61db9d9
Increment frontend chart version to v1.22.39 (#3460)
Co-authored-by: GitHub Action <action@github.com>
2025-05-30 15:07:29 +02:00
Delirium
133958622e
ui: fix alert create button (#3459) 2025-05-30 14:56:21 +02:00
GitHub Action
fb021f606f Increment frontend chart version to v1.22.38 2025-05-29 12:21:04 +02:00
rjshrjndrn
a2905fa8ed fix: move cd - command after git operations in patch workflow
Move the directory restoration command after the git operations to
ensure all git commands execute in the correct working directory
before returning to the previous directory.

Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
2025-05-29 12:16:28 +02:00
rjshrjndrn
beec2283fd refactor(ci): restructure patch-build workflow script
- Extract inline bash script into structured functions
- Add proper error handling with set -euo pipefail
- Improve variable scoping with readonly and local declarations
- Add descriptive function names and comments
- Fix shell quoting and parameter expansion
- Consolidate build logic into reusable functions
- Add proper cleanup of temporary files
- Improve readability and maintainability of the CI script

The refactored script maintains the same functionality while being
more robust and easier to understand.

Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
2025-05-29 12:16:28 +02:00
GitHub Action
6c8b55019e Increment frontend chart version 2025-05-29 10:29:46 +02:00
rjshrjndrn
e3e3e11227 fix(action): proper registry
Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>
2025-05-29 10:18:55 +02:00
Shekar Siri
c6f7de04cc Revert "fix(ui): new card data state is not updating"
This reverts commit 2921c17cbf.
2025-05-28 22:16:00 +02:00
10 changed files with 215 additions and 89 deletions

View file

@ -74,78 +74,168 @@ jobs:
MSAAS_REPO_CLONE_TOKEN: ${{ secrets.MSAAS_REPO_CLONE_TOKEN }} MSAAS_REPO_CLONE_TOKEN: ${{ secrets.MSAAS_REPO_CLONE_TOKEN }}
MSAAS_REPO_URL: ${{ secrets.MSAAS_REPO_URL }} MSAAS_REPO_URL: ${{ secrets.MSAAS_REPO_URL }}
MSAAS_REPO_FOLDER: /tmp/msaas MSAAS_REPO_FOLDER: /tmp/msaas
SERVICES_INPUT: ${{ github.event.inputs.services }}
run: | run: |
set -exo pipefail #!/bin/bash
git config --local user.email "action@github.com" set -euo pipefail
git config --local user.name "GitHub Action"
git checkout -b $BRANCH_NAME # Configuration
working_dir=$(pwd) readonly WORKING_DIR=$(pwd)
function image_version(){ readonly BUILD_SCRIPT_NAME="build.sh"
local service=$1 readonly BACKEND_SERVICES_FILE="/tmp/backend.txt"
chart_path="$working_dir/scripts/helmcharts/openreplay/charts/$service/Chart.yaml"
current_version=$(yq eval '.AppVersion' $chart_path) # Initialize git configuration
new_version=$(echo $current_version | awk -F. '{$NF += 1 ; print $1"."$2"."$3}') setup_git() {
echo $new_version git config --local user.email "action@github.com"
# yq eval ".AppVersion = \"$new_version\"" -i $chart_path git config --local user.name "GitHub Action"
git checkout -b "$BRANCH_NAME"
} }
function clone_msaas() {
[ -d $MSAAS_REPO_FOLDER ] || { # Get and increment image version
git clone -b dev --recursive https://x-access-token:$MSAAS_REPO_CLONE_TOKEN@$MSAAS_REPO_URL $MSAAS_REPO_FOLDER image_version() {
cd $MSAAS_REPO_FOLDER local service=$1
cd openreplay && git fetch origin && git checkout main # This have to be changed to specific tag local chart_path="$WORKING_DIR/scripts/helmcharts/openreplay/charts/$service/Chart.yaml"
git log -1 local current_version new_version
cd $MSAAS_REPO_FOLDER
bash git-init.sh current_version=$(yq eval '.AppVersion' "$chart_path")
git checkout new_version=$(echo "$current_version" | awk -F. '{$NF += 1; print $1"."$2"."$3}')
} echo "$new_version"
} }
function build_managed() {
local service=$1 # Clone MSAAS repository if not exists
local version=$2 clone_msaas() {
echo building managed if [[ ! -d "$MSAAS_REPO_FOLDER" ]]; then
clone_msaas git clone -b dev --recursive "https://x-access-token:${MSAAS_REPO_CLONE_TOKEN}@${MSAAS_REPO_URL}" "$MSAAS_REPO_FOLDER"
if [[ $service == 'chalice' ]]; then cd "$MSAAS_REPO_FOLDER"
cd $MSAAS_REPO_FOLDER/openreplay/api cd openreplay && git fetch origin && git checkout main
else git log -1
cd $MSAAS_REPO_FOLDER/openreplay/$service cd "$MSAAS_REPO_FOLDER"
fi bash git-init.sh
IMAGE_TAG=$version DOCKER_RUNTIME="depot" DOCKER_BUILD_ARGS="--push" ARCH=amd64 DOCKER_REPO=$DOCKER_REPO_OSS PUSH_IMAGE=0 bash $BUILD_SCRIPT_NAME >> /tmp/managed_${service}.txt 2>&1 || { echo "Build failed for $service"; cat /tmp/managed_${service}.txt; exit 1; } git checkout
fi
} }
# Checking for backend images
ls backend/cmd >> /tmp/backend.txt # Build managed services
echo Services: "${{ github.event.inputs.services }}" build_managed() {
IFS=',' read -ra SERVICES <<< "${{ github.event.inputs.services }}" local service=$1
BUILD_SCRIPT_NAME="build.sh" local version=$2
# Build FOSS
for SERVICE in "${SERVICES[@]}"; do echo "Building managed service: $service"
# Check if service is backend clone_msaas
if grep -q $SERVICE /tmp/backend.txt; then
cd backend if [[ $service == 'chalice' ]]; then
foss_build_args="nil $SERVICE" cd "$MSAAS_REPO_FOLDER/openreplay/api"
ee_build_args="ee $SERVICE" else
else cd "$MSAAS_REPO_FOLDER/openreplay/$service"
[[ $SERVICE == 'chalice' || $SERVICE == 'alerts' || $SERVICE == 'crons' ]] && cd $working_dir/api || cd $SERVICE fi
[[ $SERVICE == 'alerts' || $SERVICE == 'crons' ]] && BUILD_SCRIPT_NAME="build_${SERVICE}.sh"
ee_build_args="ee" local build_cmd="IMAGE_TAG=$version DOCKER_RUNTIME=depot DOCKER_BUILD_ARGS=--push ARCH=arm64 DOCKER_REPO=$DOCKER_REPO_ARM PUSH_IMAGE=0 bash build.sh"
fi
version=$(image_version $SERVICE) echo "Executing: $build_cmd"
echo IMAGE_TAG=$version DOCKER_RUNTIME="depot" DOCKER_BUILD_ARGS="--push" ARCH=amd64 DOCKER_REPO=$DOCKER_REPO_OSS PUSH_IMAGE=0 bash ${BUILD_SCRIPT_NAME} $foss_build_args if ! eval "$build_cmd" 2>&1; then
IMAGE_TAG=$version DOCKER_RUNTIME="depot" DOCKER_BUILD_ARGS="--push" ARCH=amd64 DOCKER_REPO=$DOCKER_REPO_OSS PUSH_IMAGE=0 bash ${BUILD_SCRIPT_NAME} $foss_build_args echo "Build failed for $service"
echo IMAGE_TAG=$version-ee DOCKER_RUNTIME="depot" DOCKER_BUILD_ARGS="--push" ARCH=amd64 DOCKER_REPO=$DOCKER_REPO_OSS PUSH_IMAGE=0 bash ${BUILD_SCRIPT_NAME} $ee_build_args exit 1
IMAGE_TAG=$version-ee DOCKER_RUNTIME="depot" DOCKER_BUILD_ARGS="--push" ARCH=amd64 DOCKER_REPO=$DOCKER_REPO_OSS PUSH_IMAGE=0 bash ${BUILD_SCRIPT_NAME} $ee_build_args fi
if [[ "$SERVICE" != "chalice" && "$SERVICE" != "frontend" ]]; then }
IMAGE_TAG=$version DOCKER_RUNTIME="depot" DOCKER_BUILD_ARGS="--push" ARCH=arm64 DOCKER_REPO=$DOCKER_REPO_ARM PUSH_IMAGE=0 bash ${BUILD_SCRIPT_NAME} $foss_build_args
echo IMAGE_TAG=$version DOCKER_RUNTIME="depot" DOCKER_BUILD_ARGS="--push" ARCH=arm64 DOCKER_REPO=$DOCKER_REPO_ARM PUSH_IMAGE=0 bash ${BUILD_SCRIPT_NAME} $foss_build_args # Build service with given arguments
else build_service() {
build_managed $SERVICE $version local service=$1
fi local version=$2
cd $working_dir local build_args=$3
chart_path="$working_dir/scripts/helmcharts/openreplay/charts/$SERVICE/Chart.yaml" local build_script=${4:-$BUILD_SCRIPT_NAME}
yq eval ".AppVersion = \"$version\"" -i $chart_path
git add $chart_path local command="IMAGE_TAG=$version DOCKER_RUNTIME=depot DOCKER_BUILD_ARGS=--push ARCH=amd64 DOCKER_REPO=$DOCKER_REPO_OSS PUSH_IMAGE=0 bash $build_script $build_args"
git commit -m "Increment $SERVICE chart version" echo "Executing: $command"
git push --set-upstream origin $BRANCH_NAME eval "$command"
done }
# Update chart version and commit changes
update_chart_version() {
local service=$1
local version=$2
local chart_path="$WORKING_DIR/scripts/helmcharts/openreplay/charts/$service/Chart.yaml"
# Ensure we're in the original working directory/repository
cd "$WORKING_DIR"
yq eval ".AppVersion = \"$version\"" -i "$chart_path"
git add "$chart_path"
git commit -m "Increment $service chart version to $version"
git push --set-upstream origin "$BRANCH_NAME"
cd -
}
# Main execution
main() {
setup_git
# Get backend services list
ls backend/cmd >"$BACKEND_SERVICES_FILE"
# Parse services input (fix for GitHub Actions syntax)
echo "Services: ${SERVICES_INPUT:-$1}"
IFS=',' read -ra services <<<"${SERVICES_INPUT:-$1}"
# Process each service
for service in "${services[@]}"; do
echo "Processing service: $service"
cd "$WORKING_DIR"
local foss_build_args="" ee_build_args="" build_script="$BUILD_SCRIPT_NAME"
# Determine build configuration based on service type
if grep -q "$service" "$BACKEND_SERVICES_FILE"; then
# Backend service
cd backend
foss_build_args="nil $service"
ee_build_args="ee $service"
else
# Non-backend service
case "$service" in
chalice | alerts | crons)
cd "$WORKING_DIR/api"
;;
*)
cd "$service"
;;
esac
# Special build scripts for alerts/crons
if [[ $service == 'alerts' || $service == 'crons' ]]; then
build_script="build_${service}.sh"
fi
ee_build_args="ee"
fi
# Get version and build
local version
version=$(image_version "$service")
# Build FOSS and EE versions
build_service "$service" "$version" "$foss_build_args"
build_service "$service" "${version}-ee" "$ee_build_args"
# Build managed version for specific services
if [[ "$service" != "chalice" && "$service" != "frontend" ]]; then
echo "Nothing to build in managed for service $service"
else
build_managed "$service" "$version"
fi
# Update chart and commit
update_chart_version "$service" "$version"
done
cd "$WORKING_DIR"
# Cleanup
rm -f "$BACKEND_SERVICES_FILE"
}
echo "Working directory: $WORKING_DIR"
# Run main function with all arguments
main "$SERVICES_INPUT"
- name: Create Pull Request - name: Create Pull Request
uses: repo-sync/pull-request@v2 uses: repo-sync/pull-request@v2

View file

@ -50,8 +50,8 @@ class JIRAIntegration(base.BaseIntegration):
cur.execute( cur.execute(
cur.mogrify( cur.mogrify(
"""SELECT username, token, url """SELECT username, token, url
FROM public.jira_cloud FROM public.jira_cloud
WHERE user_id=%(user_id)s;""", WHERE user_id = %(user_id)s;""",
{"user_id": self._user_id}) {"user_id": self._user_id})
) )
data = helper.dict_to_camel_case(cur.fetchone()) data = helper.dict_to_camel_case(cur.fetchone())
@ -95,10 +95,9 @@ class JIRAIntegration(base.BaseIntegration):
def add(self, username, token, url, obfuscate=False): def add(self, username, token, url, obfuscate=False):
with pg_client.PostgresClient() as cur: with pg_client.PostgresClient() as cur:
cur.execute( cur.execute(
cur.mogrify("""\ cur.mogrify(""" \
INSERT INTO public.jira_cloud(username, token, user_id,url) INSERT INTO public.jira_cloud(username, token, user_id, url)
VALUES (%(username)s, %(token)s, %(user_id)s,%(url)s) VALUES (%(username)s, %(token)s, %(user_id)s, %(url)s) RETURNING username, token, url;""",
RETURNING username, token, url;""",
{"user_id": self._user_id, "username": username, {"user_id": self._user_id, "username": username,
"token": token, "url": url}) "token": token, "url": url})
) )
@ -112,9 +111,10 @@ class JIRAIntegration(base.BaseIntegration):
def delete(self): def delete(self):
with pg_client.PostgresClient() as cur: with pg_client.PostgresClient() as cur:
cur.execute( cur.execute(
cur.mogrify("""\ cur.mogrify(""" \
DELETE FROM public.jira_cloud DELETE
WHERE user_id=%(user_id)s;""", FROM public.jira_cloud
WHERE user_id = %(user_id)s;""",
{"user_id": self._user_id}) {"user_id": self._user_id})
) )
return {"state": "success"} return {"state": "success"}
@ -125,7 +125,7 @@ class JIRAIntegration(base.BaseIntegration):
changes={ changes={
"username": data.username, "username": data.username,
"token": data.token if len(data.token) > 0 and data.token.find("***") == -1 \ "token": data.token if len(data.token) > 0 and data.token.find("***") == -1 \
else self.integration.token, else self.integration["token"],
"url": str(data.url) "url": str(data.url)
}, },
obfuscate=True obfuscate=True

View file

@ -23,6 +23,7 @@ function BottomButtons({
<Button <Button
loading={loading} loading={loading}
type="primary" type="primary"
htmlType="submit"
disabled={loading || !instance.validate()} disabled={loading || !instance.validate()}
id="submit-button" id="submit-button"
> >

View file

@ -64,6 +64,7 @@ function DashboardView(props: Props) {
}; };
useEffect(() => { useEffect(() => {
dashboardStore.resetPeriod();
if (queryParams.has('modal')) { if (queryParams.has('modal')) {
onAddWidgets(); onAddWidgets();
trimQuery(); trimQuery();

View file

@ -117,8 +117,6 @@ const ListView: React.FC<Props> = ({
if (disableSelection) { if (disableSelection) {
const path = withSiteId(`/metrics/${metric.metricId}`, siteId); const path = withSiteId(`/metrics/${metric.metricId}`, siteId);
history.push(path); history.push(path);
} else {
toggleSelection?.(metric.metricId);
} }
}; };

View file

@ -71,6 +71,7 @@ function WidgetView({
const params = new URLSearchParams(location.search); const params = new URLSearchParams(location.search);
const mk = params.get('mk'); const mk = params.get('mk');
if (mk) { if (mk) {
metricStore.init();
const selectedCard = CARD_LIST(t).find((c) => c.key === mk) as CardType; const selectedCard = CARD_LIST(t).find((c) => c.key === mk) as CardType;
if (selectedCard) { if (selectedCard) {
const cardData: any = { const cardData: any = {

View file

@ -42,7 +42,7 @@ function DropdownAudioPlayer({
return { return {
url: data.url, url: data.url,
timestamp: data.timestamp, timestamp: data.timestamp,
start: startTs, start: Math.max(0, startTs),
}; };
}), }),
[audioEvents.length, sessionStart], [audioEvents.length, sessionStart],

View file

@ -1,12 +1,13 @@
import { makeAutoObservable, runInAction, reaction } from 'mobx'; import { makeAutoObservable, runInAction, reaction } from 'mobx';
import { dashboardService, metricService } from 'App/services'; import { dashboardService, metricService } from 'App/services';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import Period, { LAST_24_HOURS, LAST_7_DAYS } from 'Types/app/period'; import Period, { LAST_24_HOURS } from 'Types/app/period';
import { getRE } from 'App/utils'; import { getRE } from 'App/utils';
import Filter from './types/filter'; import Filter from './types/filter';
import Widget from './types/widget'; import Widget from './types/widget';
import Dashboard from './types/dashboard'; import Dashboard from './types/dashboard';
import { calculateGranularities } from '@/components/Dashboard/components/WidgetDateRange/RangeGranularity'; import { calculateGranularities } from '@/components/Dashboard/components/WidgetDateRange/RangeGranularity';
import { CUSTOM_RANGE } from '@/dateRange';
interface DashboardFilter { interface DashboardFilter {
query?: string; query?: string;
@ -90,16 +91,20 @@ export default class DashboardStore {
() => this.period, () => this.period,
(period) => { (period) => {
this.createDensity(period.getDuration()); this.createDensity(period.getDuration());
} },
) );
} }
resetDensity = () => {
this.createDensity(this.period.getDuration());
};
createDensity = (duration: number) => { createDensity = (duration: number) => {
const densityOpts = calculateGranularities(duration); const densityOpts = calculateGranularities(duration);
const defaultOption = densityOpts[densityOpts.length - 2]; const defaultOption = densityOpts[densityOpts.length - 2];
this.setDensity(defaultOption.key) this.setDensity(defaultOption.key);
} };
setDensity = (density: number) => { setDensity = (density: number) => {
this.selectedDensity = density; this.selectedDensity = density;
@ -462,7 +467,7 @@ export default class DashboardStore {
this.isSaving = true; this.isSaving = true;
try { try {
try { try {
const response = await dashboardService.addWidget(dashboard, metricIds); await dashboardService.addWidget(dashboard, metricIds);
toast.success('Card added to dashboard.'); toast.success('Card added to dashboard.');
} catch { } catch {
toast.error('Card could not be added.'); toast.error('Card could not be added.');
@ -472,6 +477,17 @@ export default class DashboardStore {
} }
} }
resetPeriod = () => {
if (this.period) {
const range = this.period.rangeName;
if (range !== CUSTOM_RANGE) {
this.period = Period({ rangeName: this.period.rangeName });
} else {
this.period = Period({ rangeName: LAST_24_HOURS });
}
}
};
setPeriod(period: any) { setPeriod(period: any) {
this.period = Period({ this.period = Period({
start: period.start, start: period.start,
@ -545,7 +561,7 @@ export default class DashboardStore {
const data = await metricService.getMetricChartData( const data = await metricService.getMetricChartData(
metric, metric,
params, params,
isSaved isSaved,
); );
resolve(metric.setData(data, period, isComparison, density)); resolve(metric.setData(data, period, isComparison, density));
} catch (error) { } catch (error) {

View file

@ -54,6 +54,25 @@ server {
add_header 'Access-Control-Allow-Headers' 'Content-Type,Authorization,Content-Encoding'; add_header 'Access-Control-Allow-Headers' 'Content-Type,Authorization,Content-Encoding';
add_header 'Access-Control-Expose-Headers' 'Content-Length'; add_header 'Access-Control-Expose-Headers' 'Content-Length';
} }
location /integrations/ {
rewrite ^/integrations/(.*) /$1 break;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header X-Forwarded-For $real_ip;
proxy_set_header X-Forwarded-Host $real_ip;
proxy_set_header X-Real-IP $real_ip;
proxy_set_header Host $host;
proxy_pass http://integrations-openreplay:8080;
proxy_read_timeout 300;
proxy_connect_timeout 120;
proxy_send_timeout 300;
# CORS Headers
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'POST,PATCH,OPTIONS,DELETE';
add_header 'Access-Control-Allow-Headers' 'Content-Type,Authorization,Content-Encoding,X-Openreplay-Batch';
add_header 'Access-Control-Expose-Headers' 'Content-Length';
}
location /api/ { location /api/ {
rewrite ^/api/(.*) /$1 break; rewrite ^/api/(.*) /$1 break;

View file

@ -18,4 +18,4 @@ version: 0.1.10
# incremented each time you make changes to the application. Versions are not expected to # incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using. # follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes. # It is recommended to use it with quotes.
AppVersion: "v1.22.36" AppVersion: "v1.22.42"