mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-15 17:31:56 +03:00
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:
parent
aa70c62bdd
commit
49a2822dbe
@ -6,16 +6,16 @@ export function HerokuBanner() {
|
|||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<GrHeroku size={15} className="mr-xs" color="#430098" />
|
<GrHeroku size={15} className="mr-xs" color="#430098" />
|
||||||
<div className="text-sm text-gray-700">
|
<div className="text-sm text-gray-700">
|
||||||
Heroku free database integration support has been deprecated.
|
Heroku free database integration support has been deprecated.{' '}
|
||||||
</div>
|
|
||||||
<a
|
<a
|
||||||
href="https://hasura.io/docs/latest/databases/connect-db/cloud-databases/heroku/"
|
href="https://hasura.io/docs/latest/databases/connect-db/cloud-databases/heroku/"
|
||||||
className="ml-xs font-normal text-secondary italic text-sm"
|
className="text-secondary italic"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
(Know More)
|
(Know More)
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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">
|
<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
|
Free
|
||||||
</span>
|
</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>
|
</div>
|
||||||
<img
|
<img
|
||||||
src="https://storage.googleapis.com/graphql-engine-cdn.hasura.io/cloud-console/assets/common/img/neon.jpg"
|
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>
|
||||||
<div className="flex justify-between items-center mb-sm">
|
<div className="flex justify-between items-center mb-sm">
|
||||||
<div className="w-[70%] text-md text-gray-700">
|
<div className="w-[70%] text-md text-gray-700">
|
||||||
Fully managed Postgres with separate storage and compute, that scales
|
Modern, developer-friendly Postgres built for the cloud. Neon
|
||||||
to zero on inactivity and provides seamless scaling and branching.
|
separates storage and compute to offer scale to zero and support
|
||||||
|
database branching.
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button
|
||||||
|
@ -16,11 +16,11 @@ export function Neon(props: { allDatabases: string[]; dispatch: Dispatch }) {
|
|||||||
|
|
||||||
// success callback
|
// success callback
|
||||||
const pushToDatasource = (dataSourceName: string) => {
|
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
|
// overriding the stale time
|
||||||
reactQueryClient.refetchQueries(FETCH_NEON_PROJECTS_BY_PROJECTID_QUERYKEY);
|
reactQueryClient.refetchQueries(FETCH_NEON_PROJECTS_BY_PROJECTID_QUERYKEY);
|
||||||
|
|
||||||
dispatch(_push(`/data/${dataSourceName}`));
|
dispatch(_push(`/data/${dataSourceName}/schema/public`));
|
||||||
};
|
};
|
||||||
const pushToConnectDBPage = () => {
|
const pushToConnectDBPage = () => {
|
||||||
dispatch(_push(`/data/manage/connect`));
|
dispatch(_push(`/data/manage/connect`));
|
||||||
|
@ -52,7 +52,7 @@ export function NeonOnboarding(props: {
|
|||||||
const neonIntegrationStatus = useNeonIntegration(
|
const neonIntegrationStatus = useNeonIntegration(
|
||||||
'default',
|
'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
|
// overriding the stale time
|
||||||
reactQueryClient.refetchQueries(
|
reactQueryClient.refetchQueries(
|
||||||
FETCH_NEON_PROJECTS_BY_PROJECTID_QUERYKEY
|
FETCH_NEON_PROJECTS_BY_PROJECTID_QUERYKEY
|
||||||
|
@ -30,8 +30,8 @@ export const NEON_ONBOARDING_QUERY_KEY = 'neonOnboarding';
|
|||||||
export const experimentId = growthExperimentsIds.onboardingWizardV1;
|
export const experimentId = growthExperimentsIds.onboardingWizardV1;
|
||||||
|
|
||||||
export const graphQlMutation = `
|
export const graphQlMutation = `
|
||||||
mutation trackExperimentsCohortActivity ($projectId: uuid!, $experimentId: String!, $kind: String!) {
|
mutation trackExperimentsCohortActivity ($projectId: uuid!, $experimentId: String!, $kind: String! $error_code: String) {
|
||||||
trackExperimentsCohortActivity(experiment: $experimentId, payload: {kind: $kind, project_id: $projectId}) {
|
trackExperimentsCohortActivity(experiment: $experimentId, payload: {kind: $kind, project_id: $projectId, error_code: $error_code}) {
|
||||||
status
|
status
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,10 @@ import {
|
|||||||
type HasuraFamiliaritySurveyProps = {
|
type HasuraFamiliaritySurveyProps = {
|
||||||
data: { question: string; options: IconCardGroupItem<string>[] };
|
data: { question: string; options: IconCardGroupItem<string>[] };
|
||||||
onOptionClick: (optionValue: string) => void;
|
onOptionClick: (optionValue: string) => void;
|
||||||
onSkip: () => void;
|
onSkip?: () => void;
|
||||||
};
|
};
|
||||||
export function HasuraFamiliaritySurvey(props: HasuraFamiliaritySurveyProps) {
|
export function HasuraFamiliaritySurvey(props: HasuraFamiliaritySurveyProps) {
|
||||||
const { data, onOptionClick, onSkip } = props;
|
const { data, onOptionClick } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -24,14 +24,15 @@ export function HasuraFamiliaritySurvey(props: HasuraFamiliaritySurveyProps) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</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
|
<div
|
||||||
data-trackid="hasura-familiarity-survey-skip-button"
|
data-trackid="hasura-familiarity-survey-skip-button"
|
||||||
onClick={onSkip}
|
onClick={onSkip}
|
||||||
>
|
>
|
||||||
Skip
|
Skip
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> */}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useState } from 'react';
|
import { useState, useMemo } from 'react';
|
||||||
import { useMutation, useQuery, useQueryClient } from 'react-query';
|
import { useMutation, useQuery, useQueryClient } from 'react-query';
|
||||||
import { APIError } from '@/hooks/error';
|
import { APIError } from '@/hooks/error';
|
||||||
import { IconCardGroupItem } from '@/new-components/IconCardGroup';
|
import { IconCardGroupItem } from '@/new-components/IconCardGroup';
|
||||||
@ -40,14 +40,19 @@ export function useFamiliaritySurveyData(): {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isLoading || isError) {
|
|
||||||
return emptySurveyResponseData;
|
|
||||||
}
|
|
||||||
|
|
||||||
const surveyQuestionData = data?.data?.survey?.find(
|
const surveyQuestionData = data?.data?.survey?.find(
|
||||||
surveyInfo => surveyInfo.survey_name === surveyName
|
surveyInfo => surveyInfo.survey_name === surveyName
|
||||||
)?.survey_questions?.[0];
|
)?.survey_questions?.[0];
|
||||||
|
|
||||||
|
const surveyOptions = useMemo(
|
||||||
|
() => mapOptionLabelToDetails(surveyQuestionData),
|
||||||
|
[surveyQuestionData]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isLoading || isError) {
|
||||||
|
return emptySurveyResponseData;
|
||||||
|
}
|
||||||
|
|
||||||
// skip showing the survey form if survey has no questions
|
// skip showing the survey form if survey has no questions
|
||||||
if (!surveyQuestionData) {
|
if (!surveyQuestionData) {
|
||||||
return emptySurveyResponseData;
|
return emptySurveyResponseData;
|
||||||
@ -92,7 +97,7 @@ export function useFamiliaritySurveyData(): {
|
|||||||
showFamiliaritySurvey,
|
showFamiliaritySurvey,
|
||||||
data: {
|
data: {
|
||||||
question: surveyQuestionData.question,
|
question: surveyQuestionData.question,
|
||||||
options: mapOptionLabelToDetails(surveyQuestionData),
|
options: surveyOptions,
|
||||||
},
|
},
|
||||||
onSkip,
|
onSkip,
|
||||||
onOptionClick,
|
onOptionClick,
|
||||||
|
@ -6,14 +6,61 @@ import {
|
|||||||
getFamiliaritySurveyOptionDetails,
|
getFamiliaritySurveyOptionDetails,
|
||||||
} from './familiaritySurveyOptionDetails';
|
} from './familiaritySurveyOptionDetails';
|
||||||
|
|
||||||
export const mapOptionLabelToDetails = (
|
type UnroderedOptionArray = {
|
||||||
data: SurveysResponseData['data']['survey'][0]['survey_questions'][0]
|
|
||||||
): IconCardGroupItem<string>[] => {
|
|
||||||
const unroderedOptionArray: {
|
|
||||||
option: FamiliaritySurveyOptionCode;
|
option: FamiliaritySurveyOptionCode;
|
||||||
id: string;
|
id: string;
|
||||||
}[] = [];
|
}[];
|
||||||
data.survey_question_options.forEach(optionData => {
|
|
||||||
|
/**
|
||||||
|
* 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]
|
||||||
|
): IconCardGroupItem<string>[] => {
|
||||||
|
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();
|
const optionLabel = optionData.option.toLowerCase();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -34,20 +81,6 @@ export const mapOptionLabelToDetails = (
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// enforce order of options to show in the UI
|
// return manuallyOrderOptions(unroderedOptionArray);
|
||||||
const surveyOptionDetails: IconCardGroupItem<string>[] = [];
|
return randomlyOrderOptions(unroderedOptionArray);
|
||||||
familiaritySurveyOptionCode.forEach(optionCode => {
|
|
||||||
const optionData = unroderedOptionArray.find(
|
|
||||||
optionObj => optionObj.option === optionCode
|
|
||||||
);
|
|
||||||
if (optionData) {
|
|
||||||
const optionValues = getFamiliaritySurveyOptionDetails(
|
|
||||||
optionData.id,
|
|
||||||
optionCode
|
|
||||||
);
|
|
||||||
surveyOptionDetails.push(optionValues);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return surveyOptionDetails;
|
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user