mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-14 17:02:49 +03:00
console: Schema registry notification dot( cherrypick v2.34)
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/10431 Co-authored-by: ojas <31686586+OjasWadhwani@users.noreply.github.com> GitOrigin-RevId: 8ad8590a44924dfa5aeec2a29e02dafd1d11e01e
This commit is contained in:
parent
d892851183
commit
3c3e359457
@ -4,8 +4,19 @@ import { isProConsole } from '../../../utils/proConsole';
|
||||
import { useEELiteAccess } from '../../../features/EETrial';
|
||||
import globals from '../../../Globals';
|
||||
import { IconTooltip } from '../../../new-components/Tooltip';
|
||||
import { FaRegMap } from 'react-icons/fa';
|
||||
import { FaExclamationCircle, FaRegMap } from 'react-icons/fa';
|
||||
import { sendTelemetryEvent } from '../../../telemetry';
|
||||
import { useGetSchemaRegistryNotificationColor } from '../../../features/SchemaRegistry/hooks/useGetSchemaRegistryNotificationColor';
|
||||
import { getLSItem, LS_KEYS, setLSItem } from '../../../utils';
|
||||
import {
|
||||
BreakingChangesColor,
|
||||
BreakingChangesTooltipMessage,
|
||||
DangerousChangesColor,
|
||||
DangerousChangesTooltipMessage,
|
||||
DefaultToopTipMessage,
|
||||
SafeChangesColor,
|
||||
SafeChangesTooltipMessage,
|
||||
} from '../../../features/SchemaRegistry/constants';
|
||||
|
||||
type TopNavProps = {
|
||||
location: RouteComponentProps<unknown, unknown>['location'];
|
||||
@ -60,7 +71,54 @@ const TopNav: React.FC<TopNavProps> = ({ location }) => {
|
||||
}
|
||||
return location.pathname.includes(link);
|
||||
};
|
||||
const projectID = globals.hasuraCloudProjectId || '';
|
||||
const fetchSchemaRegistryNotificationData =
|
||||
useGetSchemaRegistryNotificationColor(projectID);
|
||||
let color = '';
|
||||
let tooltipMessage = DefaultToopTipMessage;
|
||||
let change_recorded_at = '';
|
||||
let showNotifications = false;
|
||||
if (fetchSchemaRegistryNotificationData.kind === 'success') {
|
||||
const data =
|
||||
fetchSchemaRegistryNotificationData?.response
|
||||
?.schema_registry_dumps_v2[0] || [];
|
||||
if (
|
||||
data &&
|
||||
data.diff_with_previous_schema &&
|
||||
data.diff_with_previous_schema[0] &&
|
||||
data.diff_with_previous_schema[0].schema_diff_data &&
|
||||
data.change_recorded_at
|
||||
) {
|
||||
const changes = data.diff_with_previous_schema[0].schema_diff_data;
|
||||
// Check if there's a change with a criticality level of "BREAKING"
|
||||
const hasBreakingChange = changes.some(
|
||||
change => change.criticality && change.criticality.level === 'BREAKING'
|
||||
);
|
||||
const hasDangerousChange = changes.some(
|
||||
change => change.criticality && change.criticality.level === 'DANGEROUS'
|
||||
);
|
||||
const last_viewed_change = getLSItem(LS_KEYS.lastViewedSchemaChange);
|
||||
|
||||
if (
|
||||
(!last_viewed_change || last_viewed_change < data.change_recorded_at) &&
|
||||
changes
|
||||
) {
|
||||
if (hasBreakingChange) {
|
||||
color = BreakingChangesColor;
|
||||
tooltipMessage = BreakingChangesTooltipMessage;
|
||||
} else if (hasDangerousChange) {
|
||||
//gold color instead of yellow to be more visible
|
||||
color = DangerousChangesColor;
|
||||
tooltipMessage = DangerousChangesTooltipMessage;
|
||||
} else {
|
||||
color = SafeChangesColor;
|
||||
tooltipMessage = SafeChangesTooltipMessage;
|
||||
}
|
||||
change_recorded_at = data.change_recorded_at;
|
||||
showNotifications = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (
|
||||
<div className="flex justify-between items-center border-b border-gray-300 bg-white px-sm">
|
||||
<div className="flex px-1 w-full">
|
||||
@ -78,6 +136,9 @@ const TopNav: React.FC<TopNavProps> = ({ location }) => {
|
||||
}`}
|
||||
key={section.key}
|
||||
onClick={() => {
|
||||
if (showNotifications) {
|
||||
setLSItem(LS_KEYS.lastViewedSchemaChange, change_recorded_at);
|
||||
}
|
||||
// Send Telemetry data for Schema Registry tab
|
||||
if (section.key === 'schema-registry') {
|
||||
sendTelemetryEvent({
|
||||
@ -97,8 +158,14 @@ const TopNav: React.FC<TopNavProps> = ({ location }) => {
|
||||
{section.title}
|
||||
{section.key === 'schema-registry' && (
|
||||
<IconTooltip
|
||||
icon={<FaRegMap />}
|
||||
message="Detect breaking and dangerous changes, view schema change history. Keep your GraphQL services safe and reliable! 🚀"
|
||||
icon={
|
||||
color ? (
|
||||
<FaExclamationCircle style={{ color }} />
|
||||
) : (
|
||||
<FaRegMap />
|
||||
)
|
||||
}
|
||||
message={tooltipMessage}
|
||||
/>
|
||||
)}
|
||||
</Link>
|
||||
|
@ -380,6 +380,7 @@ const SchemaCard: React.VFC<{
|
||||
</div>
|
||||
<div>
|
||||
{RolesList.map((roleBasedChange, index) => (
|
||||
<Analytics name="schema-registry-schema-change-card">
|
||||
<div
|
||||
className={`flex w-full px-2 py-1 ${
|
||||
isCurrentCardOpen && roleBasedChange.id === selectedRoleID
|
||||
@ -400,6 +401,7 @@ const SchemaCard: React.VFC<{
|
||||
<FaChevronRight />
|
||||
</div>
|
||||
</div>
|
||||
</Analytics>
|
||||
))}
|
||||
{!defaultShowAllRoles && (
|
||||
<Analytics name="schema-registry-see-more-roles-btn">
|
||||
|
@ -17,6 +17,8 @@ export const FETCH_SCHEMA_REGISTRY_DUMPS_V2_QUERY_NAME =
|
||||
export const FETCH_SCHEMA_REGISTRY_DUMPS_V1_QUERY_NAME =
|
||||
'FETCH_SCHEMA_REGISTRY_DUMPS_V1_QUERY_NAME';
|
||||
|
||||
export const FETCH_SCHEMA_REGISTRY_NOTIFICATION_QUERY_NAME =
|
||||
'FETCH_SCHEMA_REGISTRY_NOTIFICATION_QUERY_NAME';
|
||||
// 5 minutes as default stale time
|
||||
export const SCHEMA_REGISTRY_REFRESH_TIME = 5 * 60 * 1000;
|
||||
|
||||
@ -29,3 +31,14 @@ export const SCHEMA_LIST_FETCH_BATCH_SIZE = 10;
|
||||
export const EMPTY_UUID_STRING = '00000000-0000-0000-0000-000000000000';
|
||||
|
||||
export const DEFAULT_TAG_COLOR = '#000000';
|
||||
|
||||
export const BreakingChangesTooltipMessage = 'Breaking changes detected!';
|
||||
export const DangerousChangesTooltipMessage = 'Dangerous changes detected!';
|
||||
export const SafeChangesTooltipMessage = 'Checkout the Latest Schema Change';
|
||||
|
||||
export const DefaultToopTipMessage =
|
||||
'Detect breaking and dangerous changes, view schema change history. Keep your GraphQL services safe and reliable! 🚀';
|
||||
|
||||
export const BreakingChangesColor = 'red';
|
||||
export const DangerousChangesColor = '#FFD700';
|
||||
export const SafeChangesColor = 'green';
|
||||
|
@ -0,0 +1,52 @@
|
||||
import { useQuery } from 'react-query';
|
||||
import { FETCH_SCHEMA_REGISTRY_NOTIFICATION_QUERY_NAME } from '../constants';
|
||||
import { FETCH_SCHEMA_REGISTRY_NOTIFICATION_QUERY } from '../queries';
|
||||
import { GetSchemaRegistryNotificationResponseWithError } from '../types';
|
||||
import { schemaRegsitryControlPlaneClient } from '../utils';
|
||||
|
||||
type FetchSchemaRegistryNotificationResponse =
|
||||
| {
|
||||
kind: 'loading';
|
||||
}
|
||||
| {
|
||||
kind: 'error';
|
||||
}
|
||||
| {
|
||||
kind: 'success';
|
||||
response: NonNullable<
|
||||
GetSchemaRegistryNotificationResponseWithError['data']
|
||||
>;
|
||||
};
|
||||
|
||||
export const useGetSchemaRegistryNotificationColor = (
|
||||
projectId: string
|
||||
): FetchSchemaRegistryNotificationResponse => {
|
||||
const fetchSchemaRegistyNotificationFn = (projectId: string) => {
|
||||
return schemaRegsitryControlPlaneClient.query<
|
||||
GetSchemaRegistryNotificationResponseWithError,
|
||||
{ projectId: string }
|
||||
>(FETCH_SCHEMA_REGISTRY_NOTIFICATION_QUERY, {
|
||||
projectId: projectId,
|
||||
});
|
||||
};
|
||||
const { data, error, isLoading } = useQuery({
|
||||
queryKey: FETCH_SCHEMA_REGISTRY_NOTIFICATION_QUERY_NAME,
|
||||
queryFn: () => fetchSchemaRegistyNotificationFn(projectId),
|
||||
refetchOnMount: 'always',
|
||||
refetchOnWindowFocus: true,
|
||||
});
|
||||
if (isLoading) {
|
||||
return {
|
||||
kind: 'loading',
|
||||
};
|
||||
}
|
||||
if (error || !data || !!data?.errors || !data?.data) {
|
||||
return {
|
||||
kind: 'error',
|
||||
};
|
||||
}
|
||||
return {
|
||||
kind: 'success',
|
||||
response: data.data,
|
||||
};
|
||||
};
|
@ -134,6 +134,16 @@ query fetchSchemaRegistryDumpsV2($projectId: uuid!, $limit: Int!, $offset: Int!)
|
||||
}
|
||||
}
|
||||
`);
|
||||
export const FETCH_SCHEMA_REGISTRY_NOTIFICATION_QUERY = gql(`
|
||||
query fetchSchemaRegistryDumpsV2($projectId: uuid!) {
|
||||
schema_registry_dumps_v2(where: {_and: [{project_id: {_eq: $projectId}, hasura_schema_role: {_eq: "admin"}}]}, order_by: {change_recorded_at: desc}, limit: 1) {
|
||||
change_recorded_at
|
||||
diff_with_previous_schema {
|
||||
schema_diff_data
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
export const FETCH_SCHEMA_REGISTRY_DUMPS_V1_QUERY = gql(`
|
||||
query fetchSchemaRegistryDumpsV1($projectId: uuid!, $limit: Int!, $offset: Int!, $changeTimestamp: timestamptz!) {
|
||||
|
@ -90,6 +90,11 @@ export type GetSchemaRegstiryDumpsV2AggregateResponseWithError = {
|
||||
errors?: GraphQLError[];
|
||||
};
|
||||
|
||||
export type GetSchemaRegistryNotificationResponseWithError = {
|
||||
data?: GetSchemaRegistryNotificationResponse;
|
||||
errors?: GraphQLError[];
|
||||
};
|
||||
|
||||
export type GetSchemaRegstiryDumpsV2AggregateResponse = {
|
||||
schema_registry_dumps_v2_aggregate: SchemaRegistryDumpsAggregate;
|
||||
schema_registry_dumps_v2: SchemaRegistryChangeRecordedAt[];
|
||||
@ -101,6 +106,12 @@ export type GetSchemaRegstiryDumpsV1AggregateResponseWithError = {
|
||||
export type GetSchemaRegstiryDumpsV1AggregateResponse = {
|
||||
schema_registry_dumps_aggregate: SchemaRegistryDumpsAggregate;
|
||||
};
|
||||
export type GetSchemaRegistryNotificationResponse = {
|
||||
schema_registry_dumps_v2: SchemaRegsitryNotificationData[];
|
||||
};
|
||||
export type SchemaRegsitryNotificationData = SchemaRegistryChangeRecordedAt & {
|
||||
diff_with_previous_schema: SchemaDiffData[];
|
||||
};
|
||||
export type SchemaRegistryChangeRecordedAt = {
|
||||
change_recorded_at: string;
|
||||
};
|
||||
|
@ -126,6 +126,7 @@ export const LS_KEYS = {
|
||||
notificationsLastSeen: 'notifications:lastSeen',
|
||||
authState: 'AUTH_STATE',
|
||||
skipOnboarding: 'SKIP_CLOUD_ONBOARDING',
|
||||
lastViewedSchemaChange: 'LAST_VIEWED_SCHEMA_CHANGE',
|
||||
};
|
||||
|
||||
export const clearGraphiqlLS = () => {
|
||||
|
Loading…
Reference in New Issue
Block a user