Skip to content

Commit

Permalink
Merge pull request #2645 from RedisInsight/latest
Browse files Browse the repository at this point in the history
Latest to main
  • Loading branch information
vlad-dargel committed Sep 28, 2023
2 parents bddfb99 + 9372bce commit f141733
Show file tree
Hide file tree
Showing 28 changed files with 180 additions and 81 deletions.
2 changes: 1 addition & 1 deletion redisinsight/api/config/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export default {
tlsKey: process.env.SERVER_TLS_KEY,
staticContent: !!process.env.SERVER_STATIC_CONTENT || false,
buildType: process.env.BUILD_TYPE || 'ELECTRON',
appVersion: process.env.APP_VERSION || '2.32.0',
appVersion: process.env.APP_VERSION || '2.34.0',
requestTimeout: parseInt(process.env.REQUEST_TIMEOUT, 10) || 25000,
excludeRoutes: [],
excludeAuthRoutes: [],
Expand Down
7 changes: 6 additions & 1 deletion redisinsight/api/config/features-config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": 2.34,
"version": 2.3401,
"features": {
"insightsRecommendations": {
"flag": true,
Expand Down Expand Up @@ -28,6 +28,11 @@
}
],
"data": {
"filterFreePlan": [{
"field": "name",
"expression": "^(No HA?.)|(Cache?.)",
"options": "i"
}],
"selectPlan": {
"components": {
"triggersAndFunctions": [
Expand Down
2 changes: 1 addition & 1 deletion redisinsight/api/config/swagger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const SWAGGER_CONFIG: Omit<OpenAPIObject, 'paths'> = {
info: {
title: 'RedisInsight Backend API',
description: 'RedisInsight Backend API',
version: '2.32.0',
version: '2.34.0',
},
tags: [],
};
Expand Down
2 changes: 1 addition & 1 deletion redisinsight/api/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "redisinsight-api",
"version": "2.32.0",
"version": "2.34.0",
"description": "RedisInsight API",
"private": true,
"author": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ export class CloudAuthAnalytics extends TelemetryBaseService {
}

sendCloudSignInFailed(exception: HttpException, flow?: CloudSsoFeatureStrategy, action?: string) {
this.sendFailedEvent(TelemetryEvents.CloudSignInFailed, exception, { flow, action });
this.sendFailedEvent(TelemetryEvents.CloudSignInFailed, exception, {
flow,
action,
errorDescription: exception?.['options']?.['description'],
});
}
}
8 changes: 6 additions & 2 deletions redisinsight/api/src/modules/cloud/auth/cloud-auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,14 @@ export class CloudAuthService {

static getAuthorizationServerRedirectError(query: { error_description: string }) {
if (query?.error_description?.indexOf('properties are missing') > -1) {
return new CloudOauthMissedRequiredDataException(query.error_description);
return new CloudOauthMissedRequiredDataException(query.error_description, {
description: query.error_description,
});
}

return new CloudOauthMisconfigurationException();
return new CloudOauthMisconfigurationException(undefined, {
description: query.error_description,
});
}

getAuthStrategy(strategy: CloudAuthIdpType): CloudAuthStrategy {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export class CloudOauthUnknownAuthorizationRequestException extends HttpExceptio
const response = {
message,
statusCode: HttpStatus.BAD_REQUEST,
error: 'CloudOauthGithubEmailPermission',
error: 'CloudOauthUnknownAuthorizationRequest',
errorCode: CustomErrorCodes.CloudOauthUnknownAuthorizationRequest,
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { ICloudCapiCredentials } from 'src/modules/cloud/common/models';
import { CloudSubscriptionType } from 'src/modules/cloud/subscription/models';
import config from 'src/utils/config';
import { CloudCapiProvider } from './cloud.capi.provider';

const serverConfig = config.get('server');

const getPrefixTests = [
{
input: undefined,
Expand All @@ -17,22 +20,24 @@ const getPrefixTests = [
},
];

const userAgent = `RedisInsight/${serverConfig.version}`;

const getHeadersTests = [
{
input: {},
expected: { 'x-api-key': undefined, 'x-api-secret-key': undefined, 'User-Agent': 'RedisInsight/2.32.0' },
expected: { 'x-api-key': undefined, 'x-api-secret-key': undefined, 'User-Agent': userAgent },
},
{
input: { capiKey: 'key' },
expected: { 'x-api-key': 'key', 'x-api-secret-key': undefined, 'User-Agent': 'RedisInsight/2.32.0' },
expected: { 'x-api-key': 'key', 'x-api-secret-key': undefined, 'User-Agent': userAgent },
},
{
input: { capiSecret: 'secret' },
expected: { 'x-api-key': undefined, 'x-api-secret-key': 'secret', 'User-Agent': 'RedisInsight/2.32.0' },
expected: { 'x-api-key': undefined, 'x-api-secret-key': 'secret', 'User-Agent': userAgent },
},
{
input: { capiKey: 'key', capiSecret: 'secret' },
expected: { 'x-api-key': 'key', 'x-api-secret-key': 'secret', 'User-Agent': 'RedisInsight/2.32.0' },
expected: { 'x-api-key': 'key', 'x-api-secret-key': 'secret', 'User-Agent': userAgent },
},
];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,24 @@ import {
mockCloudSubscriptionApiProvider,
mockCloudSubscriptionCapiService,
mockCloudSubscriptionRegions,
mockFeatureService,
mockSessionMetadata,
mockSubscriptionPlanResponse,
MockType,
} from 'src/__mocks__';
import { CloudApiUnauthorizedException } from 'src/modules/cloud/common/exceptions';
import { CloudCapiKeyService } from 'src/modules/cloud/capi-key/cloud-capi-key.service';
import { FeatureService } from 'src/modules/feature/feature.service';
import { CloudSubscriptionApiService } from './cloud-subscription.api.service';
import { CloudUserApiService } from '../user/cloud-user.api.service';
import { CloudSessionService } from '../session/cloud-session.service';
import { CloudSubscriptionCapiService } from './cloud-subscription.capi.service';
import { CloudSubscriptionApiProvider } from './providers/cloud-subscription.api.provider';

describe('CloudSubscriptionApiService', () => {
let service: CloudSubscriptionApiService;
let api: MockType<CloudSubscriptionApiProvider>;
let sessionService: MockType<CloudSessionService>;
let cloudUserApiService: MockType<CloudUserApiService>;
let cloudSubscriptionCapiService: MockType<CloudSubscriptionCapiService>;
let capi: MockType<CloudSubscriptionCapiService>;
let featureService: MockType<FeatureService>;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
Expand All @@ -44,11 +44,17 @@ describe('CloudSubscriptionApiService', () => {
provide: CloudCapiKeyService,
useFactory: mockCloudCapiKeyService,
},
{
provide: FeatureService,
useFactory: mockFeatureService,
},
],
}).compile();

service = module.get(CloudSubscriptionApiService);
api = module.get(CloudSubscriptionApiProvider);
capi = module.get(CloudSubscriptionCapiService);
featureService = module.get(FeatureService);
});

describe('getSubscriptionPlans', () => {
Expand All @@ -61,6 +67,55 @@ describe('CloudSubscriptionApiService', () => {
CloudApiUnauthorizedException,
);
});

describe('filter', () => {
beforeEach(() => {
featureService.getByName.mockResolvedValueOnce({
flag: true,
data: {
filterFreePlan: [{
field: 'name',
expression: '^(No HA?.)|(Cache?.)',
options: 'i',
}],
},
});
});

it('get empty list due to filter', async () => {
capi.getSubscriptionsPlans.mockResolvedValueOnce([
{ name: 'some name', price: 0 },
]);
expect(await service.getSubscriptionPlans(mockSessionMetadata)).toEqual([]);
});

it('filter only "no ha" and "cache" plans', async () => {
capi.getSubscriptionsPlans.mockResolvedValueOnce([
{ name: 'some name', price: 0 },
{ name: 'no thing', price: 0 },
{ name: 'No HA', price: 0 },
{ name: 'No HA 30MB price:0', price: 0 },
{ name: 'No HA 30MB price:1', price: 1 },
{ name: 'no ha 30MB', price: 0 },
{ name: 'no ha', price: 0 },
{ name: 'Cache', price: 0 },
{ name: 'Cache 30MB', price: 0 },
{ name: 'cache', price: 0 },
{ name: 'cache 30MB', price: 0 },
{ name: '', price: 0 },
]);
expect(await service.getSubscriptionPlans(mockSessionMetadata)).toEqual([
{ name: 'No HA', price: 0 },
{ name: 'No HA 30MB price:0', price: 0 },
{ name: 'no ha 30MB', price: 0 },
{ name: 'no ha', price: 0 },
{ name: 'Cache', price: 0 },
{ name: 'Cache 30MB', price: 0 },
{ name: 'cache', price: 0 },
{ name: 'cache 30MB', price: 0 },
]);
});
});
});

describe('getCloudRegions', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { SessionMetadata } from 'src/common/models';
import { wrapHttpError } from 'src/common/utils';
import { CloudRequestUtm, ICloudApiCredentials } from 'src/modules/cloud/common/models';
import { CloudCapiKeyService } from 'src/modules/cloud/capi-key/cloud-capi-key.service';
import { FeatureService } from 'src/modules/feature/feature.service';
import { KnownFeatures } from 'src/modules/feature/constants';
import { CloudSubscriptionCapiService } from './cloud-subscription.capi.service';
import { CloudSubscriptionRegion, CloudSubscriptionType } from './models';
import { CloudSessionService } from '../session/cloud-session.service';
Expand All @@ -20,6 +22,7 @@ export class CloudSubscriptionApiService {
private readonly sessionService: CloudSessionService,
private readonly cloudCapiKeyService: CloudCapiKeyService,
private readonly cloudSubscriptionCapiService: CloudSubscriptionCapiService,
private readonly featureService: FeatureService,
) {}

/**
Expand All @@ -42,9 +45,22 @@ export class CloudSubscriptionApiService {
),
]);

const cloudSsoFeature = await this.featureService.getByName(KnownFeatures.CloudSso);

const freePlans = filter(
fixedPlans,
({ price, name }) => price === 0 && name.startsWith('Cache'),
(plan) => {
if (plan.price !== 0) {
return false;
}

if (!cloudSsoFeature?.data?.filterFreePlan?.length) {
return true;
}

return !!((cloudSsoFeature?.data?.filterFreePlan).find((f) => f.expression
&& (new RegExp(f.expression, f.options)).test(plan[f?.field])));
},
);

return freePlans.map((plan) => ({
Expand Down
4 changes: 4 additions & 0 deletions redisinsight/desktop/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ import {
initAutoUpdaterHandlers,
launchApiServer,
initCloudHandlers,
electronStore,
} from 'desktopSrc/lib'
import { wrapErrorMessageSensitiveData } from 'desktopSrc/utils'
import { configMain as config } from 'desktopSrc/config'
import { deepLinkHandler, deepLinkWindowHandler } from 'desktopSrc/lib/app/deep-link.handlers'
import { ElectronStorageItem } from 'uiSrc/electron/constants'

if (!config.isProduction) {
const sourceMapSupport = require('source-map-support')
Expand All @@ -33,6 +35,8 @@ const init = async () => {
initTray()
initCloudHandlers()

nativeTheme.themeSource = electronStore?.get(ElectronStorageItem.themeSource) || config.themeSource

checkForUpdate(process.env.MANUAL_UPGRADES_LINK || process.env.UPGRADES_LINK)

app.setName(config.name)
Expand Down
1 change: 1 addition & 0 deletions redisinsight/desktop/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"defaultPort": 5530,
"host": "localhost",
"debug": false,
"themeSource": "dark",
"appName": "RedisInsight",
"schema": "redisinsight",
"mainWindow": {
Expand Down
2 changes: 1 addition & 1 deletion redisinsight/desktop/src/lib/aboutPanel/aboutPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const ICON_PATH = app.isPackaged

export const AboutPanelOptions = {
applicationName: 'RedisInsight-v2',
applicationVersion: `${app.getVersion() || '2.32.0'}${
applicationVersion: `${app.getVersion() || '2.34.0'}${
!config.isProduction ? `-dev-${process.getCreationTime()}` : ''
}`,
copyright: `Copyright © ${new Date().getFullYear()} Redis Ltd.`,
Expand Down
7 changes: 5 additions & 2 deletions redisinsight/desktop/src/lib/app/ipc.handlers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { app, ipcMain, nativeTheme } from 'electron'
import { electronStore } from 'desktopSrc/lib'
import { IpcInvokeEvent } from 'uiSrc/electron/constants'
import { ElectronStorageItem, IpcInvokeEvent } from 'uiSrc/electron/constants'

export const initIPCHandlers = () => {
ipcMain.handle(IpcInvokeEvent.getAppVersion, () => app?.getVersion())
Expand All @@ -10,6 +10,9 @@ export const initIPCHandlers = () => {
ipcMain.handle(IpcInvokeEvent.deleteStoreValue, (_event, key) => electronStore?.delete(key))

ipcMain.handle(IpcInvokeEvent.themeChange, (_event, theme: string) => {
nativeTheme.themeSource = theme.toLowerCase()
const themeSource = theme.toLowerCase() as typeof nativeTheme.themeSource

nativeTheme.themeSource = themeSource
electronStore?.set(ElectronStorageItem.themeSource, themeSource)
})
}
2 changes: 1 addition & 1 deletion redisinsight/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "redisinsight",
"productName": "RedisInsight",
"private": true,
"version": "2.32.0",
"version": "2.34.0",
"description": "RedisInsight",
"main": "./dist/main/main.js",
"author": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ export const INFINITE_MESSAGES = {
<EuiButton
size="s"
color="secondary"
className="infiniteMessage__btn"
onClick={() => onClose?.()}
data-testid="cancel-import-db-sso-btn"
>
Expand Down Expand Up @@ -144,6 +145,7 @@ export const INFINITE_MESSAGES = {
<EuiButton
size="s"
color="secondary"
className="infiniteMessage__btn"
onClick={() => onClose?.()}
data-testid="cancel-create-subscription-sso-btn"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,9 @@
margin-right: 8px;
margin-top: 2px;
}

.infiniteMessage__btn .euiButton__text {
color: var(--euiColorSecondaryText) !important;
}
}
}
4 changes: 1 addition & 3 deletions redisinsight/ui/src/constants/featuresHighlighting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,5 @@ interface BuildHighlightingFeature {
}

export const BUILD_FEATURES: Record<string, BuildHighlightingFeature> = {
cloudButton: {
type: 'plain'
}

} as const
4 changes: 2 additions & 2 deletions redisinsight/ui/src/contexts/themeContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ interface Props {
const THEME_NAMES = THEMES.map(({ value }) => value)

export const defaultState = {
theme: THEME_NAMES[0],
theme: THEME_NAMES[1], // dark theme by default
usingSystemTheme: localStorageService.get(BrowserStorageItem.theme) === Theme.System,
changeTheme: (themeValue: any) => {
themeService.applyTheme(themeValue)
Expand All @@ -36,7 +36,7 @@ export class ThemeProvider extends React.Component<Props> {
}
}

getSystemTheme = () => window.matchMedia && window.matchMedia(THEME_MATCH_MEDIA_DARK).matches ? Theme.Dark : Theme.Light
getSystemTheme = () => (window.matchMedia && window.matchMedia(THEME_MATCH_MEDIA_DARK).matches ? Theme.Dark : Theme.Light)

changeTheme = (themeValue: any) => {
let actualTheme = themeValue
Expand Down
1 change: 1 addition & 0 deletions redisinsight/ui/src/electron/constants/storageElectron.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ enum ElectronStorageItem {
isDisplayAppInTray = 'isDisplayAppInTray',
updatePreviousVersion = 'updatePreviousVersion',
zoomFactor = 'zoomFactor',
themeSource = 'themeSource',
}

export default ElectronStorageItem
Loading

0 comments on commit f141733

Please sign in to comment.