console: UI fixes for neon banner in connect db page

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6376
Co-authored-by: Rishichandra Wawhal <27274869+wawhal@users.noreply.github.com>
GitOrigin-RevId: 8f2ec961be370097b48b684211606d34dbaa002d
This commit is contained in:
Abhijeet Khangarot 2022-10-18 00:32:58 +05:30 committed by hasura-bot
parent aa70c62bdd
commit 49a2822dbe
8 changed files with 88 additions and 51 deletions

View File

@ -6,16 +6,16 @@ export function HerokuBanner() {
<div className="flex items-center">
<GrHeroku size={15} className="mr-xs" color="#430098" />
<div className="text-sm text-gray-700">
Heroku free database integration support has been deprecated.
Heroku free database integration support has been deprecated.{' '}
<a
href="https://hasura.io/docs/latest/databases/connect-db/cloud-databases/heroku/"
className="text-secondary italic"
target="_blank"
rel="noopener noreferrer"
>
(Know More)
</a>
</div>
<a
href="https://hasura.io/docs/latest/databases/connect-db/cloud-databases/heroku/"
className="ml-xs font-normal text-secondary italic text-sm"
target="_blank"
rel="noopener noreferrer"
>
(Know More)
</a>
</div>
);
}

View File

@ -40,9 +40,6 @@ export function NeonBanner(props: Props) {
<span className="ml-xs font-semibold flex items-center text-sm py-0.5 px-1.5 text-indigo-600 bg-indigo-100 rounded">
Free
</span>
<span className="ml-xs font-semibold flex items-center text-sm py-0.5 px-1.5 text-indigo-600 bg-indigo-100 rounded">
Preview
</span>
</div>
<img
src="https://storage.googleapis.com/graphql-engine-cdn.hasura.io/cloud-console/assets/common/img/neon.jpg"
@ -54,8 +51,9 @@ export function NeonBanner(props: Props) {
</div>
<div className="flex justify-between items-center mb-sm">
<div className="w-[70%] text-md text-gray-700">
Fully managed Postgres with separate storage and compute, that scales
to zero on inactivity and provides seamless scaling and branching.
Modern, developer-friendly Postgres built for the cloud. Neon
separates storage and compute to offer scale to zero and support
database branching.
</div>
<div>
<Button

View File

@ -16,11 +16,11 @@ export function Neon(props: { allDatabases: string[]; dispatch: Dispatch }) {
// success callback
const pushToDatasource = (dataSourceName: string) => {
// on success, refetch queries to show neon onboarding link in connect database page,
// on success, refetch queries to show neon dashboard link in connect database page,
// overriding the stale time
reactQueryClient.refetchQueries(FETCH_NEON_PROJECTS_BY_PROJECTID_QUERYKEY);
dispatch(_push(`/data/${dataSourceName}`));
dispatch(_push(`/data/${dataSourceName}/schema/public`));
};
const pushToConnectDBPage = () => {
dispatch(_push(`/data/manage/connect`));

View File

@ -52,7 +52,7 @@ export function NeonOnboarding(props: {
const neonIntegrationStatus = useNeonIntegration(
'default',
() => {
// on success, refetch queries to show neon onboarding link in connect database page,
// on success, refetch queries to show neon dashboard link in connect database page,
// overriding the stale time
reactQueryClient.refetchQueries(
FETCH_NEON_PROJECTS_BY_PROJECTID_QUERYKEY

View File

@ -30,8 +30,8 @@ export const NEON_ONBOARDING_QUERY_KEY = 'neonOnboarding';
export const experimentId = growthExperimentsIds.onboardingWizardV1;
export const graphQlMutation = `
mutation trackExperimentsCohortActivity ($projectId: uuid!, $experimentId: String!, $kind: String!) {
trackExperimentsCohortActivity(experiment: $experimentId, payload: {kind: $kind, project_id: $projectId}) {
mutation trackExperimentsCohortActivity ($projectId: uuid!, $experimentId: String!, $kind: String! $error_code: String) {
trackExperimentsCohortActivity(experiment: $experimentId, payload: {kind: $kind, project_id: $projectId, error_code: $error_code}) {
status
}
}

View File

@ -7,10 +7,10 @@ import {
type HasuraFamiliaritySurveyProps = {
data: { question: string; options: IconCardGroupItem<string>[] };
onOptionClick: (optionValue: string) => void;
onSkip: () => void;
onSkip?: () => void;
};
export function HasuraFamiliaritySurvey(props: HasuraFamiliaritySurveyProps) {
const { data, onOptionClick, onSkip } = props;
const { data, onOptionClick } = props;
return (
<>
@ -24,14 +24,15 @@ export function HasuraFamiliaritySurvey(props: HasuraFamiliaritySurveyProps) {
/>
</div>
</div>
<div className="cursor-pointer text-secondary text-sm hover:text-secondary-dark">
{/* Remove skipping survey button, this change is experimental according to analytics data, so only commenting the code */}
{/* <div className="cursor-pointer text-secondary text-sm hover:text-secondary-dark">
<div
data-trackid="hasura-familiarity-survey-skip-button"
onClick={onSkip}
>
Skip
</div>
</div>
</div> */}
</>
);
}

View File

@ -1,4 +1,4 @@
import { useState } from 'react';
import { useState, useMemo } from 'react';
import { useMutation, useQuery, useQueryClient } from 'react-query';
import { APIError } from '@/hooks/error';
import { IconCardGroupItem } from '@/new-components/IconCardGroup';
@ -40,14 +40,19 @@ export function useFamiliaritySurveyData(): {
},
});
if (isLoading || isError) {
return emptySurveyResponseData;
}
const surveyQuestionData = data?.data?.survey?.find(
surveyInfo => surveyInfo.survey_name === surveyName
)?.survey_questions?.[0];
const surveyOptions = useMemo(
() => mapOptionLabelToDetails(surveyQuestionData),
[surveyQuestionData]
);
if (isLoading || isError) {
return emptySurveyResponseData;
}
// skip showing the survey form if survey has no questions
if (!surveyQuestionData) {
return emptySurveyResponseData;
@ -92,7 +97,7 @@ export function useFamiliaritySurveyData(): {
showFamiliaritySurvey,
data: {
question: surveyQuestionData.question,
options: mapOptionLabelToDetails(surveyQuestionData),
options: surveyOptions,
},
onSkip,
onOptionClick,

View File

@ -6,14 +6,61 @@ import {
getFamiliaritySurveyOptionDetails,
} from './familiaritySurveyOptionDetails';
type UnroderedOptionArray = {
option: FamiliaritySurveyOptionCode;
id: string;
}[];
/**
* Manually enforces the order of options as present in `familiaritySurveyOptionCode`
* array.
*/
// Not removing this function. Although it is not being used currenty due to dynamic product requirements,
// but can again be used in future.
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const manuallyOrderOptions = (unroderedOptionArray: UnroderedOptionArray) => {
const surveyOptionDetails: IconCardGroupItem<string>[] = [];
familiaritySurveyOptionCode.forEach(optionCode => {
const optionData = unroderedOptionArray.find(
optionObj => optionObj.option === optionCode
);
if (optionData) {
const optionValues = getFamiliaritySurveyOptionDetails(
optionData.id,
optionCode
);
surveyOptionDetails.push(optionValues);
}
});
return surveyOptionDetails;
};
/**
* Randomly shuffles order of options of survey.
* The method comes from this algorithm: https://stackoverflow.com/a/46545530/7088648
*/
const randomlyOrderOptions = (unroderedOptionArray: UnroderedOptionArray) => {
const shuffledOptionArray = unroderedOptionArray
.map(value => ({ value, sort: Math.random() }))
.sort((a, b) => a.sort - b.sort)
.map(({ value }) => value);
const surveyOptionDetails: IconCardGroupItem<string>[] =
shuffledOptionArray.map(option =>
getFamiliaritySurveyOptionDetails(option.id, option.option)
);
return surveyOptionDetails;
};
export const mapOptionLabelToDetails = (
data: SurveysResponseData['data']['survey'][0]['survey_questions'][0]
data?: SurveysResponseData['data']['survey'][0]['survey_questions'][0]
): IconCardGroupItem<string>[] => {
const unroderedOptionArray: {
option: FamiliaritySurveyOptionCode;
id: string;
}[] = [];
data.survey_question_options.forEach(optionData => {
if (!data) return [];
// Array containing order of options as it comes from backend
const unroderedOptionArray: UnroderedOptionArray = [];
data?.survey_question_options?.forEach(optionData => {
const optionLabel = optionData.option.toLowerCase();
if (
@ -34,20 +81,6 @@ export const mapOptionLabelToDetails = (
});
});
// enforce order of options to show in the UI
const surveyOptionDetails: IconCardGroupItem<string>[] = [];
familiaritySurveyOptionCode.forEach(optionCode => {
const optionData = unroderedOptionArray.find(
optionObj => optionObj.option === optionCode
);
if (optionData) {
const optionValues = getFamiliaritySurveyOptionDetails(
optionData.id,
optionCode
);
surveyOptionDetails.push(optionValues);
}
});
return surveyOptionDetails;
// return manuallyOrderOptions(unroderedOptionArray);
return randomlyOrderOptions(unroderedOptionArray);
};