From 23b1b1a33a43fe466aa2b55171615b2a8df5332e Mon Sep 17 00:00:00 2001 From: Ciaran Morinan Date: Fri, 6 Dec 2024 19:35:54 +0000 Subject: [PATCH 1/5] wip: only request notification count when polling app-wide --- .../queries/knowledge/entity.queries.ts | 1 + apps/hash-frontend/src/pages/_app.page.tsx | 6 +- .../draft-entities-bulk-actions-dropdown.tsx | 4 +- .../src/pages/notifications.page.tsx | 4 +- .../shared/accept-draft-entity-button.tsx | 4 +- .../shared/discard-draft-entity-button.tsx | 4 +- .../notifications-with-links-context.tsx | 111 +++++---- .../notifications-dropdown.tsx | 4 +- .../layout/layout-with-sidebar/sidebar.tsx | 4 +- .../shared/notification-entities-context.tsx | 154 +++++------- .../src/types/generated/block-entity.ts | 53 ++-- .../code/src/types/generated/block-entity.ts | 61 +++-- .../src/types/generated/block-entity.ts | 59 +++-- .../src/types/generated/block-entity.ts | 60 +++-- .../src/types/generated/block-entity.ts | 71 ------ .../image/src/types/generated/block-entity.ts | 235 ++++++++++++------ .../src/types/generated/block-entity.ts | 45 ++-- .../src/types/generated/block-entity.ts | 44 +++- .../timer/src/types/generated/block-entity.ts | 77 +++--- .../video/src/types/generated/block-entity.ts | 200 --------------- .../type-defs/knowledge/entity.typedef.ts | 1 + 21 files changed, 562 insertions(+), 640 deletions(-) delete mode 100644 blocks/heading/src/types/generated/block-entity.ts delete mode 100644 blocks/video/src/types/generated/block-entity.ts diff --git a/apps/hash-frontend/src/graphql/queries/knowledge/entity.queries.ts b/apps/hash-frontend/src/graphql/queries/knowledge/entity.queries.ts index f690f36727c..6b55c04f0d9 100644 --- a/apps/hash-frontend/src/graphql/queries/knowledge/entity.queries.ts +++ b/apps/hash-frontend/src/graphql/queries/knowledge/entity.queries.ts @@ -62,6 +62,7 @@ export const getEntitySubgraphQuery = gql` ) { getEntitySubgraph(request: $request) { closedMultiEntityTypes + count definitions userPermissionsOnEntities @include(if: $includePermissions) subgraph { diff --git a/apps/hash-frontend/src/pages/_app.page.tsx b/apps/hash-frontend/src/pages/_app.page.tsx index 7686fa7fb13..bc0b0932a0e 100644 --- a/apps/hash-frontend/src/pages/_app.page.tsx +++ b/apps/hash-frontend/src/pages/_app.page.tsx @@ -42,7 +42,7 @@ import { KeyboardShortcutsContextProvider } from "../shared/keyboard-shortcuts-c import type { NextPageWithLayout } from "../shared/layout"; import { getLayoutWithSidebar, getPlainLayout } from "../shared/layout"; import { SidebarContextProvider } from "../shared/layout/layout-with-sidebar/sidebar-context"; -import { NotificationEntitiesContextProvider } from "../shared/notification-entities-context"; +import { NotificationCountContextProvider } from "../shared/notification-entities-context"; import { PropertyTypesContextProvider } from "../shared/property-types-context"; import { RoutePageInfoProvider } from "../shared/routing"; import { ErrorFallback } from "./_app.page/error-fallback"; @@ -108,7 +108,7 @@ const App: FunctionComponent = ({ - + @@ -133,7 +133,7 @@ const App: FunctionComponent = ({ - + diff --git a/apps/hash-frontend/src/pages/actions.page/draft-entities-bulk-actions-dropdown.tsx b/apps/hash-frontend/src/pages/actions.page/draft-entities-bulk-actions-dropdown.tsx index 67a2634d9d6..ab423dc850b 100644 --- a/apps/hash-frontend/src/pages/actions.page/draft-entities-bulk-actions-dropdown.tsx +++ b/apps/hash-frontend/src/pages/actions.page/draft-entities-bulk-actions-dropdown.tsx @@ -30,7 +30,7 @@ import { } from "../../graphql/queries/knowledge/entity.queries"; import { useDraftEntities } from "../../shared/draft-entities-context"; import { LayerGroupLightIcon } from "../../shared/icons/layer-group-light-icon"; -import { useNotificationEntities } from "../../shared/notification-entities-context"; +import { useNotificationCount } from "../../shared/notification-entities-context"; import { Button, MenuItem } from "../../shared/ui"; import { useNotificationsWithLinks } from "../shared/notifications-with-links-context"; @@ -46,7 +46,7 @@ export const DraftEntitiesBulkActionsDropdown: FunctionComponent<{ const { draftEntities, refetch: refetchDraftEntities } = useDraftEntities(); const { notifications } = useNotificationsWithLinks(); const { archiveNotifications, markNotificationsAsRead } = - useNotificationEntities(); + useNotificationCount(); const popupState = usePopupState({ variant: "popover", diff --git a/apps/hash-frontend/src/pages/notifications.page.tsx b/apps/hash-frontend/src/pages/notifications.page.tsx index efe5d34bf3b..8e016edf544 100644 --- a/apps/hash-frontend/src/pages/notifications.page.tsx +++ b/apps/hash-frontend/src/pages/notifications.page.tsx @@ -36,7 +36,7 @@ import { useUserOrOrgShortnameByOwnedById } from "../components/hooks/use-user-o import { constructPageRelativeUrl } from "../lib/routes"; import type { NextPageWithLayout } from "../shared/layout"; import { getLayoutWithSidebar } from "../shared/layout"; -import { useNotificationEntities } from "../shared/notification-entities-context"; +import { useNotificationCount } from "../shared/notification-entities-context"; import { Button, Link } from "../shared/ui"; import type { GraphChangeNotification, @@ -173,7 +173,7 @@ const PageRelatedNotificationContent = ({ const NotificationRow: FunctionComponent<{ notification: Notification }> = ({ notification, }) => { - const { markNotificationAsRead } = useNotificationEntities(); + const { markNotificationAsRead } = useNotificationCount(); const handleNotificationClick = useCallback(async () => { await markNotificationAsRead({ notificationEntity: notification.entity }); diff --git a/apps/hash-frontend/src/pages/shared/accept-draft-entity-button.tsx b/apps/hash-frontend/src/pages/shared/accept-draft-entity-button.tsx index 2b1213afc50..03d3daaef4d 100644 --- a/apps/hash-frontend/src/pages/shared/accept-draft-entity-button.tsx +++ b/apps/hash-frontend/src/pages/shared/accept-draft-entity-button.tsx @@ -17,7 +17,7 @@ import type { import { updateEntityMutation } from "../../graphql/queries/knowledge/entity.queries"; import { useDraftEntities } from "../../shared/draft-entities-context"; import { CheckRegularIcon } from "../../shared/icons/check-regular-icon"; -import { useNotificationEntities } from "../../shared/notification-entities-context"; +import { useNotificationCount } from "../../shared/notification-entities-context"; import type { ButtonProps } from "../../shared/ui"; import { Button } from "../../shared/ui"; import { LinkLabelWithSourceAndDestination } from "./link-label-with-source-and-destination"; @@ -138,7 +138,7 @@ export const AcceptDraftEntityButton: FunctionComponent< const { refetch: refetchDraftEntities } = useDraftEntities(); - const { markNotificationAsRead } = useNotificationEntities(); + const { markNotificationAsRead } = useNotificationCount(); const { notifications } = useNotificationsWithLinks(); /** diff --git a/apps/hash-frontend/src/pages/shared/discard-draft-entity-button.tsx b/apps/hash-frontend/src/pages/shared/discard-draft-entity-button.tsx index 2b101ca5252..c953fa307f8 100644 --- a/apps/hash-frontend/src/pages/shared/discard-draft-entity-button.tsx +++ b/apps/hash-frontend/src/pages/shared/discard-draft-entity-button.tsx @@ -17,7 +17,7 @@ import type { } from "../../graphql/api-types.gen"; import { archiveEntityMutation } from "../../graphql/queries/knowledge/entity.queries"; import { useDraftEntities } from "../../shared/draft-entities-context"; -import { useNotificationEntities } from "../../shared/notification-entities-context"; +import { useNotificationCount } from "../../shared/notification-entities-context"; import type { ButtonProps } from "../../shared/ui"; import { Button } from "../../shared/ui"; import { useNotificationsWithLinks } from "./notifications-with-links-context"; @@ -36,7 +36,7 @@ export const DiscardDraftEntityButton: FunctionComponent< }) => { const { refetch: refetchDraftEntities } = useDraftEntities(); - const { archiveNotification } = useNotificationEntities(); + const { archiveNotification } = useNotificationCount(); const { notifications } = useNotificationsWithLinks(); diff --git a/apps/hash-frontend/src/pages/shared/notifications-with-links-context.tsx b/apps/hash-frontend/src/pages/shared/notifications-with-links-context.tsx index 3947902d5c9..6391e8a80f6 100644 --- a/apps/hash-frontend/src/pages/shared/notifications-with-links-context.tsx +++ b/apps/hash-frontend/src/pages/shared/notifications-with-links-context.tsx @@ -1,13 +1,14 @@ import { useQuery } from "@apollo/client"; import type { VersionedUrl } from "@blockprotocol/type-system"; import { typedEntries, typedValues } from "@local/advanced-types/typed-entries"; -import type { Filter } from "@local/hash-graph-client"; import type { Entity } from "@local/hash-graph-sdk/entity"; import type { TextWithTokens } from "@local/hash-isomorphic-utils/entity"; import { generateEntityLabel } from "@local/hash-isomorphic-utils/generate-entity-label"; import { currentTimeInstantTemporalAxes, + generateVersionedUrlMatchingFilter, mapGqlSubgraphFieldsFragmentToSubgraph, + pageOrNotificationNotArchivedFilter, zeroedGraphResolveDepths, } from "@local/hash-isomorphic-utils/graph-queries"; import { @@ -32,8 +33,10 @@ import type { EntityVertex, LinkEntityAndRightEntity, } from "@local/hash-subgraph"; -import { extractEntityUuidFromEntityId } from "@local/hash-subgraph"; -import { getOutgoingLinkAndTargetEntities } from "@local/hash-subgraph/stdlib"; +import { + getOutgoingLinkAndTargetEntities, + getRoots, +} from "@local/hash-subgraph/stdlib"; import type { FunctionComponent, PropsWithChildren } from "react"; import { createContext, useContext, useMemo, useRef } from "react"; @@ -44,7 +47,8 @@ import type { import { getEntitySubgraphQuery } from "../../graphql/queries/knowledge/entity.queries"; import type { MinimalUser } from "../../lib/user-and-org"; import { constructMinimalUser } from "../../lib/user-and-org"; -import { useNotificationEntities } from "../../shared/notification-entities-context"; +import { pollInterval } from "../../shared/poll-interval"; +import { useAuthInfo } from "./auth-info-context"; export type PageMentionNotification = { kind: "page-mention"; @@ -118,24 +122,7 @@ const isLinkAndRightEntityWithLinkType = export const useNotificationsWithLinksContextValue = (): NotificationsWithLinksContextValue => { - const { notificationEntities } = useNotificationEntities(); - - const getNotificationEntitiesFilter = useMemo( - () => ({ - any: - notificationEntities?.map((entity) => ({ - equal: [ - { path: ["uuid"] }, - { - parameter: extractEntityUuidFromEntityId( - entity.metadata.recordId.entityId, - ), - }, - ], - })) ?? [], - }), - [notificationEntities], - ); + const { authenticatedUser } = useAuthInfo(); const { data: notificationsWithOutgoingLinksData } = useQuery< GetEntitySubgraphQuery, @@ -144,7 +131,21 @@ export const useNotificationsWithLinksContextValue = variables: { includePermissions: false, request: { - filter: getNotificationEntitiesFilter, + filter: { + all: [ + { + equal: [ + { path: ["ownedById"] }, + { parameter: authenticatedUser?.accountId }, + ], + }, + generateVersionedUrlMatchingFilter( + systemEntityTypes.notification.entityTypeId, + { ignoreParents: false }, + ), + pageOrNotificationNotArchivedFilter, + ], + }, graphResolveDepths: { ...zeroedGraphResolveDepths, inheritsFrom: { outgoing: 255 }, @@ -157,16 +158,17 @@ export const useNotificationsWithLinksContextValue = includeDrafts: true, }, }, - skip: !notificationEntities || notificationEntities.length === 0, + skip: !authenticatedUser, fetchPolicy: "network-only", + pollInterval, }); - const outgoingLinksSubgraph = useMemo( + const notificationsSubgraph = useMemo( () => notificationsWithOutgoingLinksData - ? mapGqlSubgraphFieldsFragmentToSubgraph( - notificationsWithOutgoingLinksData.getEntitySubgraph.subgraph, - ) + ? mapGqlSubgraphFieldsFragmentToSubgraph< + EntityRootType + >(notificationsWithOutgoingLinksData.getEntitySubgraph.subgraph) : undefined, [notificationsWithOutgoingLinksData], ); @@ -176,12 +178,12 @@ export const useNotificationsWithLinksContextValue = ); const notifications = useMemo(() => { - if (notificationEntities && notificationEntities.length === 0) { - return []; - } else if (!outgoingLinksSubgraph || !notificationEntities) { + if (!notificationsSubgraph) { return previouslyFetchedNotificationsRef.current ?? undefined; } + const notificationEntities = getRoots(notificationsSubgraph); + const derivedNotifications = notificationEntities .map((entity) => { const { @@ -194,7 +196,7 @@ export const useNotificationsWithLinksContextValue = const { readAt } = simplifyProperties(entity.properties); const outgoingLinks = getOutgoingLinkAndTargetEntities( - outgoingLinksSubgraph, + notificationsSubgraph, entityId, ); @@ -252,7 +254,8 @@ export const useNotificationsWithLinksContextValue = return { kind: "comment-mention", readAt, - entity: entity as Entity, + entity: + entity as unknown as Entity, occurredInEntity: occurredInEntity as Entity, occurredInBlock: occurredInBlock as Entity, occurredInText: occurredInText as Entity, @@ -265,7 +268,8 @@ export const useNotificationsWithLinksContextValue = return { kind: "page-mention", readAt, - entity: entity as Entity, + entity: + entity as unknown as Entity, occurredInEntity: occurredInEntity as Entity, occurredInBlock: occurredInBlock as Entity, occurredInText: occurredInText as Entity, @@ -325,7 +329,8 @@ export const useNotificationsWithLinksContextValue = return { kind: "comment-reply", readAt, - entity: entity as Entity, + entity: + entity as unknown as Entity, occurredInEntity: occurredInEntity as Entity, occurredInBlock: occurredInBlock as Entity, triggeredByComment: @@ -338,7 +343,8 @@ export const useNotificationsWithLinksContextValue = return { kind: "new-comment", readAt, - entity: entity as Entity, + entity: + entity as unknown as Entity, occurredInEntity: occurredInEntity as Entity, occurredInBlock: occurredInBlock as Entity, triggeredByComment: @@ -380,14 +386,15 @@ export const useNotificationsWithLinksContextValue = let occurredInEntity: Entity | undefined; for (const [vertexKey, editionMap] of typedEntries( - outgoingLinksSubgraph.vertices, + notificationsSubgraph.vertices, )) { /** - * The created/updated record might be a draft, in which case it is keyed in the subgraph by `${entityId}~${draftId}`. - * We need to find the vertex that _starts with_ the entityId and contains an edition at the exact timestamp from the link. - * Needing to do this is a limitation caused by: + * The created/updated record might be a draft, in which case it is keyed in the subgraph by + * `${entityId}~${draftId}`. We need to find the vertex that _starts with_ the entityId and contains an + * edition at the exact timestamp from the link. Needing to do this is a limitation caused by: * 1. The fact that links only point to the entire Entity, not any specific edition or draft series of it - * 2. The logic for returning linked entities from the subgraph library will just return the non-draft entity if it is found + * 2. The logic for returning linked entities from the subgraph library will just return the non-draft + * entity if it is found */ if (!vertexKey.startsWith(linkRightEntityId)) { continue; @@ -396,9 +403,9 @@ export const useNotificationsWithLinksContextValue = const editions = typedValues(editionMap).flat(); /** - * We have a candidate – this might be one of multiple draft series for the entity, or the single live series. - * We match the timestamp logged in the link to the editions of the entity. - * This may result in a false positive if the live entity and any of its drafts have editions at the exact same timestamp. + * We have a candidate – this might be one of multiple draft series for the entity, or the single live + * series. We match the timestamp logged in the link to the editions of the entity. This may result in a + * false positive if the live entity and any of its drafts have editions at the exact same timestamp. */ occurredInEntity = editions.find( (vertex): vertex is EntityVertex => @@ -412,12 +419,12 @@ export const useNotificationsWithLinksContextValue = } /** - * If the entity has been updated since the notification was created, we won't have the edition in the subgraph, - * because the request above only fetches editions still valid for the current timestamp. - * In order to show the notification we just take any available edition. + * If the entity has been updated since the notification was created, we won't have the edition in the + * subgraph, because the request above only fetches editions still valid for the current timestamp. In + * order to show the notification we just take any available edition. * - * The other option would be to fetch the entire history for all entities which are the subject of a notification, - * but this might be a lot of data. + * The other option would be to fetch the entire history for all entities which are the subject of a + * notification, but this might be a lot of data. */ const anyAvailableEdition = editions.find( (vertex): vertex is EntityVertex => vertex.kind === "entity", @@ -435,14 +442,14 @@ export const useNotificationsWithLinksContextValue = } const graphChangeEntity = - entity as Entity; + entity as unknown as Entity; return { kind: "graph-change", readAt, entity: graphChangeEntity, occurredInEntityLabel: generateEntityLabel( - outgoingLinksSubgraph, + notificationsSubgraph, occurredInEntity, ), occurredInEntityEditionTimestamp, @@ -489,7 +496,7 @@ export const useNotificationsWithLinksContextValue = previouslyFetchedNotificationsRef.current = derivedNotifications; return derivedNotifications; - }, [notificationEntities, outgoingLinksSubgraph]); + }, [notificationsSubgraph]); return { notifications }; }; diff --git a/apps/hash-frontend/src/shared/layout/layout-with-header/notifications-dropdown.tsx b/apps/hash-frontend/src/shared/layout/layout-with-header/notifications-dropdown.tsx index d87da417b3b..bdb83249ec7 100644 --- a/apps/hash-frontend/src/shared/layout/layout-with-header/notifications-dropdown.tsx +++ b/apps/hash-frontend/src/shared/layout/layout-with-header/notifications-dropdown.tsx @@ -3,14 +3,14 @@ import { FontAwesomeIcon } from "@hashintel/design-system"; import { Tooltip, useTheme } from "@mui/material"; import type { FunctionComponent } from "react"; -import { useNotificationEntities } from "../../notification-entities-context"; +import { useNotificationCount } from "../../notification-entities-context"; import { Link } from "../../ui"; import { HeaderIconButtonWithCount } from "./shared/header-icon-button-with-count"; export const NotificationsDropdown: FunctionComponent = () => { const theme = useTheme(); - const { numberOfUnreadNotifications } = useNotificationEntities(); + const { numberOfUnreadNotifications } = useNotificationCount(); return ( diff --git a/apps/hash-frontend/src/shared/layout/layout-with-sidebar/sidebar.tsx b/apps/hash-frontend/src/shared/layout/layout-with-sidebar/sidebar.tsx index a335c56e5fc..018ac9716c3 100644 --- a/apps/hash-frontend/src/shared/layout/layout-with-sidebar/sidebar.tsx +++ b/apps/hash-frontend/src/shared/layout/layout-with-sidebar/sidebar.tsx @@ -22,7 +22,7 @@ import { ArrowRightToLineIcon } from "../../icons"; import { BoltLightIcon } from "../../icons/bolt-light-icon"; import { InboxIcon } from "../../icons/inbox-icon"; import { NoteIcon } from "../../icons/note-icon"; -import { useNotificationEntities } from "../../notification-entities-context"; +import { useNotificationCount } from "../../notification-entities-context"; import { useRoutePageInfo } from "../../routing"; import { useUserPreferences } from "../../use-user-preferences"; import { AccountEntitiesList } from "./sidebar/account-entities-list"; @@ -72,7 +72,7 @@ export const PageSidebar: FunctionComponent = () => { const { hashInstance } = useHashInstance(); - const { numberOfUnreadNotifications } = useNotificationEntities(); + const { numberOfUnreadNotifications } = useNotificationCount(); const { draftEntities } = useDraftEntities(); diff --git a/apps/hash-frontend/src/shared/notification-entities-context.tsx b/apps/hash-frontend/src/shared/notification-entities-context.tsx index c7a8b1787ca..b55cc88e1bf 100644 --- a/apps/hash-frontend/src/shared/notification-entities-context.tsx +++ b/apps/hash-frontend/src/shared/notification-entities-context.tsx @@ -1,5 +1,6 @@ import { useMutation, useQuery } from "@apollo/client"; import type { Entity } from "@local/hash-graph-sdk/entity"; +import type { EntityId } from "@local/hash-graph-types/entity"; import type { BaseUrl } from "@local/hash-graph-types/ontology"; import { currentTimeInstantTemporalAxes, @@ -39,52 +40,46 @@ import { import { useAuthInfo } from "../pages/shared/auth-info-context"; import { pollInterval } from "./poll-interval"; -export type NotificationEntitiesContextValues = { - notificationEntities?: Entity< - | Notification - | MentionNotification - | CommentNotification - | GraphChangeNotification - >[]; +export type NotificationCountContextValues = { numberOfUnreadNotifications?: number; loading: boolean; refetch: () => Promise; markNotificationAsRead: (params: { - notificationEntity: Entity; + notificationEntityId: EntityId; }) => Promise; markNotificationsAsRead: (params: { - notificationEntities: Entity[]; + notificationEntityIds: EntityId[]; }) => Promise; archiveNotification: (params: { - notificationEntity: Entity; + notificationEntityId: EntityId; }) => Promise; archiveNotifications: (params: { - notificationEntities: Entity[]; + notificationEntityIds: EntityId[]; }) => Promise; }; -export const NotificationEntitiesContext = - createContext(null); +export const NotificationCountContext = + createContext(null); -export const useNotificationEntities = () => { - const notificationsEntitiesContext = useContext(NotificationEntitiesContext); +export const useNotificationCount = () => { + const notificationCountContext = useContext(NotificationCountContext); - if (!notificationsEntitiesContext) { + if (!notificationCountContext) { throw new Error("Context missing"); } - return notificationsEntitiesContext; + return notificationCountContext; }; -export const NotificationEntitiesContextProvider: FunctionComponent< +export const NotificationCountContextProvider: FunctionComponent< PropsWithChildren > = ({ children }) => { const { authenticatedUser } = useAuthInfo(); const { - data: notificationEntitiesData, - loading: loadingNotificationEntities, - refetch: refetchNotificationEntities, + data: notificationCountData, + loading: loadingNotificationCount, + refetch: refetchNotificationCount, } = useQuery( getEntitySubgraphQuery, { @@ -110,6 +105,8 @@ export const NotificationEntitiesContextProvider: FunctionComponent< graphResolveDepths: zeroedGraphResolveDepths, temporalAxes: currentTimeInstantTemporalAxes, includeDrafts: false, + includeCount: true, + limit: 0, }, }, skip: !authenticatedUser, @@ -117,51 +114,27 @@ export const NotificationEntitiesContextProvider: FunctionComponent< }, ); - const notificationEntitiesSubgraph = useMemo( - () => - notificationEntitiesData - ? mapGqlSubgraphFieldsFragmentToSubgraph>( - notificationEntitiesData.getEntitySubgraph.subgraph, - ) - : undefined, - [notificationEntitiesData], - ); - - const notificationEntities = useMemo< - | Entity< - | Notification - | MentionNotification - | CommentNotification - | GraphChangeNotification - >[] - | undefined - >( - () => - notificationEntitiesSubgraph - ? getRoots(notificationEntitiesSubgraph) - : undefined, - [notificationEntitiesSubgraph], - ); - const refetch = useCallback(async () => { - await refetchNotificationEntities(); - }, [refetchNotificationEntities]); + await refetchNotificationCount(); + }, [refetchNotificationCount]); const [updateEntity] = useMutation< UpdateEntityMutation, UpdateEntityMutationVariables >(updateEntityMutation); - const markNotificationAsRead = useCallback( - async (params: { notificationEntity: Entity }) => { - const { notificationEntity } = params; + const markNotificationAsRead = useCallback< + NotificationCountContextValues["markNotificationAsRead"] + >( + async (params) => { + const { notificationEntityId } = params; const now = new Date(); await updateEntity({ variables: { entityUpdate: { - entityId: notificationEntity.metadata.recordId.entityId, + entityId: notificationEntityId, propertyPatches: [ { op: "add", @@ -191,16 +164,17 @@ export const NotificationEntitiesContextProvider: FunctionComponent< UpdateEntitiesMutationVariables >(updateEntitiesMutation); - const markNotificationsAsRead = useCallback( - async (params: { notificationEntities: Entity[] }) => { + const markNotificationsAsRead = useCallback< + NotificationCountContextValues["markNotificationsAsRead"] + >( + async (params) => { const now = new Date(); await updateEntities({ variables: { - entityUpdates: params.notificationEntities.map( - (notificationEntity) => ({ - entityId: notificationEntity.metadata.recordId.entityId, - entityTypeIds: notificationEntity.metadata.entityTypeIds, + entityUpdates: params.notificationEntityIds.map( + (notificationEntityId) => ({ + entityId: notificationEntityId, propertyPatches: [ { op: "add", @@ -226,15 +200,16 @@ export const NotificationEntitiesContextProvider: FunctionComponent< [updateEntities, refetch], ); - const archiveNotification = useCallback( - async (params: { notificationEntity: Entity; shouldRefetch?: boolean }) => { - const { notificationEntity, shouldRefetch = true } = params; + const archiveNotification = useCallback< + NotificationCountContextValues["archiveNotification"] + >( + async (params) => { + const { notificationEntityId } = params; await updateEntity({ variables: { entityUpdate: { - entityId: notificationEntity.metadata.recordId.entityId, - entityTypeIds: notificationEntity.metadata.entityTypeIds, + entityId: notificationEntityId, propertyPatches: [ { op: "add", @@ -254,21 +229,20 @@ export const NotificationEntitiesContextProvider: FunctionComponent< }, }); - if (shouldRefetch) { - await refetch(); - } + await refetch(); }, [updateEntity, refetch], ); - const archiveNotifications = useCallback( - async (params: { notificationEntities: Entity[] }) => { + const archiveNotifications = useCallback< + NotificationCountContextValues["archiveNotifications"] + >( + async (params) => { await updateEntities({ variables: { - entityUpdates: params.notificationEntities.map( - (notificationEntity) => ({ - entityId: notificationEntity.metadata.recordId.entityId, - entityTypeIds: notificationEntity.metadata.entityTypeIds, + entityUpdates: params.notificationEntityIds.map( + (notificationEntityId) => ({ + entityId: notificationEntityId, propertyPatches: [ { op: "add", @@ -293,42 +267,30 @@ export const NotificationEntitiesContextProvider: FunctionComponent< [updateEntities, refetch], ); - const numberOfUnreadNotifications = useMemo( - () => - notificationEntities?.filter(({ properties }) => { - const { readAt } = simplifyProperties(properties); - - return !readAt; - }).length, - [notificationEntities], - ); - - const value = useMemo( + const value = useMemo( () => ({ - notificationEntities, - numberOfUnreadNotifications, - loading: loadingNotificationEntities, + archiveNotification, archiveNotifications, - refetch, + loading: loadingNotificationCount, markNotificationAsRead, markNotificationsAsRead, - archiveNotification, + numberOfUnreadNotifications: notificationCountData?.getEntitySubgraph, + refetch, }), [ - notificationEntities, - numberOfUnreadNotifications, + archiveNotification, archiveNotifications, - loadingNotificationEntities, - refetch, + loadingNotificationCount, markNotificationAsRead, markNotificationsAsRead, - archiveNotification, + notificationCountData, + refetch, ], ); return ( - + {children} - + ); }; diff --git a/blocks/callout/src/types/generated/block-entity.ts b/blocks/callout/src/types/generated/block-entity.ts index 226232a9c33..8dd781dc4ee 100644 --- a/blocks/callout/src/types/generated/block-entity.ts +++ b/blocks/callout/src/types/generated/block-entity.ts @@ -2,47 +2,68 @@ * This file was automatically generated – do not edit it. */ -import { Entity } from "@blockprotocol/graph"; +import { Entity } from "@blockprotocol/graph" -export type BlockEntity = CalloutBlock; -export type BlockEntityOutgoingLinkAndTarget = - CalloutBlockOutgoingLinkAndTarget; -export type CalloutBlock = Entity; + + +export type BlockEntity = CalloutBlock + + + +export type BlockEntityOutgoingLinkAndTarget = CalloutBlockOutgoingLinkAndTarget + + + +export type CalloutBlock = Entity + /** * A Unicode emoji displayed along the textual contents of a Callout block. - * + * * See: https://unicode.org/emoji/charts/full-emoji-list.html */ -export type CalloutBlockEmojiPropertyValue = TextDataType; +export type CalloutBlockEmojiPropertyValue = TextDataType + + + +export type CalloutBlockOutgoingLinkAndTarget = never + +export type CalloutBlockOutgoingLinksByLinkEntityTypeId = { } + -export type CalloutBlockOutgoingLinkAndTarget = never; -export type CalloutBlockOutgoingLinksByLinkEntityTypeId = {}; /** * The block entity for the “Callout” block. - * + * * See: https://blockprotocol.org/@hash/blocks/callout */ export type CalloutBlockProperties = { - "https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/"?: TextualContentPropertyValue; - "https://blockprotocol.org/@hash/types/property-type/callout-block-emoji/"?: CalloutBlockEmojiPropertyValue; -}; +"https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/"?: TextualContentPropertyValue +"https://blockprotocol.org/@hash/types/property-type/callout-block-emoji/"?: CalloutBlockEmojiPropertyValue +} + /** * An opaque, untyped JSON object */ -export type ObjectDataType = {}; +export type ObjectDataType = { + +} + /** * An ordered sequence of characters */ -export type TextDataType = string; +export type TextDataType = string + /** * The text material, information, or body, that makes up the content of this thing. */ -export type TextualContentPropertyValue = TextDataType | ObjectDataType[]; +export type TextualContentPropertyValue = (TextDataType | ObjectDataType[]) + + + diff --git a/blocks/code/src/types/generated/block-entity.ts b/blocks/code/src/types/generated/block-entity.ts index 9c678dc8b88..b1335f8ee6f 100644 --- a/blocks/code/src/types/generated/block-entity.ts +++ b/blocks/code/src/types/generated/block-entity.ts @@ -2,54 +2,79 @@ * This file was automatically generated – do not edit it. */ -import { Entity } from "@blockprotocol/graph"; +import { Entity } from "@blockprotocol/graph" -export type BlockEntity = CodeBlock; -export type BlockEntityOutgoingLinkAndTarget = CodeBlockOutgoingLinkAndTarget; + + + +export type BlockEntity = CodeBlock + + + +export type BlockEntityOutgoingLinkAndTarget = CodeBlockOutgoingLinkAndTarget + /** * A brief explanation or accompanying message. */ -export type CaptionPropertyValue = TextDataType; +export type CaptionPropertyValue = TextDataType + + + + +export type CodeBlock = Entity -export type CodeBlock = Entity; /** * A description of the language the code is written in. - * + * * This should conform to one of the languages supported by Prism, for example "javascript". - * + * * See: https://prismjs.com/#supported-languages */ -export type CodeBlockLanguagePropertyValue = TextDataType; +export type CodeBlockLanguagePropertyValue = TextDataType + + + +export type CodeBlockOutgoingLinkAndTarget = never + +export type CodeBlockOutgoingLinksByLinkEntityTypeId = { } + + -export type CodeBlockOutgoingLinkAndTarget = never; -export type CodeBlockOutgoingLinksByLinkEntityTypeId = {}; /** * The block entity of the “Code” block. - * + * * See: https://blockprotocol.org/@hash/blocks/code */ export type CodeBlockProperties = { - "https://blockprotocol.org/@blockprotocol/types/property-type/caption/"?: CaptionPropertyValue; - "https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/"?: TextualContentPropertyValue; - "https://blockprotocol.org/@hash/types/property-type/code-block-language/"?: CodeBlockLanguagePropertyValue; -}; +"https://blockprotocol.org/@blockprotocol/types/property-type/caption/"?: CaptionPropertyValue +"https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/"?: TextualContentPropertyValue +"https://blockprotocol.org/@hash/types/property-type/code-block-language/"?: CodeBlockLanguagePropertyValue +} + /** * An opaque, untyped JSON object */ -export type ObjectDataType = {}; +export type ObjectDataType = { + +} + /** * An ordered sequence of characters */ -export type TextDataType = string; +export type TextDataType = string + /** * The text material, information, or body, that makes up the content of this thing. */ -export type TextualContentPropertyValue = TextDataType | ObjectDataType[]; +export type TextualContentPropertyValue = (TextDataType | ObjectDataType[]) + + + diff --git a/blocks/countdown/src/types/generated/block-entity.ts b/blocks/countdown/src/types/generated/block-entity.ts index 0ff9b56f4c5..6bc08ea0542 100644 --- a/blocks/countdown/src/types/generated/block-entity.ts +++ b/blocks/countdown/src/types/generated/block-entity.ts @@ -2,55 +2,76 @@ * This file was automatically generated – do not edit it. */ -import { Entity } from "@blockprotocol/graph"; +import { Entity } from "@blockprotocol/graph" -export type BlockEntity = CountdownBlock; -export type BlockEntityOutgoingLinkAndTarget = - CountdownBlockOutgoingLinkAndTarget; + + + +export type BlockEntity = CountdownBlock + + + +export type BlockEntityOutgoingLinkAndTarget = CountdownBlockOutgoingLinkAndTarget + /** * A True or False value */ -export type BooleanDataType = boolean; +export type BooleanDataType = boolean + + + +export type CountdownBlock = Entity + + +export type CountdownBlockOutgoingLinkAndTarget = never + +export type CountdownBlockOutgoingLinksByLinkEntityTypeId = { } + -export type CountdownBlock = Entity; -export type CountdownBlockOutgoingLinkAndTarget = never; -export type CountdownBlockOutgoingLinksByLinkEntityTypeId = {}; /** * The block entity for the “Countdown” block. - * + * * See: https://blockprotocol.org/@hash/blocks/countdown */ export type CountdownBlockProperties = { - "https://blockprotocol.org/@blockprotocol/types/property-type/title/"?: TitlePropertyValue; - "https://blockprotocol.org/@hash/types/property-type/target-date-and-time/"?: TargetDateAndTimePropertyValue; - "https://blockprotocol.org/@hash/types/property-type/countdown-block-should-display-time/"?: CountdownBlockShouldDisplayTimePropertyValue; -}; +"https://blockprotocol.org/@blockprotocol/types/property-type/title/"?: TitlePropertyValue +"https://blockprotocol.org/@hash/types/property-type/target-date-and-time/"?: TargetDateAndTimePropertyValue +"https://blockprotocol.org/@hash/types/property-type/countdown-block-should-display-time/"?: CountdownBlockShouldDisplayTimePropertyValue +} + /** * Whether or not the Countdown block should display granular time-related information, or just date information. - * + * * See: https://blockprotocol.org/@hash/blocks/countdown */ -export type CountdownBlockShouldDisplayTimePropertyValue = BooleanDataType; +export type CountdownBlockShouldDisplayTimePropertyValue = BooleanDataType + + /** * An ISO-8601 formatted date and time that acts as the target for something. - * + * * For example: “2233-03-22T13:30:23Z” */ -export type TargetDateAndTimePropertyValue = TextDataType; +export type TargetDateAndTimePropertyValue = TextDataType + + /** * An ordered sequence of characters */ -export type TextDataType = string; +export type TextDataType = string + /** * The name given to something to identify it, generally associated with objects or inanimate things such as books, websites, songs, etc. */ -export type TitlePropertyValue = TextDataType; +export type TitlePropertyValue = TextDataType + + diff --git a/blocks/divider/src/types/generated/block-entity.ts b/blocks/divider/src/types/generated/block-entity.ts index 44ac21344b1..2dc1df9978e 100644 --- a/blocks/divider/src/types/generated/block-entity.ts +++ b/blocks/divider/src/types/generated/block-entity.ts @@ -2,57 +2,75 @@ * This file was automatically generated – do not edit it. */ -import { Entity } from "@blockprotocol/graph"; +import { Entity } from "@blockprotocol/graph" -export type BlockEntity = DividerBlock; -export type BlockEntityOutgoingLinkAndTarget = - DividerBlockOutgoingLinkAndTarget; + + + +export type BlockEntity = DividerBlock + + + +export type BlockEntityOutgoingLinkAndTarget = DividerBlockOutgoingLinkAndTarget + /** * The text color represented as a CSS-compatible color property expressed as a string. - * + * * This is any ‘legal’ color value in CSS, for example (but not limited to) - * + * * - a hexadecimal string: “#FFFFFF” - * + * * - a named color: “skyblue” - * + * * - an RGB value in functional notation: “rgb(255, 0, 255)” - * + * * - an HSLA value in functional notation: “hsla(120, 100%, 50%)” - * + * * See: https://www.w3schools.com/cssref/css_colors_legal.php */ -export type CSSBackgroundColorPropertyValue = TextDataType; +export type CSSBackgroundColorPropertyValue = TextDataType + + + + +export type DividerBlock = Entity + + +export type DividerBlockOutgoingLinkAndTarget = never + +export type DividerBlockOutgoingLinksByLinkEntityTypeId = { } -export type DividerBlock = Entity; -export type DividerBlockOutgoingLinkAndTarget = never; -export type DividerBlockOutgoingLinksByLinkEntityTypeId = {}; /** * The block entity for the “Divider” block. - * + * * See: https://blockprotocol.org/@hash/blocks/divider */ export type DividerBlockProperties = { - "https://blockprotocol.org/@blockprotocol/types/property-type/height-in-pixels/"?: HeightInPixelsPropertyValue; - "https://blockprotocol.org/@blockprotocol/types/property-type/css-background-color/"?: CSSBackgroundColorPropertyValue; -}; +"https://blockprotocol.org/@blockprotocol/types/property-type/height-in-pixels/"?: HeightInPixelsPropertyValue +"https://blockprotocol.org/@blockprotocol/types/property-type/css-background-color/"?: CSSBackgroundColorPropertyValue +} + /** * The height of a UI element in pixels. */ -export type HeightInPixelsPropertyValue = NumberDataType; +export type HeightInPixelsPropertyValue = NumberDataType + + /** * An arithmetical value (in the Real number system) */ -export type NumberDataType = number; +export type NumberDataType = number + /** * An ordered sequence of characters */ -export type TextDataType = string; +export type TextDataType = string + diff --git a/blocks/heading/src/types/generated/block-entity.ts b/blocks/heading/src/types/generated/block-entity.ts deleted file mode 100644 index 11040c8ea65..00000000000 --- a/blocks/heading/src/types/generated/block-entity.ts +++ /dev/null @@ -1,71 +0,0 @@ -/** - * This file was automatically generated – do not edit it. - */ - -import { Entity } from "@blockprotocol/graph"; - -export type BlockEntity = HeadingBlock; - -export type BlockEntityOutgoingLinkAndTarget = - HeadingBlockOutgoingLinkAndTarget; - -/** - * The text color, represented as a CSS-compatible color property expressed as a string. - * - * This is any ‘legal’ color value in CSS, for example (but not limited to) - * - * - a hexadecimal string: “#FFFFFF” - * - * - a named color: “skyblue” - * - * - an RGB value in functional notation: “rgb(255, 0, 255)” - * - * - an HSLA value in functional notation: “hsla(120, 100%, 50%)” - * - * See: https://www.w3schools.com/cssref/css_colors_legal.php - */ -export type CSSTextColorPropertyValue = TextDataType; - -/** - * The “level” or size of the heading, this can be an integer between 1 to 6 (inclusive). - * - * This corresponds to the equivalent HTML tags (h1, h2, etc.) - */ -export type HTMLHeadingLevelPropertyValue = NumberDataType; - -export type HeadingBlock = Entity; - -export type HeadingBlockOutgoingLinkAndTarget = never; - -export type HeadingBlockOutgoingLinksByLinkEntityTypeId = {}; - -/** - * The block entity for the “Heading” block. - * - * See: https://blockprotocol.org/@hash/blocks/heading - */ -export type HeadingBlockProperties = { - "https://blockprotocol.org/@blockprotocol/types/property-type/html-heading-level/"?: HTMLHeadingLevelPropertyValue; - "https://blockprotocol.org/@blockprotocol/types/property-type/css-text-color/"?: CSSTextColorPropertyValue; - "https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/"?: TextualContentPropertyValue; -}; - -/** - * An arithmetical value (in the Real number system) - */ -export type NumberDataType = number; - -/** - * An opaque, untyped JSON object - */ -export type ObjectDataType = {}; - -/** - * An ordered sequence of characters - */ -export type TextDataType = string; - -/** - * The text material, information, or body, that makes up the content of this thing. - */ -export type TextualContentPropertyValue = TextDataType | ObjectDataType[]; diff --git a/blocks/image/src/types/generated/block-entity.ts b/blocks/image/src/types/generated/block-entity.ts index 1039ac58ee2..308ed2627b1 100644 --- a/blocks/image/src/types/generated/block-entity.ts +++ b/blocks/image/src/types/generated/block-entity.ts @@ -2,205 +2,286 @@ * This file was automatically generated – do not edit it. */ -import { Entity, LinkData } from "@blockprotocol/graph"; +import { Entity, LinkData } from "@blockprotocol/graph" -export type BlockEntity = ImageBlock; -export type BlockEntityOutgoingLinkAndTarget = ImageBlockOutgoingLinkAndTarget; + + + +export type BlockEntity = ImageBlock + + + +export type BlockEntityOutgoingLinkAndTarget = ImageBlockOutgoingLinkAndTarget + /** * A True or False value */ -export type BooleanDataType = boolean; +export type BooleanDataType = boolean + /** * A brief explanation or accompanying message. */ -export type CaptionPropertyValue = TextDataType; +export type CaptionPropertyValue = TextDataType + + /** * A piece of text that tells you about something or someone. This can include explaining what they look like, what its purpose is for, what they’re like, etc. */ -export type DescriptionPropertyValue = TextDataType; +export type DescriptionPropertyValue = TextDataType + + /** * A human-friendly display name for something */ -export type DisplayNamePropertyValue = TextDataType; +export type DisplayNamePropertyValue = TextDataType + + -export type DisplaysMediaFile = Entity & { - linkData: LinkData; -}; -export type DisplaysMediaFileOutgoingLinkAndTarget = never; +export type DisplaysMediaFile = Entity & { linkData: LinkData } -export type DisplaysMediaFileOutgoingLinksByLinkEntityTypeId = {}; + +export type DisplaysMediaFileOutgoingLinkAndTarget = never + +export type DisplaysMediaFileOutgoingLinksByLinkEntityTypeId = { } /** * Displays this media file. */ -export type DisplaysMediaFileProperties = DisplaysMediaFileProperties1 & - DisplaysMediaFileProperties2; -export type DisplaysMediaFileProperties1 = LinkProperties; +export type DisplaysMediaFileProperties = (DisplaysMediaFileProperties1 & DisplaysMediaFileProperties2) +export type DisplaysMediaFileProperties1 = LinkProperties + -export type DisplaysMediaFileProperties2 = {}; +export type DisplaysMediaFileProperties2 = { + +} + + + +export type File = Entity -export type File = Entity; /** * A unique signature derived from a file's contents */ -export type FileHashPropertyValue = TextDataType; +export type FileHashPropertyValue = TextDataType + + /** * The name of a file. */ -export type FileNamePropertyValue = TextDataType; +export type FileNamePropertyValue = TextDataType + + + +export type FileOutgoingLinkAndTarget = never + +export type FileOutgoingLinksByLinkEntityTypeId = { } + + + + + + + + + + + + + + + -export type FileOutgoingLinkAndTarget = never; -export type FileOutgoingLinksByLinkEntityTypeId = {}; /** * A file hosted at a URL */ export type FileProperties = { - "https://blockprotocol.org/@blockprotocol/types/property-type/description/"?: DescriptionPropertyValue; - "https://blockprotocol.org/@blockprotocol/types/property-type/display-name/"?: DisplayNamePropertyValue; - "https://blockprotocol.org/@blockprotocol/types/property-type/file-hash/"?: FileHashPropertyValue; - "https://blockprotocol.org/@blockprotocol/types/property-type/file-name/"?: FileNamePropertyValue; - "https://blockprotocol.org/@blockprotocol/types/property-type/file-size/"?: FileSizePropertyValue; - "https://blockprotocol.org/@blockprotocol/types/property-type/file-url/": FileURLPropertyValue; - "https://blockprotocol.org/@blockprotocol/types/property-type/mime-type/"?: MIMETypePropertyValue; - "https://blockprotocol.org/@blockprotocol/types/property-type/original-file-name/"?: OriginalFileNamePropertyValue; - "https://blockprotocol.org/@blockprotocol/types/property-type/original-source/"?: OriginalSourcePropertyValue; - "https://blockprotocol.org/@blockprotocol/types/property-type/original-url/"?: OriginalURLPropertyValue; - "https://hash.ai/@hash/types/property-type/file-storage-bucket/"?: FileStorageBucketPropertyValue; - "https://hash.ai/@hash/types/property-type/file-storage-endpoint/"?: FileStorageEndpointPropertyValue; - "https://hash.ai/@hash/types/property-type/file-storage-force-path-style/"?: FileStorageForcePathStylePropertyValue; - "https://hash.ai/@hash/types/property-type/file-storage-key/"?: FileStorageKeyPropertyValue; - "https://hash.ai/@hash/types/property-type/file-storage-provider/"?: FileStorageProviderPropertyValue; - "https://hash.ai/@hash/types/property-type/file-storage-region/"?: FileStorageRegionPropertyValue; -}; +"https://blockprotocol.org/@blockprotocol/types/property-type/description/"?: DescriptionPropertyValue +"https://blockprotocol.org/@blockprotocol/types/property-type/display-name/"?: DisplayNamePropertyValue +"https://blockprotocol.org/@blockprotocol/types/property-type/file-hash/"?: FileHashPropertyValue +"https://blockprotocol.org/@blockprotocol/types/property-type/file-name/"?: FileNamePropertyValue +"https://blockprotocol.org/@blockprotocol/types/property-type/file-size/"?: FileSizePropertyValue +"https://blockprotocol.org/@blockprotocol/types/property-type/file-url/": FileURLPropertyValue +"https://blockprotocol.org/@blockprotocol/types/property-type/mime-type/"?: MIMETypePropertyValue +"https://blockprotocol.org/@blockprotocol/types/property-type/original-file-name/"?: OriginalFileNamePropertyValue +"https://blockprotocol.org/@blockprotocol/types/property-type/original-source/"?: OriginalSourcePropertyValue +"https://blockprotocol.org/@blockprotocol/types/property-type/original-url/"?: OriginalURLPropertyValue +"https://hash.ai/@hash/types/property-type/file-storage-bucket/"?: FileStorageBucketPropertyValue +"https://hash.ai/@hash/types/property-type/file-storage-endpoint/"?: FileStorageEndpointPropertyValue +"https://hash.ai/@hash/types/property-type/file-storage-force-path-style/"?: FileStorageForcePathStylePropertyValue +"https://hash.ai/@hash/types/property-type/file-storage-key/"?: FileStorageKeyPropertyValue +"https://hash.ai/@hash/types/property-type/file-storage-provider/"?: FileStorageProviderPropertyValue +"https://hash.ai/@hash/types/property-type/file-storage-region/"?: FileStorageRegionPropertyValue +} + /** * The size of a file */ -export type FileSizePropertyValue = NumberDataType; +export type FileSizePropertyValue = NumberDataType + + /** * The bucket in which a file is stored. */ -export type FileStorageBucketPropertyValue = TextDataType; +export type FileStorageBucketPropertyValue = TextDataType + + /** * The endpoint for making requests to a file storage provider. */ -export type FileStorageEndpointPropertyValue = TextDataType; +export type FileStorageEndpointPropertyValue = TextDataType + + /** * Whether to force path style for requests to a file storage provider (vs virtual host style). */ -export type FileStorageForcePathStylePropertyValue = BooleanDataType; +export type FileStorageForcePathStylePropertyValue = BooleanDataType + + /** * The key identifying a file in storage. */ -export type FileStorageKeyPropertyValue = TextDataType; +export type FileStorageKeyPropertyValue = TextDataType + + /** * The provider of a file storage service. */ -export type FileStorageProviderPropertyValue = TextDataType; +export type FileStorageProviderPropertyValue = TextDataType + + /** * The region in which a file is stored. */ -export type FileStorageRegionPropertyValue = TextDataType; +export type FileStorageRegionPropertyValue = TextDataType + + /** * A URL that serves a file. */ -export type FileURLPropertyValue = TextDataType; +export type FileURLPropertyValue = TextDataType + + + + +export type Image = Entity + + + +export type ImageBlock = Entity + -export type Image = Entity; +export type ImageBlockDisplaysMediaFileLink = { linkEntity: DisplaysMediaFile; rightEntity: Image } -export type ImageBlock = Entity; +export type ImageBlockOutgoingLinkAndTarget = ImageBlockDisplaysMediaFileLink + +export type ImageBlockOutgoingLinksByLinkEntityTypeId = { "https://blockprotocol.org/@hash/types/entity-type/displays-media-file/v/1": ImageBlockDisplaysMediaFileLink } -export type ImageBlockDisplaysMediaFileLink = { - linkEntity: DisplaysMediaFile; - rightEntity: Image; -}; -export type ImageBlockOutgoingLinkAndTarget = ImageBlockDisplaysMediaFileLink; -export type ImageBlockOutgoingLinksByLinkEntityTypeId = { - "https://blockprotocol.org/@hash/types/entity-type/displays-media-file/v/1": ImageBlockDisplaysMediaFileLink; -}; /** * The block entity for the “Image” block. - * + * * See: https://blockprotocol.org/@hash/blocks/image */ export type ImageBlockProperties = { - "https://blockprotocol.org/@blockprotocol/types/property-type/caption/"?: CaptionPropertyValue; - "https://blockprotocol.org/@blockprotocol/types/property-type/width-in-pixels/"?: WidthInPixelsPropertyValue; -}; +"https://blockprotocol.org/@blockprotocol/types/property-type/caption/"?: CaptionPropertyValue +"https://blockprotocol.org/@blockprotocol/types/property-type/width-in-pixels/"?: WidthInPixelsPropertyValue +} + -export type ImageOutgoingLinkAndTarget = never; +export type ImageOutgoingLinkAndTarget = never -export type ImageOutgoingLinksByLinkEntityTypeId = {}; +export type ImageOutgoingLinksByLinkEntityTypeId = { } /** * An image file hosted at a URL */ -export type ImageProperties = ImageProperties1 & ImageProperties2; -export type ImageProperties1 = FileProperties; +export type ImageProperties = (ImageProperties1 & ImageProperties2) +export type ImageProperties1 = FileProperties + + +export type ImageProperties2 = { + +} + -export type ImageProperties2 = {}; -export type Link = Entity; +export type Link = Entity -export type LinkOutgoingLinkAndTarget = never; -export type LinkOutgoingLinksByLinkEntityTypeId = {}; +export type LinkOutgoingLinkAndTarget = never + +export type LinkOutgoingLinksByLinkEntityTypeId = { } + +export type LinkProperties = { + +} -export type LinkProperties = {}; /** * A MIME (Multipurpose Internet Mail Extensions) type. - * + * * See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types */ -export type MIMETypePropertyValue = TextDataType; +export type MIMETypePropertyValue = TextDataType + + /** * An arithmetical value (in the Real number system) */ -export type NumberDataType = number; +export type NumberDataType = number + /** * The original name of a file */ -export type OriginalFileNamePropertyValue = TextDataType; +export type OriginalFileNamePropertyValue = TextDataType + + /** * The original source of something */ -export type OriginalSourcePropertyValue = TextDataType; +export type OriginalSourcePropertyValue = TextDataType + + /** * The original URL something was hosted at */ -export type OriginalURLPropertyValue = TextDataType; +export type OriginalURLPropertyValue = TextDataType + + /** * An ordered sequence of characters */ -export type TextDataType = string; +export type TextDataType = string + /** * The width of a UI element in pixels. */ -export type WidthInPixelsPropertyValue = NumberDataType; +export type WidthInPixelsPropertyValue = NumberDataType + + diff --git a/blocks/minesweeper/src/types/generated/block-entity.ts b/blocks/minesweeper/src/types/generated/block-entity.ts index 6f9593fed46..e6054105597 100644 --- a/blocks/minesweeper/src/types/generated/block-entity.ts +++ b/blocks/minesweeper/src/types/generated/block-entity.ts @@ -2,40 +2,57 @@ * This file was automatically generated – do not edit it. */ -import { Entity } from "@blockprotocol/graph"; +import { Entity } from "@blockprotocol/graph" -export type BlockEntity = MinesweeperBlock; -export type BlockEntityOutgoingLinkAndTarget = - MinesweeperBlockOutgoingLinkAndTarget; -export type MinesweeperBlock = Entity; -export type MinesweeperBlockOutgoingLinkAndTarget = never; -export type MinesweeperBlockOutgoingLinksByLinkEntityTypeId = {}; +export type BlockEntity = MinesweeperBlock + + + +export type BlockEntityOutgoingLinkAndTarget = MinesweeperBlockOutgoingLinkAndTarget + + + +export type MinesweeperBlock = Entity + + +export type MinesweeperBlockOutgoingLinkAndTarget = never + +export type MinesweeperBlockOutgoingLinksByLinkEntityTypeId = { } + + + /** * The block entity of the "Minesweeper" block. - * + * * See: https://blockprotocol.org/@hash/blocks/minesweeper */ export type MinesweeperBlockProperties = { - "https://blockprotocol.org/@hash/types/property-type/number-of-mines/"?: NumberOfMinesPropertyValue; - "https://blockprotocol.org/@hash/types/property-type/number-of-columns/"?: NumberOfColumnsPropertyValue; -}; +"https://blockprotocol.org/@hash/types/property-type/number-of-mines/"?: NumberOfMinesPropertyValue +"https://blockprotocol.org/@hash/types/property-type/number-of-columns/"?: NumberOfColumnsPropertyValue +} + /** * An arithmetical value (in the Real number system) */ -export type NumberDataType = number; +export type NumberDataType = number + /** * How many columns there are or should be */ -export type NumberOfColumnsPropertyValue = NumberDataType; +export type NumberOfColumnsPropertyValue = NumberDataType + + /** * How many mines there are or should be */ -export type NumberOfMinesPropertyValue = NumberDataType; +export type NumberOfMinesPropertyValue = NumberDataType + + diff --git a/blocks/paragraph/src/types/generated/block-entity.ts b/blocks/paragraph/src/types/generated/block-entity.ts index 690a9cb134c..e6fbb6f0788 100644 --- a/blocks/paragraph/src/types/generated/block-entity.ts +++ b/blocks/paragraph/src/types/generated/block-entity.ts @@ -2,39 +2,57 @@ * This file was automatically generated – do not edit it. */ -import { Entity } from "@blockprotocol/graph"; +import { Entity } from "@blockprotocol/graph" -export type BlockEntity = ParagraphBlock; -export type BlockEntityOutgoingLinkAndTarget = - ParagraphBlockOutgoingLinkAndTarget; + + + +export type BlockEntity = ParagraphBlock + + + +export type BlockEntityOutgoingLinkAndTarget = ParagraphBlockOutgoingLinkAndTarget + /** * An opaque, untyped JSON object */ -export type ObjectDataType = {}; +export type ObjectDataType = { + +} + -export type ParagraphBlock = Entity; -export type ParagraphBlockOutgoingLinkAndTarget = never; +export type ParagraphBlock = Entity + + +export type ParagraphBlockOutgoingLinkAndTarget = never + +export type ParagraphBlockOutgoingLinksByLinkEntityTypeId = { } + -export type ParagraphBlockOutgoingLinksByLinkEntityTypeId = {}; /** * The block entity for the “Paragraph” block. - * + * * See: https://blockprotocol.org/@hash/blocks/paragraph */ export type ParagraphBlockProperties = { - "https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/"?: TextualContentPropertyValue; -}; +"https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/"?: TextualContentPropertyValue +} + /** * An ordered sequence of characters */ -export type TextDataType = string; +export type TextDataType = string + /** * The text material, information, or body, that makes up the content of this thing. */ -export type TextualContentPropertyValue = TextDataType | ObjectDataType[]; +export type TextualContentPropertyValue = (TextDataType | ObjectDataType[]) + + + diff --git a/blocks/timer/src/types/generated/block-entity.ts b/blocks/timer/src/types/generated/block-entity.ts index fc9ed7692db..aa9e15aef60 100644 --- a/blocks/timer/src/types/generated/block-entity.ts +++ b/blocks/timer/src/types/generated/block-entity.ts @@ -2,69 +2,90 @@ * This file was automatically generated – do not edit it. */ -import { Entity } from "@blockprotocol/graph"; +import { Entity } from "@blockprotocol/graph" -export type BlockEntity = TimerBlock; -export type BlockEntityOutgoingLinkAndTarget = TimerBlockOutgoingLinkAndTarget; + + + +export type BlockEntity = TimerBlock + + + +export type BlockEntityOutgoingLinkAndTarget = TimerBlockOutgoingLinkAndTarget + /** * An ISO-8601 formatted date and time that acts as the target for something. - * + * * For example: “2233-03-22T13:30:23Z” */ -export type TargetDateAndTimePropertyValue = TextDataType; +export type TargetDateAndTimePropertyValue = TextDataType + + /** * An ordered sequence of characters */ -export type TextDataType = string; +export type TextDataType = string + + + +export type TimerBlock = Entity -export type TimerBlock = Entity; -export type TimerBlockOutgoingLinkAndTarget = never; +export type TimerBlockOutgoingLinkAndTarget = never -export type TimerBlockOutgoingLinksByLinkEntityTypeId = {}; +export type TimerBlockOutgoingLinksByLinkEntityTypeId = { } /** * An ISO-8601 formatted duration, which remaining duration on the timer block when it has been paused. The elapsed time can be calculated by subtracting this value from the total duration. - * + * * For example: `PT42M24S` corresponds to 42 minutes and 24 seconds. - * + * * See: https://blockprotocol.org/@hash/blocks/timer */ -export type TimerBlockPauseDurationPropertyValue = TextDataType; +export type TimerBlockPauseDurationPropertyValue = TextDataType + + /** * Defines the relative offsets of the timer block when in a paused or unpaused state, respective to the total duration. - * - * See: + * + * See: * - https://blockprotocol.org/@hash/types/property-type/timer-block-total-duration * - https://blockprotocol.org/@hash/blocks/timer */ -export type TimerBlockProgressPropertyValue = - | { - "https://blockprotocol.org/@hash/types/property-type/target-date-and-time/": TargetDateAndTimePropertyValue; - } - | { - "https://blockprotocol.org/@hash/types/property-type/timer-block-pause-duration/": TimerBlockPauseDurationPropertyValue; - }; +export type TimerBlockProgressPropertyValue = ({ +"https://blockprotocol.org/@hash/types/property-type/target-date-and-time/": TargetDateAndTimePropertyValue +} | { +"https://blockprotocol.org/@hash/types/property-type/timer-block-pause-duration/": TimerBlockPauseDurationPropertyValue +}) + + + + + + /** * The block entity for the “Timer” block. - * + * * See: https://blockprotocol.org/@hash/blocks/timer */ export type TimerBlockProperties = { - "https://blockprotocol.org/@hash/types/property-type/timer-block-progress/"?: TimerBlockProgressPropertyValue; - "https://blockprotocol.org/@hash/types/property-type/timer-block-total-duration/"?: TimerBlockTotalDurationPropertyValue; -}; +"https://blockprotocol.org/@hash/types/property-type/timer-block-progress/"?: TimerBlockProgressPropertyValue +"https://blockprotocol.org/@hash/types/property-type/timer-block-total-duration/"?: TimerBlockTotalDurationPropertyValue +} + /** * An ISO-8601 formatted duration, which is the total duration the timer will countdown for once the play button is clicked. - * + * * For example: `PT42M24S` corresponds to 42 minutes and 24 seconds. - * + * * See: https://blockprotocol.org/@hash/blocks/timer */ -export type TimerBlockTotalDurationPropertyValue = TextDataType; +export type TimerBlockTotalDurationPropertyValue = TextDataType + + diff --git a/blocks/video/src/types/generated/block-entity.ts b/blocks/video/src/types/generated/block-entity.ts deleted file mode 100644 index 83aab43af6f..00000000000 --- a/blocks/video/src/types/generated/block-entity.ts +++ /dev/null @@ -1,200 +0,0 @@ -/** - * This file was automatically generated – do not edit it. - */ - -import { Entity, LinkData } from "@blockprotocol/graph"; - -export type BlockEntity = VideoBlock; - -export type BlockEntityOutgoingLinkAndTarget = VideoBlockOutgoingLinkAndTarget; - -/** - * A True or False value - */ -export type BooleanDataType = boolean; - -/** - * A brief explanation or accompanying message. - */ -export type CaptionPropertyValue = TextDataType; - -/** - * A piece of text that tells you about something or someone. This can include explaining what they look like, what its purpose is for, what they’re like, etc. - */ -export type DescriptionPropertyValue = TextDataType; - -/** - * A human-friendly display name for something - */ -export type DisplayNamePropertyValue = TextDataType; - -export type DisplaysMediaFile = Entity & { - linkData: LinkData; -}; - -export type DisplaysMediaFileOutgoingLinkAndTarget = never; - -export type DisplaysMediaFileOutgoingLinksByLinkEntityTypeId = {}; - -/** - * Displays this media file. - */ -export type DisplaysMediaFileProperties = DisplaysMediaFileProperties1 & - DisplaysMediaFileProperties2; -export type DisplaysMediaFileProperties1 = LinkProperties; - -export type DisplaysMediaFileProperties2 = {}; - -export type File = Entity; - -/** - * A unique signature derived from a file's contents - */ -export type FileHashPropertyValue = TextDataType; - -/** - * The name of a file. - */ -export type FileNamePropertyValue = TextDataType; - -export type FileOutgoingLinkAndTarget = never; - -export type FileOutgoingLinksByLinkEntityTypeId = {}; - -/** - * A file hosted at a URL - */ -export type FileProperties = { - "https://blockprotocol.org/@blockprotocol/types/property-type/description/"?: DescriptionPropertyValue; - "https://blockprotocol.org/@blockprotocol/types/property-type/display-name/"?: DisplayNamePropertyValue; - "https://blockprotocol.org/@blockprotocol/types/property-type/file-hash/"?: FileHashPropertyValue; - "https://blockprotocol.org/@blockprotocol/types/property-type/file-name/"?: FileNamePropertyValue; - "https://blockprotocol.org/@blockprotocol/types/property-type/file-size/"?: FileSizePropertyValue; - "https://blockprotocol.org/@blockprotocol/types/property-type/file-url/": FileURLPropertyValue; - "https://blockprotocol.org/@blockprotocol/types/property-type/mime-type/"?: MIMETypePropertyValue; - "https://blockprotocol.org/@blockprotocol/types/property-type/original-file-name/"?: OriginalFileNamePropertyValue; - "https://blockprotocol.org/@blockprotocol/types/property-type/original-source/"?: OriginalSourcePropertyValue; - "https://blockprotocol.org/@blockprotocol/types/property-type/original-url/"?: OriginalURLPropertyValue; - "https://hash.ai/@hash/types/property-type/file-storage-bucket/"?: FileStorageBucketPropertyValue; - "https://hash.ai/@hash/types/property-type/file-storage-endpoint/"?: FileStorageEndpointPropertyValue; - "https://hash.ai/@hash/types/property-type/file-storage-force-path-style/"?: FileStorageForcePathStylePropertyValue; - "https://hash.ai/@hash/types/property-type/file-storage-key/"?: FileStorageKeyPropertyValue; - "https://hash.ai/@hash/types/property-type/file-storage-provider/"?: FileStorageProviderPropertyValue; - "https://hash.ai/@hash/types/property-type/file-storage-region/"?: FileStorageRegionPropertyValue; -}; - -/** - * The size of a file - */ -export type FileSizePropertyValue = NumberDataType; - -/** - * The bucket in which a file is stored. - */ -export type FileStorageBucketPropertyValue = TextDataType; - -/** - * The endpoint for making requests to a file storage provider. - */ -export type FileStorageEndpointPropertyValue = TextDataType; - -/** - * Whether to force path style for requests to a file storage provider (vs virtual host style). - */ -export type FileStorageForcePathStylePropertyValue = BooleanDataType; - -/** - * The key identifying a file in storage. - */ -export type FileStorageKeyPropertyValue = TextDataType; - -/** - * The provider of a file storage service. - */ -export type FileStorageProviderPropertyValue = TextDataType; - -/** - * The region in which a file is stored. - */ -export type FileStorageRegionPropertyValue = TextDataType; - -/** - * A URL that serves a file. - */ -export type FileURLPropertyValue = TextDataType; - -export type Image = Entity; - -export type ImageOutgoingLinkAndTarget = never; - -export type ImageOutgoingLinksByLinkEntityTypeId = {}; - -/** - * An image file hosted at a URL - */ -export type ImageProperties = ImageProperties1 & ImageProperties2; -export type ImageProperties1 = FileProperties; - -export type ImageProperties2 = {}; - -export type Link = Entity; - -export type LinkOutgoingLinkAndTarget = never; - -export type LinkOutgoingLinksByLinkEntityTypeId = {}; - -export type LinkProperties = {}; - -/** - * A MIME (Multipurpose Internet Mail Extensions) type. - * - * See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types - */ -export type MIMETypePropertyValue = TextDataType; - -/** - * An arithmetical value (in the Real number system) - */ -export type NumberDataType = number; - -/** - * The original name of a file - */ -export type OriginalFileNamePropertyValue = TextDataType; - -/** - * The original source of something - */ -export type OriginalSourcePropertyValue = TextDataType; - -/** - * The original URL something was hosted at - */ -export type OriginalURLPropertyValue = TextDataType; - -/** - * An ordered sequence of characters - */ -export type TextDataType = string; - -export type VideoBlock = Entity; - -export type VideoBlockDisplaysMediaFileLink = { - linkEntity: DisplaysMediaFile; - rightEntity: Image; -}; - -export type VideoBlockOutgoingLinkAndTarget = VideoBlockDisplaysMediaFileLink; - -export type VideoBlockOutgoingLinksByLinkEntityTypeId = { - "https://blockprotocol.org/@hash/types/entity-type/displays-media-file/v/1": VideoBlockDisplaysMediaFileLink; -}; - -/** - * The block entity for the “Video” block. - * - * See: https://blockprotocol.org/@hash/blocks/video - */ -export type VideoBlockProperties = { - "https://blockprotocol.org/@blockprotocol/types/property-type/caption/"?: CaptionPropertyValue; -}; diff --git a/libs/@local/hash-isomorphic-utils/src/graphql/type-defs/knowledge/entity.typedef.ts b/libs/@local/hash-isomorphic-utils/src/graphql/type-defs/knowledge/entity.typedef.ts index d4fdf24323a..fc82d113c92 100644 --- a/libs/@local/hash-isomorphic-utils/src/graphql/type-defs/knowledge/entity.typedef.ts +++ b/libs/@local/hash-isomorphic-utils/src/graphql/type-defs/knowledge/entity.typedef.ts @@ -24,6 +24,7 @@ export const entityTypedef = gql` } type GetEntitySubgraphResponse { + count?: Int; closedMultiEntityTypes: ClosedMultiEntityTypesRootMap definitions: ClosedMultiEntityTypesDefinitions userPermissionsOnEntities: UserPermissionsOnEntities! From ac6dd62466e217dc8628ed6c2e766f04121f1159 Mon Sep 17 00:00:00 2001 From: Ciaran Morinan Date: Mon, 9 Dec 2024 14:26:35 +0000 Subject: [PATCH 2/5] wip --- .../entity-page-header.tsx | 25 +- apps/hash-frontend/src/pages/_app.page.tsx | 2 +- .../draft-entities-bulk-actions-dropdown.tsx | 2 +- .../src/pages/notifications.page.tsx | 366 +---------------- .../notifications-table.tsx | 372 ++++++++++++++++++ .../shared/accept-draft-entity-button.tsx | 2 +- .../shared/discard-draft-entity-button.tsx | 2 +- .../notifications-dropdown.tsx | 2 +- .../layout/layout-with-sidebar/sidebar.tsx | 2 +- ...ext.tsx => notification-count-context.tsx} | 11 +- .../src/types/generated/block-entity.ts | 53 +-- .../code/src/types/generated/block-entity.ts | 61 +-- .../src/types/generated/block-entity.ts | 59 +-- .../src/types/generated/block-entity.ts | 60 +-- .../src/types/generated/block-entity.ts | 71 ++++ .../image/src/types/generated/block-entity.ts | 235 ++++------- .../src/types/generated/block-entity.ts | 45 +-- .../src/types/generated/block-entity.ts | 44 +-- .../timer/src/types/generated/block-entity.ts | 77 ++-- .../video/src/types/generated/block-entity.ts | 200 ++++++++++ .../harpc/client/typescript/tsconfig.json | 2 +- .../graphql/type-defs/generation.typedef.ts | 2 - .../type-defs/knowledge/entity.typedef.ts | 2 +- 23 files changed, 875 insertions(+), 822 deletions(-) create mode 100644 apps/hash-frontend/src/pages/notifications.page/notifications-table.tsx rename apps/hash-frontend/src/shared/{notification-entities-context.tsx => notification-count-context.tsx} (93%) create mode 100644 blocks/heading/src/types/generated/block-entity.ts create mode 100644 blocks/video/src/types/generated/block-entity.ts diff --git a/apps/hash-frontend/src/pages/[shortname]/entities/[entity-uuid].page/entity-page-wrapper/entity-page-header.tsx b/apps/hash-frontend/src/pages/[shortname]/entities/[entity-uuid].page/entity-page-wrapper/entity-page-header.tsx index 182a3076b7c..db189df4fa1 100644 --- a/apps/hash-frontend/src/pages/[shortname]/entities/[entity-uuid].page/entity-page-wrapper/entity-page-header.tsx +++ b/apps/hash-frontend/src/pages/[shortname]/entities/[entity-uuid].page/entity-page-wrapper/entity-page-header.tsx @@ -10,7 +10,6 @@ import { useRouter } from "next/router"; import type { ReactNode } from "react"; import { useContext } from "react"; -import { NotificationsWithLinksContextProvider } from "../../../../shared/notifications-with-links-context"; import { TopContextBar } from "../../../../shared/top-context-bar"; import { WorkspaceContext } from "../../../../shared/workspace-context"; import { EntityEditorTabs } from "../shared/entity-editor-tabs"; @@ -84,19 +83,17 @@ export const EntityPageHeader = ({ /> {entity && entitySubgraph ? ( - - - - - + + + ) : null} {editBar} diff --git a/apps/hash-frontend/src/pages/_app.page.tsx b/apps/hash-frontend/src/pages/_app.page.tsx index bc0b0932a0e..50cc5b7ee0c 100644 --- a/apps/hash-frontend/src/pages/_app.page.tsx +++ b/apps/hash-frontend/src/pages/_app.page.tsx @@ -42,7 +42,7 @@ import { KeyboardShortcutsContextProvider } from "../shared/keyboard-shortcuts-c import type { NextPageWithLayout } from "../shared/layout"; import { getLayoutWithSidebar, getPlainLayout } from "../shared/layout"; import { SidebarContextProvider } from "../shared/layout/layout-with-sidebar/sidebar-context"; -import { NotificationCountContextProvider } from "../shared/notification-entities-context"; +import { NotificationCountContextProvider } from "../shared/notification-count-context"; import { PropertyTypesContextProvider } from "../shared/property-types-context"; import { RoutePageInfoProvider } from "../shared/routing"; import { ErrorFallback } from "./_app.page/error-fallback"; diff --git a/apps/hash-frontend/src/pages/actions.page/draft-entities-bulk-actions-dropdown.tsx b/apps/hash-frontend/src/pages/actions.page/draft-entities-bulk-actions-dropdown.tsx index ab423dc850b..1d783fed5bb 100644 --- a/apps/hash-frontend/src/pages/actions.page/draft-entities-bulk-actions-dropdown.tsx +++ b/apps/hash-frontend/src/pages/actions.page/draft-entities-bulk-actions-dropdown.tsx @@ -30,7 +30,7 @@ import { } from "../../graphql/queries/knowledge/entity.queries"; import { useDraftEntities } from "../../shared/draft-entities-context"; import { LayerGroupLightIcon } from "../../shared/icons/layer-group-light-icon"; -import { useNotificationCount } from "../../shared/notification-entities-context"; +import { useNotificationCount } from "../../shared/notification-count-context"; import { Button, MenuItem } from "../../shared/ui"; import { useNotificationsWithLinks } from "../shared/notifications-with-links-context"; diff --git a/apps/hash-frontend/src/pages/notifications.page.tsx b/apps/hash-frontend/src/pages/notifications.page.tsx index 8e016edf544..dc4fcbdbae5 100644 --- a/apps/hash-frontend/src/pages/notifications.page.tsx +++ b/apps/hash-frontend/src/pages/notifications.page.tsx @@ -1,332 +1,19 @@ import { BellLightIcon } from "@hashintel/design-system"; -import { generateEntityPath } from "@local/hash-isomorphic-utils/frontend-paths"; -import { simplifyProperties } from "@local/hash-isomorphic-utils/simplify-properties"; -import { - extractDraftIdFromEntityId, - extractEntityUuidFromEntityId, - extractOwnedByIdFromEntityId, -} from "@local/hash-subgraph"; import { breadcrumbsClasses, buttonClasses, Container, - Skeleton, - styled, - Table as MuiTable, - TableBody, - TableCell as MuiTableCell, - tableCellClasses, - TableHead, - TableRow as MuiTableRow, - tableRowClasses, Typography, } from "@mui/material"; -import { - differenceInDays, - differenceInMinutes, - format, - isThisYear, - isToday, -} from "date-fns"; import { NextSeo } from "next-seo"; -import type { FunctionComponent } from "react"; -import { useCallback, useMemo } from "react"; -import { useUserOrOrgShortnameByOwnedById } from "../components/hooks/use-user-or-org-shortname-by-owned-by-id"; -import { constructPageRelativeUrl } from "../lib/routes"; import type { NextPageWithLayout } from "../shared/layout"; import { getLayoutWithSidebar } from "../shared/layout"; -import { useNotificationCount } from "../shared/notification-entities-context"; -import { Button, Link } from "../shared/ui"; -import type { - GraphChangeNotification, - Notification, - PageRelatedNotification, -} from "./shared/notifications-with-links-context"; -import { useNotificationsWithLinksContextValue } from "./shared/notifications-with-links-context"; +import { NotificationsTable } from "./notifications.page/notifications-table"; +import { NotificationsWithLinksContextProvider } from "./shared/notifications-with-links-context"; import { TopContextBar } from "./shared/top-context-bar"; -const Table = styled(MuiTable)(({ theme }) => ({ - borderCollapse: "separate", - borderSpacing: 0, - background: theme.palette.common.white, - borderRadius: "8px", - borderColor: theme.palette.gray[30], - borderStyle: "solid", - borderWidth: 1, - overflow: "hidden", -})); - -const TableRow = styled(MuiTableRow)(() => ({ - [`&:last-of-type .${tableCellClasses.body}`]: { - borderBottom: "none", - }, - [`&:first-of-type .${tableCellClasses.head}`]: { - "&:first-of-type": { - borderTopLeftRadius: "8px", - }, - "&:last-of-type": { - borderTopRightRadius: "8px", - }, - }, - [`&:last-of-type .${tableCellClasses.body}`]: { - "&:first-of-type": { - borderBottomLeftRadius: "8px", - }, - "&:last-of-type": { - borderBottomRightRadius: "8px", - }, - }, -})); - -const TableCell = styled(MuiTableCell)(({ theme }) => ({ - whiteSpace: "nowrap", - border: 0, - borderStyle: "solid", - borderColor: theme.palette.gray[20], - borderBottomWidth: 1, - borderRightWidth: 1, - padding: theme.spacing(0.5, 1.5), - [`&.${tableCellClasses.head}`]: { - fontSize: 13, - fontWeight: 600, - color: theme.palette.common.black, - }, - [`&.${tableCellClasses.body}`]: { - fontSize: 14, - fontWeight: 500, - color: theme.palette.gray[90], - }, - "&:last-of-type": { - borderRightWidth: 0, - }, -})); - -const GraphChangeNotificationContent = ({ - notification, - handleNotificationClick, - targetHref, -}: { - notification: GraphChangeNotification; - handleNotificationClick: () => void; - targetHref?: string; -}) => { - const { occurredInEntityLabel, occurredInEntity, operation } = notification; - - return ( - - HASH AI {operation}d{" "} - - {occurredInEntityLabel} - {" "} - {extractDraftIdFromEntityId(occurredInEntity.metadata.recordId.entityId) - ? "as draft" - : ""} - - ); -}; - -const PageRelatedNotificationContent = ({ - notification, - handleNotificationClick, - targetHref, -}: { - notification: PageRelatedNotification; - handleNotificationClick: () => void; - targetHref?: string; -}) => { - const { kind, triggeredByUser, occurredInEntity } = notification; - - const pageTitle = useMemo(() => { - const { title } = simplifyProperties(occurredInEntity.properties); - - return title; - }, [occurredInEntity]); - - return ( - <> - - {triggeredByUser.displayName} - {" "} - {kind === "new-comment" - ? "commented on " - : kind === "comment-reply" - ? "replied to your comment on " - : kind === "page-mention" - ? "mentioned you in " - : "mentioned you in a comment on "} - - {pageTitle} - - - ); -}; - -const NotificationRow: FunctionComponent<{ notification: Notification }> = ({ - notification, -}) => { - const { markNotificationAsRead } = useNotificationCount(); - - const handleNotificationClick = useCallback(async () => { - await markNotificationAsRead({ notificationEntity: notification.entity }); - }, [markNotificationAsRead, notification]); - - const ownedById = useMemo( - () => - extractOwnedByIdFromEntityId( - notification.occurredInEntity.metadata.recordId.entityId, - ), - [notification], - ); - - const { shortname: entityOwningShortname } = useUserOrOrgShortnameByOwnedById( - { ownedById }, - ); - - const targetHref = useMemo(() => { - if (!entityOwningShortname) { - return undefined; - } - - if (notification.kind === "graph-change") { - return generateEntityPath({ - entityId: notification.occurredInEntity.metadata.recordId.entityId, - includeDraftId: true, - shortname: entityOwningShortname, - }); - } - - const { occurredInBlock } = notification; - - /** @todo: append query param if the mention was in a comment */ - return constructPageRelativeUrl({ - workspaceShortname: entityOwningShortname, - pageEntityUuid: extractEntityUuidFromEntityId( - notification.occurredInEntity.metadata.recordId.entityId, - ), - highlightedBlockEntityId: occurredInBlock.metadata.recordId.entityId, - }); - }, [entityOwningShortname, notification]); - - const humanReadableCreatedAt = useMemo(() => { - const now = new Date(); - - const createdAtTimestamp = - notification.kind === "graph-change" - ? (notification.occurredInEntityEditionTimestamp ?? - notification.entity.metadata.provenance.createdAtDecisionTime) - : notification.entity.metadata.provenance.createdAtDecisionTime; - - const createdAt = new Date(createdAtTimestamp); - - const numberOfMinutesAgo = differenceInMinutes(now, createdAt); - - if (numberOfMinutesAgo < 1) { - return "Just now"; - } - - if (isToday(createdAt)) { - if (numberOfMinutesAgo < 60) { - return `${numberOfMinutesAgo} minute${ - numberOfMinutesAgo > 1 ? "s" : "" - } ago`; - } - const numberOfHoursAgo = Math.floor(numberOfMinutesAgo / 60); - return `${numberOfHoursAgo} hour${numberOfHoursAgo > 1 ? "s" : ""} ago`; - } - const numberOfDaysAgo = differenceInDays(now, createdAt); - - if (numberOfDaysAgo < 7) { - return format(createdAt, "h:mma iiii"); // "12:00AM Monday" - } - - if (isThisYear(createdAt)) { - return format(createdAt, "h:mma MMMM do"); // "12:00AM October 27th" - } - - return format(createdAt, "h:mma MMMM do, yyyy"); // "12:00AM December 24th, 2022" - }, [notification]); - - return ( - palette.gray[20] - : undefined, - opacity: notification.readAt ? 0.6 : 1, - }} - > - palette.gray[70], - }, - }} - > - {humanReadableCreatedAt} - - palette.blue[70], - "&:hover": { color: ({ palette }) => palette.blue[90] }, - }, - }} - > - {notification.kind === "graph-change" ? ( - - ) : ( - - )} - - - - {notification.readAt ? null : ( - - )} - - - ); -}; - const NotificationsPage: NextPageWithLayout = () => { - const { notifications } = useNotificationsWithLinksContextValue(); - return ( <> @@ -351,52 +38,9 @@ const NotificationsPage: NextPageWithLayout = () => { Notifications - {notifications && notifications.length === 0 ? ( - You don't have any notifications. - ) : ( - - - - - When - - - Title - - - Actions - - - - .${tableRowClasses.root}:last-of-type > .${tableCellClasses.root}`]: - { - borderBottomWidth: 0, - }, - }} - > - {notifications ? ( - notifications.map((notification) => ( - - )) - ) : ( - - - - - - - - - - )} - -
- )} + + + ); diff --git a/apps/hash-frontend/src/pages/notifications.page/notifications-table.tsx b/apps/hash-frontend/src/pages/notifications.page/notifications-table.tsx new file mode 100644 index 00000000000..0341c54f8d9 --- /dev/null +++ b/apps/hash-frontend/src/pages/notifications.page/notifications-table.tsx @@ -0,0 +1,372 @@ +import { generateEntityPath } from "@local/hash-isomorphic-utils/frontend-paths"; +import { simplifyProperties } from "@local/hash-isomorphic-utils/simplify-properties"; +import { + extractDraftIdFromEntityId, + extractEntityUuidFromEntityId, + extractOwnedByIdFromEntityId, +} from "@local/hash-subgraph"; +import { + Skeleton, + styled, + Table as MuiTable, + TableBody, + TableCell as MuiTableCell, + tableCellClasses, + TableHead, + TableRow as MuiTableRow, + tableRowClasses, + Typography, +} from "@mui/material"; +import { + differenceInDays, + differenceInMinutes, + format, + isThisYear, + isToday, +} from "date-fns"; +import type { FunctionComponent } from "react"; +import { useCallback, useMemo } from "react"; + +import { useUserOrOrgShortnameByOwnedById } from "../../components/hooks/use-user-or-org-shortname-by-owned-by-id"; +import { constructPageRelativeUrl } from "../../lib/routes"; +import { useNotificationCount } from "../../shared/notification-count-context"; +import { Button, Link } from "../../shared/ui"; +import type { + GraphChangeNotification, + Notification, + PageRelatedNotification, +} from "../shared/notifications-with-links-context"; +import { useNotificationsWithLinks } from "../shared/notifications-with-links-context"; + +const Table = styled(MuiTable)(({ theme }) => ({ + borderCollapse: "separate", + borderSpacing: 0, + background: theme.palette.common.white, + borderRadius: "8px", + borderColor: theme.palette.gray[30], + borderStyle: "solid", + borderWidth: 1, + overflow: "hidden", +})); + +const TableRow = styled(MuiTableRow)(() => ({ + [`&:last-of-type .${tableCellClasses.body}`]: { + borderBottom: "none", + }, + [`&:first-of-type .${tableCellClasses.head}`]: { + "&:first-of-type": { + borderTopLeftRadius: "8px", + }, + "&:last-of-type": { + borderTopRightRadius: "8px", + }, + }, + [`&:last-of-type .${tableCellClasses.body}`]: { + "&:first-of-type": { + borderBottomLeftRadius: "8px", + }, + "&:last-of-type": { + borderBottomRightRadius: "8px", + }, + }, +})); + +const TableCell = styled(MuiTableCell)(({ theme }) => ({ + whiteSpace: "nowrap", + border: 0, + borderStyle: "solid", + borderColor: theme.palette.gray[20], + borderBottomWidth: 1, + borderRightWidth: 1, + padding: theme.spacing(0.5, 1.5), + [`&.${tableCellClasses.head}`]: { + fontSize: 13, + fontWeight: 600, + color: theme.palette.common.black, + }, + [`&.${tableCellClasses.body}`]: { + fontSize: 14, + fontWeight: 500, + color: theme.palette.gray[90], + }, + "&:last-of-type": { + borderRightWidth: 0, + }, +})); + +const GraphChangeNotificationContent = ({ + notification, + handleNotificationClick, + targetHref, +}: { + notification: GraphChangeNotification; + handleNotificationClick: () => void; + targetHref?: string; +}) => { + const { occurredInEntityLabel, occurredInEntity, operation } = notification; + + return ( + + HASH AI {operation}d{" "} + + {occurredInEntityLabel} + {" "} + {extractDraftIdFromEntityId(occurredInEntity.metadata.recordId.entityId) + ? "as draft" + : ""} + + ); +}; + +const PageRelatedNotificationContent = ({ + notification, + handleNotificationClick, + targetHref, +}: { + notification: PageRelatedNotification; + handleNotificationClick: () => void; + targetHref?: string; +}) => { + const { kind, triggeredByUser, occurredInEntity } = notification; + + const pageTitle = useMemo(() => { + const { title } = simplifyProperties(occurredInEntity.properties); + + return title; + }, [occurredInEntity]); + + return ( + <> + + {triggeredByUser.displayName} + {" "} + {kind === "new-comment" + ? "commented on " + : kind === "comment-reply" + ? "replied to your comment on " + : kind === "page-mention" + ? "mentioned you in " + : "mentioned you in a comment on "} + + {pageTitle} + + + ); +}; + +const NotificationRow: FunctionComponent<{ notification: Notification }> = ({ + notification, +}) => { + const { markNotificationAsRead } = useNotificationCount(); + + const handleNotificationClick = useCallback(async () => { + await markNotificationAsRead({ + notificationEntityId: notification.entity.entityId, + }); + }, [markNotificationAsRead, notification]); + + const ownedById = useMemo( + () => + extractOwnedByIdFromEntityId( + notification.occurredInEntity.metadata.recordId.entityId, + ), + [notification], + ); + + const { shortname: entityOwningShortname } = useUserOrOrgShortnameByOwnedById( + { ownedById }, + ); + + const targetHref = useMemo(() => { + if (!entityOwningShortname) { + return undefined; + } + + if (notification.kind === "graph-change") { + return generateEntityPath({ + entityId: notification.occurredInEntity.metadata.recordId.entityId, + includeDraftId: true, + shortname: entityOwningShortname, + }); + } + + const { occurredInBlock } = notification; + + /** @todo: append query param if the mention was in a comment */ + return constructPageRelativeUrl({ + workspaceShortname: entityOwningShortname, + pageEntityUuid: extractEntityUuidFromEntityId( + notification.occurredInEntity.metadata.recordId.entityId, + ), + highlightedBlockEntityId: occurredInBlock.metadata.recordId.entityId, + }); + }, [entityOwningShortname, notification]); + + const humanReadableCreatedAt = useMemo(() => { + const now = new Date(); + + const createdAtTimestamp = + notification.kind === "graph-change" + ? (notification.occurredInEntityEditionTimestamp ?? + notification.entity.metadata.provenance.createdAtDecisionTime) + : notification.entity.metadata.provenance.createdAtDecisionTime; + + const createdAt = new Date(createdAtTimestamp); + + const numberOfMinutesAgo = differenceInMinutes(now, createdAt); + + if (numberOfMinutesAgo < 1) { + return "Just now"; + } + + if (isToday(createdAt)) { + if (numberOfMinutesAgo < 60) { + return `${numberOfMinutesAgo} minute${ + numberOfMinutesAgo > 1 ? "s" : "" + } ago`; + } + const numberOfHoursAgo = Math.floor(numberOfMinutesAgo / 60); + return `${numberOfHoursAgo} hour${numberOfHoursAgo > 1 ? "s" : ""} ago`; + } + const numberOfDaysAgo = differenceInDays(now, createdAt); + + if (numberOfDaysAgo < 7) { + return format(createdAt, "h:mma iiii"); // "12:00AM Monday" + } + + if (isThisYear(createdAt)) { + return format(createdAt, "h:mma MMMM do"); // "12:00AM October 27th" + } + + return format(createdAt, "h:mma MMMM do, yyyy"); // "12:00AM December 24th, 2022" + }, [notification]); + + return ( + palette.gray[20] + : undefined, + opacity: notification.readAt ? 0.6 : 1, + }} + > + palette.gray[70], + }, + }} + > + {humanReadableCreatedAt} + + palette.blue[70], + "&:hover": { color: ({ palette }) => palette.blue[90] }, + }, + }} + > + {notification.kind === "graph-change" ? ( + + ) : ( + + )} + + + + {notification.readAt ? null : ( + + )} + + + ); +}; + +export const NotificationsTable = () => { + const { notifications } = useNotificationsWithLinks(); + + if (notifications?.length === 0) { + return You don't have any notifications.; + } + + return ( + + + + + When + + + Title + + + Actions + + + + .${tableRowClasses.root}:last-of-type > .${tableCellClasses.root}`]: + { + borderBottomWidth: 0, + }, + }} + > + {notifications ? ( + notifications.map((notification) => ( + + )) + ) : ( + + + + + + + + + + )} + +
+ ); +}; diff --git a/apps/hash-frontend/src/pages/shared/accept-draft-entity-button.tsx b/apps/hash-frontend/src/pages/shared/accept-draft-entity-button.tsx index 03d3daaef4d..8b9186a827c 100644 --- a/apps/hash-frontend/src/pages/shared/accept-draft-entity-button.tsx +++ b/apps/hash-frontend/src/pages/shared/accept-draft-entity-button.tsx @@ -17,7 +17,7 @@ import type { import { updateEntityMutation } from "../../graphql/queries/knowledge/entity.queries"; import { useDraftEntities } from "../../shared/draft-entities-context"; import { CheckRegularIcon } from "../../shared/icons/check-regular-icon"; -import { useNotificationCount } from "../../shared/notification-entities-context"; +import { useNotificationCount } from "../../shared/notification-count-context"; import type { ButtonProps } from "../../shared/ui"; import { Button } from "../../shared/ui"; import { LinkLabelWithSourceAndDestination } from "./link-label-with-source-and-destination"; diff --git a/apps/hash-frontend/src/pages/shared/discard-draft-entity-button.tsx b/apps/hash-frontend/src/pages/shared/discard-draft-entity-button.tsx index c953fa307f8..b971f2ce0ef 100644 --- a/apps/hash-frontend/src/pages/shared/discard-draft-entity-button.tsx +++ b/apps/hash-frontend/src/pages/shared/discard-draft-entity-button.tsx @@ -17,7 +17,7 @@ import type { } from "../../graphql/api-types.gen"; import { archiveEntityMutation } from "../../graphql/queries/knowledge/entity.queries"; import { useDraftEntities } from "../../shared/draft-entities-context"; -import { useNotificationCount } from "../../shared/notification-entities-context"; +import { useNotificationCount } from "../../shared/notification-count-context"; import type { ButtonProps } from "../../shared/ui"; import { Button } from "../../shared/ui"; import { useNotificationsWithLinks } from "./notifications-with-links-context"; diff --git a/apps/hash-frontend/src/shared/layout/layout-with-header/notifications-dropdown.tsx b/apps/hash-frontend/src/shared/layout/layout-with-header/notifications-dropdown.tsx index bdb83249ec7..d9ea8326217 100644 --- a/apps/hash-frontend/src/shared/layout/layout-with-header/notifications-dropdown.tsx +++ b/apps/hash-frontend/src/shared/layout/layout-with-header/notifications-dropdown.tsx @@ -3,7 +3,7 @@ import { FontAwesomeIcon } from "@hashintel/design-system"; import { Tooltip, useTheme } from "@mui/material"; import type { FunctionComponent } from "react"; -import { useNotificationCount } from "../../notification-entities-context"; +import { useNotificationCount } from "../../notification-count-context"; import { Link } from "../../ui"; import { HeaderIconButtonWithCount } from "./shared/header-icon-button-with-count"; diff --git a/apps/hash-frontend/src/shared/layout/layout-with-sidebar/sidebar.tsx b/apps/hash-frontend/src/shared/layout/layout-with-sidebar/sidebar.tsx index 018ac9716c3..083c79653c8 100644 --- a/apps/hash-frontend/src/shared/layout/layout-with-sidebar/sidebar.tsx +++ b/apps/hash-frontend/src/shared/layout/layout-with-sidebar/sidebar.tsx @@ -22,7 +22,7 @@ import { ArrowRightToLineIcon } from "../../icons"; import { BoltLightIcon } from "../../icons/bolt-light-icon"; import { InboxIcon } from "../../icons/inbox-icon"; import { NoteIcon } from "../../icons/note-icon"; -import { useNotificationCount } from "../../notification-entities-context"; +import { useNotificationCount } from "../../notification-count-context"; import { useRoutePageInfo } from "../../routing"; import { useUserPreferences } from "../../use-user-preferences"; import { AccountEntitiesList } from "./sidebar/account-entities-list"; diff --git a/apps/hash-frontend/src/shared/notification-entities-context.tsx b/apps/hash-frontend/src/shared/notification-count-context.tsx similarity index 93% rename from apps/hash-frontend/src/shared/notification-entities-context.tsx rename to apps/hash-frontend/src/shared/notification-count-context.tsx index b55cc88e1bf..cdbda7002f9 100644 --- a/apps/hash-frontend/src/shared/notification-entities-context.tsx +++ b/apps/hash-frontend/src/shared/notification-count-context.tsx @@ -1,26 +1,18 @@ import { useMutation, useQuery } from "@apollo/client"; -import type { Entity } from "@local/hash-graph-sdk/entity"; import type { EntityId } from "@local/hash-graph-types/entity"; import type { BaseUrl } from "@local/hash-graph-types/ontology"; import { currentTimeInstantTemporalAxes, generateVersionedUrlMatchingFilter, - mapGqlSubgraphFieldsFragmentToSubgraph, pageOrNotificationNotArchivedFilter, zeroedGraphResolveDepths, } from "@local/hash-isomorphic-utils/graph-queries"; import { systemEntityTypes } from "@local/hash-isomorphic-utils/ontology-type-ids"; -import { simplifyProperties } from "@local/hash-isomorphic-utils/simplify-properties"; import type { ArchivedPropertyValueWithMetadata, - CommentNotification, Notification, ReadAtPropertyValueWithMetadata, } from "@local/hash-isomorphic-utils/system-types/commentnotification"; -import type { GraphChangeNotification } from "@local/hash-isomorphic-utils/system-types/graphchangenotification"; -import type { MentionNotification } from "@local/hash-isomorphic-utils/system-types/mentionnotification"; -import type { EntityRootType } from "@local/hash-subgraph"; -import { getRoots } from "@local/hash-subgraph/stdlib"; import type { FunctionComponent, PropsWithChildren } from "react"; import { createContext, useCallback, useContext, useMemo } from "react"; @@ -274,7 +266,8 @@ export const NotificationCountContextProvider: FunctionComponent< loading: loadingNotificationCount, markNotificationAsRead, markNotificationsAsRead, - numberOfUnreadNotifications: notificationCountData?.getEntitySubgraph, + numberOfUnreadNotifications: + notificationCountData?.getEntitySubgraph?.count, refetch, }), [ diff --git a/blocks/callout/src/types/generated/block-entity.ts b/blocks/callout/src/types/generated/block-entity.ts index 8dd781dc4ee..226232a9c33 100644 --- a/blocks/callout/src/types/generated/block-entity.ts +++ b/blocks/callout/src/types/generated/block-entity.ts @@ -2,68 +2,47 @@ * This file was automatically generated – do not edit it. */ -import { Entity } from "@blockprotocol/graph" +import { Entity } from "@blockprotocol/graph"; +export type BlockEntity = CalloutBlock; +export type BlockEntityOutgoingLinkAndTarget = + CalloutBlockOutgoingLinkAndTarget; - - -export type BlockEntity = CalloutBlock - - - -export type BlockEntityOutgoingLinkAndTarget = CalloutBlockOutgoingLinkAndTarget - - - -export type CalloutBlock = Entity - +export type CalloutBlock = Entity; /** * A Unicode emoji displayed along the textual contents of a Callout block. - * + * * See: https://unicode.org/emoji/charts/full-emoji-list.html */ -export type CalloutBlockEmojiPropertyValue = TextDataType - - - -export type CalloutBlockOutgoingLinkAndTarget = never - -export type CalloutBlockOutgoingLinksByLinkEntityTypeId = { } - +export type CalloutBlockEmojiPropertyValue = TextDataType; +export type CalloutBlockOutgoingLinkAndTarget = never; +export type CalloutBlockOutgoingLinksByLinkEntityTypeId = {}; /** * The block entity for the “Callout” block. - * + * * See: https://blockprotocol.org/@hash/blocks/callout */ export type CalloutBlockProperties = { -"https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/"?: TextualContentPropertyValue -"https://blockprotocol.org/@hash/types/property-type/callout-block-emoji/"?: CalloutBlockEmojiPropertyValue -} - + "https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/"?: TextualContentPropertyValue; + "https://blockprotocol.org/@hash/types/property-type/callout-block-emoji/"?: CalloutBlockEmojiPropertyValue; +}; /** * An opaque, untyped JSON object */ -export type ObjectDataType = { - -} - +export type ObjectDataType = {}; /** * An ordered sequence of characters */ -export type TextDataType = string - +export type TextDataType = string; /** * The text material, information, or body, that makes up the content of this thing. */ -export type TextualContentPropertyValue = (TextDataType | ObjectDataType[]) - - - +export type TextualContentPropertyValue = TextDataType | ObjectDataType[]; diff --git a/blocks/code/src/types/generated/block-entity.ts b/blocks/code/src/types/generated/block-entity.ts index b1335f8ee6f..9c678dc8b88 100644 --- a/blocks/code/src/types/generated/block-entity.ts +++ b/blocks/code/src/types/generated/block-entity.ts @@ -2,79 +2,54 @@ * This file was automatically generated – do not edit it. */ -import { Entity } from "@blockprotocol/graph" +import { Entity } from "@blockprotocol/graph"; +export type BlockEntity = CodeBlock; - - - -export type BlockEntity = CodeBlock - - - -export type BlockEntityOutgoingLinkAndTarget = CodeBlockOutgoingLinkAndTarget - +export type BlockEntityOutgoingLinkAndTarget = CodeBlockOutgoingLinkAndTarget; /** * A brief explanation or accompanying message. */ -export type CaptionPropertyValue = TextDataType - - - - -export type CodeBlock = Entity +export type CaptionPropertyValue = TextDataType; +export type CodeBlock = Entity; /** * A description of the language the code is written in. - * + * * This should conform to one of the languages supported by Prism, for example "javascript". - * + * * See: https://prismjs.com/#supported-languages */ -export type CodeBlockLanguagePropertyValue = TextDataType - - - -export type CodeBlockOutgoingLinkAndTarget = never - -export type CodeBlockOutgoingLinksByLinkEntityTypeId = { } - - +export type CodeBlockLanguagePropertyValue = TextDataType; +export type CodeBlockOutgoingLinkAndTarget = never; +export type CodeBlockOutgoingLinksByLinkEntityTypeId = {}; /** * The block entity of the “Code” block. - * + * * See: https://blockprotocol.org/@hash/blocks/code */ export type CodeBlockProperties = { -"https://blockprotocol.org/@blockprotocol/types/property-type/caption/"?: CaptionPropertyValue -"https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/"?: TextualContentPropertyValue -"https://blockprotocol.org/@hash/types/property-type/code-block-language/"?: CodeBlockLanguagePropertyValue -} - + "https://blockprotocol.org/@blockprotocol/types/property-type/caption/"?: CaptionPropertyValue; + "https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/"?: TextualContentPropertyValue; + "https://blockprotocol.org/@hash/types/property-type/code-block-language/"?: CodeBlockLanguagePropertyValue; +}; /** * An opaque, untyped JSON object */ -export type ObjectDataType = { - -} - +export type ObjectDataType = {}; /** * An ordered sequence of characters */ -export type TextDataType = string - +export type TextDataType = string; /** * The text material, information, or body, that makes up the content of this thing. */ -export type TextualContentPropertyValue = (TextDataType | ObjectDataType[]) - - - +export type TextualContentPropertyValue = TextDataType | ObjectDataType[]; diff --git a/blocks/countdown/src/types/generated/block-entity.ts b/blocks/countdown/src/types/generated/block-entity.ts index 6bc08ea0542..0ff9b56f4c5 100644 --- a/blocks/countdown/src/types/generated/block-entity.ts +++ b/blocks/countdown/src/types/generated/block-entity.ts @@ -2,76 +2,55 @@ * This file was automatically generated – do not edit it. */ -import { Entity } from "@blockprotocol/graph" +import { Entity } from "@blockprotocol/graph"; +export type BlockEntity = CountdownBlock; - - - -export type BlockEntity = CountdownBlock - - - -export type BlockEntityOutgoingLinkAndTarget = CountdownBlockOutgoingLinkAndTarget - +export type BlockEntityOutgoingLinkAndTarget = + CountdownBlockOutgoingLinkAndTarget; /** * A True or False value */ -export type BooleanDataType = boolean - - - -export type CountdownBlock = Entity - - -export type CountdownBlockOutgoingLinkAndTarget = never - -export type CountdownBlockOutgoingLinksByLinkEntityTypeId = { } - +export type BooleanDataType = boolean; +export type CountdownBlock = Entity; +export type CountdownBlockOutgoingLinkAndTarget = never; +export type CountdownBlockOutgoingLinksByLinkEntityTypeId = {}; /** * The block entity for the “Countdown” block. - * + * * See: https://blockprotocol.org/@hash/blocks/countdown */ export type CountdownBlockProperties = { -"https://blockprotocol.org/@blockprotocol/types/property-type/title/"?: TitlePropertyValue -"https://blockprotocol.org/@hash/types/property-type/target-date-and-time/"?: TargetDateAndTimePropertyValue -"https://blockprotocol.org/@hash/types/property-type/countdown-block-should-display-time/"?: CountdownBlockShouldDisplayTimePropertyValue -} - + "https://blockprotocol.org/@blockprotocol/types/property-type/title/"?: TitlePropertyValue; + "https://blockprotocol.org/@hash/types/property-type/target-date-and-time/"?: TargetDateAndTimePropertyValue; + "https://blockprotocol.org/@hash/types/property-type/countdown-block-should-display-time/"?: CountdownBlockShouldDisplayTimePropertyValue; +}; /** * Whether or not the Countdown block should display granular time-related information, or just date information. - * + * * See: https://blockprotocol.org/@hash/blocks/countdown */ -export type CountdownBlockShouldDisplayTimePropertyValue = BooleanDataType - - +export type CountdownBlockShouldDisplayTimePropertyValue = BooleanDataType; /** * An ISO-8601 formatted date and time that acts as the target for something. - * + * * For example: “2233-03-22T13:30:23Z” */ -export type TargetDateAndTimePropertyValue = TextDataType - - +export type TargetDateAndTimePropertyValue = TextDataType; /** * An ordered sequence of characters */ -export type TextDataType = string - +export type TextDataType = string; /** * The name given to something to identify it, generally associated with objects or inanimate things such as books, websites, songs, etc. */ -export type TitlePropertyValue = TextDataType - - +export type TitlePropertyValue = TextDataType; diff --git a/blocks/divider/src/types/generated/block-entity.ts b/blocks/divider/src/types/generated/block-entity.ts index 2dc1df9978e..44ac21344b1 100644 --- a/blocks/divider/src/types/generated/block-entity.ts +++ b/blocks/divider/src/types/generated/block-entity.ts @@ -2,75 +2,57 @@ * This file was automatically generated – do not edit it. */ -import { Entity } from "@blockprotocol/graph" +import { Entity } from "@blockprotocol/graph"; +export type BlockEntity = DividerBlock; - - - -export type BlockEntity = DividerBlock - - - -export type BlockEntityOutgoingLinkAndTarget = DividerBlockOutgoingLinkAndTarget - +export type BlockEntityOutgoingLinkAndTarget = + DividerBlockOutgoingLinkAndTarget; /** * The text color represented as a CSS-compatible color property expressed as a string. - * + * * This is any ‘legal’ color value in CSS, for example (but not limited to) - * + * * - a hexadecimal string: “#FFFFFF” - * + * * - a named color: “skyblue” - * + * * - an RGB value in functional notation: “rgb(255, 0, 255)” - * + * * - an HSLA value in functional notation: “hsla(120, 100%, 50%)” - * + * * See: https://www.w3schools.com/cssref/css_colors_legal.php */ -export type CSSBackgroundColorPropertyValue = TextDataType - - - - -export type DividerBlock = Entity - - -export type DividerBlockOutgoingLinkAndTarget = never - -export type DividerBlockOutgoingLinksByLinkEntityTypeId = { } +export type CSSBackgroundColorPropertyValue = TextDataType; +export type DividerBlock = Entity; +export type DividerBlockOutgoingLinkAndTarget = never; +export type DividerBlockOutgoingLinksByLinkEntityTypeId = {}; /** * The block entity for the “Divider” block. - * + * * See: https://blockprotocol.org/@hash/blocks/divider */ export type DividerBlockProperties = { -"https://blockprotocol.org/@blockprotocol/types/property-type/height-in-pixels/"?: HeightInPixelsPropertyValue -"https://blockprotocol.org/@blockprotocol/types/property-type/css-background-color/"?: CSSBackgroundColorPropertyValue -} - + "https://blockprotocol.org/@blockprotocol/types/property-type/height-in-pixels/"?: HeightInPixelsPropertyValue; + "https://blockprotocol.org/@blockprotocol/types/property-type/css-background-color/"?: CSSBackgroundColorPropertyValue; +}; /** * The height of a UI element in pixels. */ -export type HeightInPixelsPropertyValue = NumberDataType - - +export type HeightInPixelsPropertyValue = NumberDataType; /** * An arithmetical value (in the Real number system) */ -export type NumberDataType = number - +export type NumberDataType = number; /** * An ordered sequence of characters */ -export type TextDataType = string - +export type TextDataType = string; diff --git a/blocks/heading/src/types/generated/block-entity.ts b/blocks/heading/src/types/generated/block-entity.ts new file mode 100644 index 00000000000..11040c8ea65 --- /dev/null +++ b/blocks/heading/src/types/generated/block-entity.ts @@ -0,0 +1,71 @@ +/** + * This file was automatically generated – do not edit it. + */ + +import { Entity } from "@blockprotocol/graph"; + +export type BlockEntity = HeadingBlock; + +export type BlockEntityOutgoingLinkAndTarget = + HeadingBlockOutgoingLinkAndTarget; + +/** + * The text color, represented as a CSS-compatible color property expressed as a string. + * + * This is any ‘legal’ color value in CSS, for example (but not limited to) + * + * - a hexadecimal string: “#FFFFFF” + * + * - a named color: “skyblue” + * + * - an RGB value in functional notation: “rgb(255, 0, 255)” + * + * - an HSLA value in functional notation: “hsla(120, 100%, 50%)” + * + * See: https://www.w3schools.com/cssref/css_colors_legal.php + */ +export type CSSTextColorPropertyValue = TextDataType; + +/** + * The “level” or size of the heading, this can be an integer between 1 to 6 (inclusive). + * + * This corresponds to the equivalent HTML tags (h1, h2, etc.) + */ +export type HTMLHeadingLevelPropertyValue = NumberDataType; + +export type HeadingBlock = Entity; + +export type HeadingBlockOutgoingLinkAndTarget = never; + +export type HeadingBlockOutgoingLinksByLinkEntityTypeId = {}; + +/** + * The block entity for the “Heading” block. + * + * See: https://blockprotocol.org/@hash/blocks/heading + */ +export type HeadingBlockProperties = { + "https://blockprotocol.org/@blockprotocol/types/property-type/html-heading-level/"?: HTMLHeadingLevelPropertyValue; + "https://blockprotocol.org/@blockprotocol/types/property-type/css-text-color/"?: CSSTextColorPropertyValue; + "https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/"?: TextualContentPropertyValue; +}; + +/** + * An arithmetical value (in the Real number system) + */ +export type NumberDataType = number; + +/** + * An opaque, untyped JSON object + */ +export type ObjectDataType = {}; + +/** + * An ordered sequence of characters + */ +export type TextDataType = string; + +/** + * The text material, information, or body, that makes up the content of this thing. + */ +export type TextualContentPropertyValue = TextDataType | ObjectDataType[]; diff --git a/blocks/image/src/types/generated/block-entity.ts b/blocks/image/src/types/generated/block-entity.ts index 308ed2627b1..1039ac58ee2 100644 --- a/blocks/image/src/types/generated/block-entity.ts +++ b/blocks/image/src/types/generated/block-entity.ts @@ -2,286 +2,205 @@ * This file was automatically generated – do not edit it. */ -import { Entity, LinkData } from "@blockprotocol/graph" +import { Entity, LinkData } from "@blockprotocol/graph"; +export type BlockEntity = ImageBlock; - - - -export type BlockEntity = ImageBlock - - - -export type BlockEntityOutgoingLinkAndTarget = ImageBlockOutgoingLinkAndTarget - +export type BlockEntityOutgoingLinkAndTarget = ImageBlockOutgoingLinkAndTarget; /** * A True or False value */ -export type BooleanDataType = boolean - +export type BooleanDataType = boolean; /** * A brief explanation or accompanying message. */ -export type CaptionPropertyValue = TextDataType - - +export type CaptionPropertyValue = TextDataType; /** * A piece of text that tells you about something or someone. This can include explaining what they look like, what its purpose is for, what they’re like, etc. */ -export type DescriptionPropertyValue = TextDataType - - +export type DescriptionPropertyValue = TextDataType; /** * A human-friendly display name for something */ -export type DisplayNamePropertyValue = TextDataType - - +export type DisplayNamePropertyValue = TextDataType; +export type DisplaysMediaFile = Entity & { + linkData: LinkData; +}; -export type DisplaysMediaFile = Entity & { linkData: LinkData } +export type DisplaysMediaFileOutgoingLinkAndTarget = never; - -export type DisplaysMediaFileOutgoingLinkAndTarget = never - -export type DisplaysMediaFileOutgoingLinksByLinkEntityTypeId = { } +export type DisplaysMediaFileOutgoingLinksByLinkEntityTypeId = {}; /** * Displays this media file. */ -export type DisplaysMediaFileProperties = (DisplaysMediaFileProperties1 & DisplaysMediaFileProperties2) -export type DisplaysMediaFileProperties1 = LinkProperties - +export type DisplaysMediaFileProperties = DisplaysMediaFileProperties1 & + DisplaysMediaFileProperties2; +export type DisplaysMediaFileProperties1 = LinkProperties; -export type DisplaysMediaFileProperties2 = { - -} - - - -export type File = Entity +export type DisplaysMediaFileProperties2 = {}; +export type File = Entity; /** * A unique signature derived from a file's contents */ -export type FileHashPropertyValue = TextDataType - - +export type FileHashPropertyValue = TextDataType; /** * The name of a file. */ -export type FileNamePropertyValue = TextDataType - - - -export type FileOutgoingLinkAndTarget = never - -export type FileOutgoingLinksByLinkEntityTypeId = { } - - - - - - - - - - - - - - - +export type FileNamePropertyValue = TextDataType; +export type FileOutgoingLinkAndTarget = never; +export type FileOutgoingLinksByLinkEntityTypeId = {}; /** * A file hosted at a URL */ export type FileProperties = { -"https://blockprotocol.org/@blockprotocol/types/property-type/description/"?: DescriptionPropertyValue -"https://blockprotocol.org/@blockprotocol/types/property-type/display-name/"?: DisplayNamePropertyValue -"https://blockprotocol.org/@blockprotocol/types/property-type/file-hash/"?: FileHashPropertyValue -"https://blockprotocol.org/@blockprotocol/types/property-type/file-name/"?: FileNamePropertyValue -"https://blockprotocol.org/@blockprotocol/types/property-type/file-size/"?: FileSizePropertyValue -"https://blockprotocol.org/@blockprotocol/types/property-type/file-url/": FileURLPropertyValue -"https://blockprotocol.org/@blockprotocol/types/property-type/mime-type/"?: MIMETypePropertyValue -"https://blockprotocol.org/@blockprotocol/types/property-type/original-file-name/"?: OriginalFileNamePropertyValue -"https://blockprotocol.org/@blockprotocol/types/property-type/original-source/"?: OriginalSourcePropertyValue -"https://blockprotocol.org/@blockprotocol/types/property-type/original-url/"?: OriginalURLPropertyValue -"https://hash.ai/@hash/types/property-type/file-storage-bucket/"?: FileStorageBucketPropertyValue -"https://hash.ai/@hash/types/property-type/file-storage-endpoint/"?: FileStorageEndpointPropertyValue -"https://hash.ai/@hash/types/property-type/file-storage-force-path-style/"?: FileStorageForcePathStylePropertyValue -"https://hash.ai/@hash/types/property-type/file-storage-key/"?: FileStorageKeyPropertyValue -"https://hash.ai/@hash/types/property-type/file-storage-provider/"?: FileStorageProviderPropertyValue -"https://hash.ai/@hash/types/property-type/file-storage-region/"?: FileStorageRegionPropertyValue -} - + "https://blockprotocol.org/@blockprotocol/types/property-type/description/"?: DescriptionPropertyValue; + "https://blockprotocol.org/@blockprotocol/types/property-type/display-name/"?: DisplayNamePropertyValue; + "https://blockprotocol.org/@blockprotocol/types/property-type/file-hash/"?: FileHashPropertyValue; + "https://blockprotocol.org/@blockprotocol/types/property-type/file-name/"?: FileNamePropertyValue; + "https://blockprotocol.org/@blockprotocol/types/property-type/file-size/"?: FileSizePropertyValue; + "https://blockprotocol.org/@blockprotocol/types/property-type/file-url/": FileURLPropertyValue; + "https://blockprotocol.org/@blockprotocol/types/property-type/mime-type/"?: MIMETypePropertyValue; + "https://blockprotocol.org/@blockprotocol/types/property-type/original-file-name/"?: OriginalFileNamePropertyValue; + "https://blockprotocol.org/@blockprotocol/types/property-type/original-source/"?: OriginalSourcePropertyValue; + "https://blockprotocol.org/@blockprotocol/types/property-type/original-url/"?: OriginalURLPropertyValue; + "https://hash.ai/@hash/types/property-type/file-storage-bucket/"?: FileStorageBucketPropertyValue; + "https://hash.ai/@hash/types/property-type/file-storage-endpoint/"?: FileStorageEndpointPropertyValue; + "https://hash.ai/@hash/types/property-type/file-storage-force-path-style/"?: FileStorageForcePathStylePropertyValue; + "https://hash.ai/@hash/types/property-type/file-storage-key/"?: FileStorageKeyPropertyValue; + "https://hash.ai/@hash/types/property-type/file-storage-provider/"?: FileStorageProviderPropertyValue; + "https://hash.ai/@hash/types/property-type/file-storage-region/"?: FileStorageRegionPropertyValue; +}; /** * The size of a file */ -export type FileSizePropertyValue = NumberDataType - - +export type FileSizePropertyValue = NumberDataType; /** * The bucket in which a file is stored. */ -export type FileStorageBucketPropertyValue = TextDataType - - +export type FileStorageBucketPropertyValue = TextDataType; /** * The endpoint for making requests to a file storage provider. */ -export type FileStorageEndpointPropertyValue = TextDataType - - +export type FileStorageEndpointPropertyValue = TextDataType; /** * Whether to force path style for requests to a file storage provider (vs virtual host style). */ -export type FileStorageForcePathStylePropertyValue = BooleanDataType - - +export type FileStorageForcePathStylePropertyValue = BooleanDataType; /** * The key identifying a file in storage. */ -export type FileStorageKeyPropertyValue = TextDataType - - +export type FileStorageKeyPropertyValue = TextDataType; /** * The provider of a file storage service. */ -export type FileStorageProviderPropertyValue = TextDataType - - +export type FileStorageProviderPropertyValue = TextDataType; /** * The region in which a file is stored. */ -export type FileStorageRegionPropertyValue = TextDataType - - +export type FileStorageRegionPropertyValue = TextDataType; /** * A URL that serves a file. */ -export type FileURLPropertyValue = TextDataType - - - - -export type Image = Entity - - - -export type ImageBlock = Entity - +export type FileURLPropertyValue = TextDataType; -export type ImageBlockDisplaysMediaFileLink = { linkEntity: DisplaysMediaFile; rightEntity: Image } +export type Image = Entity; -export type ImageBlockOutgoingLinkAndTarget = ImageBlockDisplaysMediaFileLink - -export type ImageBlockOutgoingLinksByLinkEntityTypeId = { "https://blockprotocol.org/@hash/types/entity-type/displays-media-file/v/1": ImageBlockDisplaysMediaFileLink } +export type ImageBlock = Entity; +export type ImageBlockDisplaysMediaFileLink = { + linkEntity: DisplaysMediaFile; + rightEntity: Image; +}; +export type ImageBlockOutgoingLinkAndTarget = ImageBlockDisplaysMediaFileLink; +export type ImageBlockOutgoingLinksByLinkEntityTypeId = { + "https://blockprotocol.org/@hash/types/entity-type/displays-media-file/v/1": ImageBlockDisplaysMediaFileLink; +}; /** * The block entity for the “Image” block. - * + * * See: https://blockprotocol.org/@hash/blocks/image */ export type ImageBlockProperties = { -"https://blockprotocol.org/@blockprotocol/types/property-type/caption/"?: CaptionPropertyValue -"https://blockprotocol.org/@blockprotocol/types/property-type/width-in-pixels/"?: WidthInPixelsPropertyValue -} - + "https://blockprotocol.org/@blockprotocol/types/property-type/caption/"?: CaptionPropertyValue; + "https://blockprotocol.org/@blockprotocol/types/property-type/width-in-pixels/"?: WidthInPixelsPropertyValue; +}; -export type ImageOutgoingLinkAndTarget = never +export type ImageOutgoingLinkAndTarget = never; -export type ImageOutgoingLinksByLinkEntityTypeId = { } +export type ImageOutgoingLinksByLinkEntityTypeId = {}; /** * An image file hosted at a URL */ -export type ImageProperties = (ImageProperties1 & ImageProperties2) -export type ImageProperties1 = FileProperties - - -export type ImageProperties2 = { - -} - +export type ImageProperties = ImageProperties1 & ImageProperties2; +export type ImageProperties1 = FileProperties; +export type ImageProperties2 = {}; -export type Link = Entity +export type Link = Entity; +export type LinkOutgoingLinkAndTarget = never; -export type LinkOutgoingLinkAndTarget = never - -export type LinkOutgoingLinksByLinkEntityTypeId = { } - -export type LinkProperties = { - -} +export type LinkOutgoingLinksByLinkEntityTypeId = {}; +export type LinkProperties = {}; /** * A MIME (Multipurpose Internet Mail Extensions) type. - * + * * See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types */ -export type MIMETypePropertyValue = TextDataType - - +export type MIMETypePropertyValue = TextDataType; /** * An arithmetical value (in the Real number system) */ -export type NumberDataType = number - +export type NumberDataType = number; /** * The original name of a file */ -export type OriginalFileNamePropertyValue = TextDataType - - +export type OriginalFileNamePropertyValue = TextDataType; /** * The original source of something */ -export type OriginalSourcePropertyValue = TextDataType - - +export type OriginalSourcePropertyValue = TextDataType; /** * The original URL something was hosted at */ -export type OriginalURLPropertyValue = TextDataType - - +export type OriginalURLPropertyValue = TextDataType; /** * An ordered sequence of characters */ -export type TextDataType = string - +export type TextDataType = string; /** * The width of a UI element in pixels. */ -export type WidthInPixelsPropertyValue = NumberDataType - - +export type WidthInPixelsPropertyValue = NumberDataType; diff --git a/blocks/minesweeper/src/types/generated/block-entity.ts b/blocks/minesweeper/src/types/generated/block-entity.ts index e6054105597..6f9593fed46 100644 --- a/blocks/minesweeper/src/types/generated/block-entity.ts +++ b/blocks/minesweeper/src/types/generated/block-entity.ts @@ -2,57 +2,40 @@ * This file was automatically generated – do not edit it. */ -import { Entity } from "@blockprotocol/graph" +import { Entity } from "@blockprotocol/graph"; +export type BlockEntity = MinesweeperBlock; +export type BlockEntityOutgoingLinkAndTarget = + MinesweeperBlockOutgoingLinkAndTarget; +export type MinesweeperBlock = Entity; +export type MinesweeperBlockOutgoingLinkAndTarget = never; -export type BlockEntity = MinesweeperBlock - - - -export type BlockEntityOutgoingLinkAndTarget = MinesweeperBlockOutgoingLinkAndTarget - - - -export type MinesweeperBlock = Entity - - -export type MinesweeperBlockOutgoingLinkAndTarget = never - -export type MinesweeperBlockOutgoingLinksByLinkEntityTypeId = { } - - - +export type MinesweeperBlockOutgoingLinksByLinkEntityTypeId = {}; /** * The block entity of the "Minesweeper" block. - * + * * See: https://blockprotocol.org/@hash/blocks/minesweeper */ export type MinesweeperBlockProperties = { -"https://blockprotocol.org/@hash/types/property-type/number-of-mines/"?: NumberOfMinesPropertyValue -"https://blockprotocol.org/@hash/types/property-type/number-of-columns/"?: NumberOfColumnsPropertyValue -} - + "https://blockprotocol.org/@hash/types/property-type/number-of-mines/"?: NumberOfMinesPropertyValue; + "https://blockprotocol.org/@hash/types/property-type/number-of-columns/"?: NumberOfColumnsPropertyValue; +}; /** * An arithmetical value (in the Real number system) */ -export type NumberDataType = number - +export type NumberDataType = number; /** * How many columns there are or should be */ -export type NumberOfColumnsPropertyValue = NumberDataType - - +export type NumberOfColumnsPropertyValue = NumberDataType; /** * How many mines there are or should be */ -export type NumberOfMinesPropertyValue = NumberDataType - - +export type NumberOfMinesPropertyValue = NumberDataType; diff --git a/blocks/paragraph/src/types/generated/block-entity.ts b/blocks/paragraph/src/types/generated/block-entity.ts index e6fbb6f0788..690a9cb134c 100644 --- a/blocks/paragraph/src/types/generated/block-entity.ts +++ b/blocks/paragraph/src/types/generated/block-entity.ts @@ -2,57 +2,39 @@ * This file was automatically generated – do not edit it. */ -import { Entity } from "@blockprotocol/graph" +import { Entity } from "@blockprotocol/graph"; +export type BlockEntity = ParagraphBlock; - - - -export type BlockEntity = ParagraphBlock - - - -export type BlockEntityOutgoingLinkAndTarget = ParagraphBlockOutgoingLinkAndTarget - +export type BlockEntityOutgoingLinkAndTarget = + ParagraphBlockOutgoingLinkAndTarget; /** * An opaque, untyped JSON object */ -export type ObjectDataType = { - -} - +export type ObjectDataType = {}; +export type ParagraphBlock = Entity; -export type ParagraphBlock = Entity - - -export type ParagraphBlockOutgoingLinkAndTarget = never - -export type ParagraphBlockOutgoingLinksByLinkEntityTypeId = { } - +export type ParagraphBlockOutgoingLinkAndTarget = never; +export type ParagraphBlockOutgoingLinksByLinkEntityTypeId = {}; /** * The block entity for the “Paragraph” block. - * + * * See: https://blockprotocol.org/@hash/blocks/paragraph */ export type ParagraphBlockProperties = { -"https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/"?: TextualContentPropertyValue -} - + "https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/"?: TextualContentPropertyValue; +}; /** * An ordered sequence of characters */ -export type TextDataType = string - +export type TextDataType = string; /** * The text material, information, or body, that makes up the content of this thing. */ -export type TextualContentPropertyValue = (TextDataType | ObjectDataType[]) - - - +export type TextualContentPropertyValue = TextDataType | ObjectDataType[]; diff --git a/blocks/timer/src/types/generated/block-entity.ts b/blocks/timer/src/types/generated/block-entity.ts index aa9e15aef60..fc9ed7692db 100644 --- a/blocks/timer/src/types/generated/block-entity.ts +++ b/blocks/timer/src/types/generated/block-entity.ts @@ -2,90 +2,69 @@ * This file was automatically generated – do not edit it. */ -import { Entity } from "@blockprotocol/graph" +import { Entity } from "@blockprotocol/graph"; +export type BlockEntity = TimerBlock; - - - -export type BlockEntity = TimerBlock - - - -export type BlockEntityOutgoingLinkAndTarget = TimerBlockOutgoingLinkAndTarget - +export type BlockEntityOutgoingLinkAndTarget = TimerBlockOutgoingLinkAndTarget; /** * An ISO-8601 formatted date and time that acts as the target for something. - * + * * For example: “2233-03-22T13:30:23Z” */ -export type TargetDateAndTimePropertyValue = TextDataType - - +export type TargetDateAndTimePropertyValue = TextDataType; /** * An ordered sequence of characters */ -export type TextDataType = string - - - -export type TimerBlock = Entity +export type TextDataType = string; +export type TimerBlock = Entity; -export type TimerBlockOutgoingLinkAndTarget = never +export type TimerBlockOutgoingLinkAndTarget = never; -export type TimerBlockOutgoingLinksByLinkEntityTypeId = { } +export type TimerBlockOutgoingLinksByLinkEntityTypeId = {}; /** * An ISO-8601 formatted duration, which remaining duration on the timer block when it has been paused. The elapsed time can be calculated by subtracting this value from the total duration. - * + * * For example: `PT42M24S` corresponds to 42 minutes and 24 seconds. - * + * * See: https://blockprotocol.org/@hash/blocks/timer */ -export type TimerBlockPauseDurationPropertyValue = TextDataType - - +export type TimerBlockPauseDurationPropertyValue = TextDataType; /** * Defines the relative offsets of the timer block when in a paused or unpaused state, respective to the total duration. - * - * See: + * + * See: * - https://blockprotocol.org/@hash/types/property-type/timer-block-total-duration * - https://blockprotocol.org/@hash/blocks/timer */ -export type TimerBlockProgressPropertyValue = ({ -"https://blockprotocol.org/@hash/types/property-type/target-date-and-time/": TargetDateAndTimePropertyValue -} | { -"https://blockprotocol.org/@hash/types/property-type/timer-block-pause-duration/": TimerBlockPauseDurationPropertyValue -}) - - - - - - +export type TimerBlockProgressPropertyValue = + | { + "https://blockprotocol.org/@hash/types/property-type/target-date-and-time/": TargetDateAndTimePropertyValue; + } + | { + "https://blockprotocol.org/@hash/types/property-type/timer-block-pause-duration/": TimerBlockPauseDurationPropertyValue; + }; /** * The block entity for the “Timer” block. - * + * * See: https://blockprotocol.org/@hash/blocks/timer */ export type TimerBlockProperties = { -"https://blockprotocol.org/@hash/types/property-type/timer-block-progress/"?: TimerBlockProgressPropertyValue -"https://blockprotocol.org/@hash/types/property-type/timer-block-total-duration/"?: TimerBlockTotalDurationPropertyValue -} - + "https://blockprotocol.org/@hash/types/property-type/timer-block-progress/"?: TimerBlockProgressPropertyValue; + "https://blockprotocol.org/@hash/types/property-type/timer-block-total-duration/"?: TimerBlockTotalDurationPropertyValue; +}; /** * An ISO-8601 formatted duration, which is the total duration the timer will countdown for once the play button is clicked. - * + * * For example: `PT42M24S` corresponds to 42 minutes and 24 seconds. - * + * * See: https://blockprotocol.org/@hash/blocks/timer */ -export type TimerBlockTotalDurationPropertyValue = TextDataType - - +export type TimerBlockTotalDurationPropertyValue = TextDataType; diff --git a/blocks/video/src/types/generated/block-entity.ts b/blocks/video/src/types/generated/block-entity.ts new file mode 100644 index 00000000000..83aab43af6f --- /dev/null +++ b/blocks/video/src/types/generated/block-entity.ts @@ -0,0 +1,200 @@ +/** + * This file was automatically generated – do not edit it. + */ + +import { Entity, LinkData } from "@blockprotocol/graph"; + +export type BlockEntity = VideoBlock; + +export type BlockEntityOutgoingLinkAndTarget = VideoBlockOutgoingLinkAndTarget; + +/** + * A True or False value + */ +export type BooleanDataType = boolean; + +/** + * A brief explanation or accompanying message. + */ +export type CaptionPropertyValue = TextDataType; + +/** + * A piece of text that tells you about something or someone. This can include explaining what they look like, what its purpose is for, what they’re like, etc. + */ +export type DescriptionPropertyValue = TextDataType; + +/** + * A human-friendly display name for something + */ +export type DisplayNamePropertyValue = TextDataType; + +export type DisplaysMediaFile = Entity & { + linkData: LinkData; +}; + +export type DisplaysMediaFileOutgoingLinkAndTarget = never; + +export type DisplaysMediaFileOutgoingLinksByLinkEntityTypeId = {}; + +/** + * Displays this media file. + */ +export type DisplaysMediaFileProperties = DisplaysMediaFileProperties1 & + DisplaysMediaFileProperties2; +export type DisplaysMediaFileProperties1 = LinkProperties; + +export type DisplaysMediaFileProperties2 = {}; + +export type File = Entity; + +/** + * A unique signature derived from a file's contents + */ +export type FileHashPropertyValue = TextDataType; + +/** + * The name of a file. + */ +export type FileNamePropertyValue = TextDataType; + +export type FileOutgoingLinkAndTarget = never; + +export type FileOutgoingLinksByLinkEntityTypeId = {}; + +/** + * A file hosted at a URL + */ +export type FileProperties = { + "https://blockprotocol.org/@blockprotocol/types/property-type/description/"?: DescriptionPropertyValue; + "https://blockprotocol.org/@blockprotocol/types/property-type/display-name/"?: DisplayNamePropertyValue; + "https://blockprotocol.org/@blockprotocol/types/property-type/file-hash/"?: FileHashPropertyValue; + "https://blockprotocol.org/@blockprotocol/types/property-type/file-name/"?: FileNamePropertyValue; + "https://blockprotocol.org/@blockprotocol/types/property-type/file-size/"?: FileSizePropertyValue; + "https://blockprotocol.org/@blockprotocol/types/property-type/file-url/": FileURLPropertyValue; + "https://blockprotocol.org/@blockprotocol/types/property-type/mime-type/"?: MIMETypePropertyValue; + "https://blockprotocol.org/@blockprotocol/types/property-type/original-file-name/"?: OriginalFileNamePropertyValue; + "https://blockprotocol.org/@blockprotocol/types/property-type/original-source/"?: OriginalSourcePropertyValue; + "https://blockprotocol.org/@blockprotocol/types/property-type/original-url/"?: OriginalURLPropertyValue; + "https://hash.ai/@hash/types/property-type/file-storage-bucket/"?: FileStorageBucketPropertyValue; + "https://hash.ai/@hash/types/property-type/file-storage-endpoint/"?: FileStorageEndpointPropertyValue; + "https://hash.ai/@hash/types/property-type/file-storage-force-path-style/"?: FileStorageForcePathStylePropertyValue; + "https://hash.ai/@hash/types/property-type/file-storage-key/"?: FileStorageKeyPropertyValue; + "https://hash.ai/@hash/types/property-type/file-storage-provider/"?: FileStorageProviderPropertyValue; + "https://hash.ai/@hash/types/property-type/file-storage-region/"?: FileStorageRegionPropertyValue; +}; + +/** + * The size of a file + */ +export type FileSizePropertyValue = NumberDataType; + +/** + * The bucket in which a file is stored. + */ +export type FileStorageBucketPropertyValue = TextDataType; + +/** + * The endpoint for making requests to a file storage provider. + */ +export type FileStorageEndpointPropertyValue = TextDataType; + +/** + * Whether to force path style for requests to a file storage provider (vs virtual host style). + */ +export type FileStorageForcePathStylePropertyValue = BooleanDataType; + +/** + * The key identifying a file in storage. + */ +export type FileStorageKeyPropertyValue = TextDataType; + +/** + * The provider of a file storage service. + */ +export type FileStorageProviderPropertyValue = TextDataType; + +/** + * The region in which a file is stored. + */ +export type FileStorageRegionPropertyValue = TextDataType; + +/** + * A URL that serves a file. + */ +export type FileURLPropertyValue = TextDataType; + +export type Image = Entity; + +export type ImageOutgoingLinkAndTarget = never; + +export type ImageOutgoingLinksByLinkEntityTypeId = {}; + +/** + * An image file hosted at a URL + */ +export type ImageProperties = ImageProperties1 & ImageProperties2; +export type ImageProperties1 = FileProperties; + +export type ImageProperties2 = {}; + +export type Link = Entity; + +export type LinkOutgoingLinkAndTarget = never; + +export type LinkOutgoingLinksByLinkEntityTypeId = {}; + +export type LinkProperties = {}; + +/** + * A MIME (Multipurpose Internet Mail Extensions) type. + * + * See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types + */ +export type MIMETypePropertyValue = TextDataType; + +/** + * An arithmetical value (in the Real number system) + */ +export type NumberDataType = number; + +/** + * The original name of a file + */ +export type OriginalFileNamePropertyValue = TextDataType; + +/** + * The original source of something + */ +export type OriginalSourcePropertyValue = TextDataType; + +/** + * The original URL something was hosted at + */ +export type OriginalURLPropertyValue = TextDataType; + +/** + * An ordered sequence of characters + */ +export type TextDataType = string; + +export type VideoBlock = Entity; + +export type VideoBlockDisplaysMediaFileLink = { + linkEntity: DisplaysMediaFile; + rightEntity: Image; +}; + +export type VideoBlockOutgoingLinkAndTarget = VideoBlockDisplaysMediaFileLink; + +export type VideoBlockOutgoingLinksByLinkEntityTypeId = { + "https://blockprotocol.org/@hash/types/entity-type/displays-media-file/v/1": VideoBlockDisplaysMediaFileLink; +}; + +/** + * The block entity for the “Video” block. + * + * See: https://blockprotocol.org/@hash/blocks/video + */ +export type VideoBlockProperties = { + "https://blockprotocol.org/@blockprotocol/types/property-type/caption/"?: CaptionPropertyValue; +}; diff --git a/libs/@local/harpc/client/typescript/tsconfig.json b/libs/@local/harpc/client/typescript/tsconfig.json index ab21763bae7..d388501d083 100644 --- a/libs/@local/harpc/client/typescript/tsconfig.json +++ b/libs/@local/harpc/client/typescript/tsconfig.json @@ -1,7 +1,7 @@ { "extends": "@local/tsconfig/legacy-base-tsconfig-to-refactor.json", "compilerOptions": { - "lib": ["dom", "dom.iterable", "ES2023", "ESNext"], + "lib": ["ES2023", "ESNext"], "module": "NodeNext", "moduleResolution": "NodeNext", "types": ["vitest/importMeta"] diff --git a/libs/@local/hash-isomorphic-utils/src/graphql/type-defs/generation.typedef.ts b/libs/@local/hash-isomorphic-utils/src/graphql/type-defs/generation.typedef.ts index 976f10a4255..878ca394c90 100644 --- a/libs/@local/hash-isomorphic-utils/src/graphql/type-defs/generation.typedef.ts +++ b/libs/@local/hash-isomorphic-utils/src/graphql/type-defs/generation.typedef.ts @@ -9,8 +9,6 @@ export const generationTypedef = gql` extend type Query { """ Generates the plural form of a word or phrase (e.g. Company -> Companies) - - TODO handle missing API keys gracefully for self-hosted instances """ generatePlural(singular: String!): String! diff --git a/libs/@local/hash-isomorphic-utils/src/graphql/type-defs/knowledge/entity.typedef.ts b/libs/@local/hash-isomorphic-utils/src/graphql/type-defs/knowledge/entity.typedef.ts index fc82d113c92..edfaf5af0fe 100644 --- a/libs/@local/hash-isomorphic-utils/src/graphql/type-defs/knowledge/entity.typedef.ts +++ b/libs/@local/hash-isomorphic-utils/src/graphql/type-defs/knowledge/entity.typedef.ts @@ -24,7 +24,7 @@ export const entityTypedef = gql` } type GetEntitySubgraphResponse { - count?: Int; + count?: Int closedMultiEntityTypes: ClosedMultiEntityTypesRootMap definitions: ClosedMultiEntityTypesDefinitions userPermissionsOnEntities: UserPermissionsOnEntities! From 8e53f588fe002587bcfc4489d5e1b80450aa3c0e Mon Sep 17 00:00:00 2001 From: Ciaran Morinan Date: Mon, 9 Dec 2024 16:27:43 +0000 Subject: [PATCH 3/5] finish polling for any count of notifs/drafts unless on their pages (pending testing) --- .../src/graph/knowledge/primitive/entity.ts | 2 + apps/hash-frontend/src/pages/_app.page.tsx | 6 +- apps/hash-frontend/src/pages/actions.page.tsx | 22 +- .../draft-entities-bulk-actions-dropdown.tsx | 71 +++--- .../actions.page}/draft-entities-context.tsx | 28 ++- .../src/pages/actions.page/draft-entities.tsx | 2 +- .../src/pages/actions.page/draft-entity.tsx | 2 +- .../draft-entity-action-buttons.tsx | 6 +- .../src/pages/notifications.page.tsx | 2 +- .../notifications-table.tsx | 8 +- .../notifications-with-links-context.tsx | 11 +- .../shared/accept-draft-entity-button.tsx | 43 +--- .../shared/discard-draft-entity-button.tsx | 38 +-- .../shared/draft-entities-count-context.tsx | 92 ++++++++ .../layout/layout-with-header/page-header.tsx | 6 +- .../layout/layout-with-sidebar/sidebar.tsx | 8 +- .../src/shared/notification-count-context.tsx | 217 +++++++++++------- .../type-defs/knowledge/entity.typedef.ts | 2 +- 18 files changed, 333 insertions(+), 233 deletions(-) rename apps/hash-frontend/src/{shared => pages/actions.page}/draft-entities-context.tsx (80%) rename apps/hash-frontend/src/pages/{shared => notifications.page}/notifications-with-links-context.tsx (98%) create mode 100644 apps/hash-frontend/src/shared/draft-entities-count-context.tsx diff --git a/apps/hash-api/src/graph/knowledge/primitive/entity.ts b/apps/hash-api/src/graph/knowledge/primitive/entity.ts index 7942a671bf8..37eb3d5ca50 100644 --- a/apps/hash-api/src/graph/knowledge/primitive/entity.ts +++ b/apps/hash-api/src/graph/knowledge/primitive/entity.ts @@ -237,6 +237,8 @@ export const getEntitySubgraphResponse: ImpureGraphFunction< } } + console.log({ rest, params }); + return { closedMultiEntityTypes, definitions: definitions diff --git a/apps/hash-frontend/src/pages/_app.page.tsx b/apps/hash-frontend/src/pages/_app.page.tsx index 50cc5b7ee0c..e0c64901c1e 100644 --- a/apps/hash-frontend/src/pages/_app.page.tsx +++ b/apps/hash-frontend/src/pages/_app.page.tsx @@ -35,7 +35,7 @@ import { hasAccessToHashQuery, meQuery } from "../graphql/queries/user.queries"; import { apolloClient } from "../lib/apollo-client"; import type { MinimalUser } from "../lib/user-and-org"; import { constructMinimalUser } from "../lib/user-and-org"; -import { DraftEntitiesContextProvider } from "../shared/draft-entities-context"; +import { DraftEntitiesCountContextProvider } from "../shared/draft-entities-count-context"; import { EntityTypesContextProvider } from "../shared/entity-types-context/provider"; import { FileUploadsProvider } from "../shared/file-upload-context"; import { KeyboardShortcutsContextProvider } from "../shared/keyboard-shortcuts-context"; @@ -109,7 +109,7 @@ const App: FunctionComponent = ({ - + @@ -132,7 +132,7 @@ const App: FunctionComponent = ({ - + diff --git a/apps/hash-frontend/src/pages/actions.page.tsx b/apps/hash-frontend/src/pages/actions.page.tsx index 2750b6b362a..1fb7ae99929 100644 --- a/apps/hash-frontend/src/pages/actions.page.tsx +++ b/apps/hash-frontend/src/pages/actions.page.tsx @@ -24,7 +24,6 @@ import type { GetEntitySubgraphQueryVariables, } from "../graphql/api-types.gen"; import { getEntitySubgraphQuery } from "../graphql/queries/knowledge/entity.queries"; -import { useDraftEntities } from "../shared/draft-entities-context"; import { BarsSortRegularIcon } from "../shared/icons/bars-sort-regular-icon"; import type { NextPageWithLayout } from "../shared/layout"; import { getLayoutWithSidebar } from "../shared/layout"; @@ -32,8 +31,11 @@ import { MenuItem } from "../shared/ui"; import type { SortOrder } from "./actions.page/draft-entities"; import { DraftEntities } from "./actions.page/draft-entities"; import { DraftEntitiesBulkActionsDropdown } from "./actions.page/draft-entities-bulk-actions-dropdown"; +import { + DraftEntitiesContextProvider, + useDraftEntities, +} from "./actions.page/draft-entities-context"; import { InlineSelect } from "./shared/inline-select"; -import { NotificationsWithLinksContextProvider } from "./shared/notifications-with-links-context"; import { TopContextBar } from "./shared/top-context-bar"; const sortOrderHumanReadable: Record = { @@ -41,7 +43,7 @@ const sortOrderHumanReadable: Record = { "created-at-desc": "creation date/time (newest first)", }; -const ActionsPage: NextPageWithLayout = () => { +const ActionsPage = () => { const [selectedDraftEntityIds, setSelectedDraftEntityIds] = useState< EntityId[] >([]); @@ -117,7 +119,7 @@ const ActionsPage: NextPageWithLayout = () => { ); return ( - + <> { draftEntitiesWithLinkedDataSubgraph } /> - + + ); +}; + +const ActionsPageOuter: NextPageWithLayout = () => { + return ( + + + ); }; -ActionsPage.getLayout = (page) => +ActionsPageOuter.getLayout = (page) => getLayoutWithSidebar(page, { fullWidth: true, }); diff --git a/apps/hash-frontend/src/pages/actions.page/draft-entities-bulk-actions-dropdown.tsx b/apps/hash-frontend/src/pages/actions.page/draft-entities-bulk-actions-dropdown.tsx index 1d783fed5bb..1f58a9b6351 100644 --- a/apps/hash-frontend/src/pages/actions.page/draft-entities-bulk-actions-dropdown.tsx +++ b/apps/hash-frontend/src/pages/actions.page/draft-entities-bulk-actions-dropdown.tsx @@ -28,11 +28,10 @@ import { archiveEntitiesMutation, updateEntitiesMutation, } from "../../graphql/queries/knowledge/entity.queries"; -import { useDraftEntities } from "../../shared/draft-entities-context"; import { LayerGroupLightIcon } from "../../shared/icons/layer-group-light-icon"; import { useNotificationCount } from "../../shared/notification-count-context"; import { Button, MenuItem } from "../../shared/ui"; -import { useNotificationsWithLinks } from "../shared/notifications-with-links-context"; +import { useDraftEntities } from "./draft-entities-context"; export const DraftEntitiesBulkActionsDropdown: FunctionComponent<{ selectedDraftEntityIds: EntityId[]; @@ -44,8 +43,7 @@ export const DraftEntitiesBulkActionsDropdown: FunctionComponent<{ deselectAllDraftEntities, }) => { const { draftEntities, refetch: refetchDraftEntities } = useDraftEntities(); - const { notifications } = useNotificationsWithLinks(); - const { archiveNotifications, markNotificationsAsRead } = + const { archiveNotificationsForEntity, markNotificationsAsReadForEntity } = useNotificationCount(); const popupState = usePopupState({ @@ -108,41 +106,37 @@ export const DraftEntitiesBulkActionsDropdown: FunctionComponent<{ >(archiveEntitiesMutation); const ignoreAllSelectedDraftEntities = useCallback(async () => { - if (!notifications) { + if (!selectedDraftEntities.length) { return; } - const relatedNotifications = notifications.filter((notification) => - selectedDraftEntityIds.includes( - notification.occurredInEntity.metadata.recordId.entityId, - ), - ); - await archiveEntities({ variables: { entityIds: [ - ...selectedDraftEntities, - ...(incomingOrOutgoingDraftLinksToIgnore ?? []), - ].map(({ metadata }) => metadata.recordId.entityId), + ...selectedDraftEntityIds, + ...(incomingOrOutgoingDraftLinksToIgnore ?? []).map( + ({ metadata }) => metadata.recordId.entityId, + ), + ], }, }); - await archiveNotifications({ - notificationEntities: relatedNotifications.map(({ entity }) => entity), - }); - + await Promise.all( + selectedDraftEntityIds.map((entityId) => + archiveNotificationsForEntity({ targetEntityId: entityId }), + ), + ); await refetchDraftEntities(); deselectAllDraftEntities(); }, [ - notifications, - archiveNotifications, archiveEntities, - selectedDraftEntityIds, - selectedDraftEntities, - refetchDraftEntities, - incomingOrOutgoingDraftLinksToIgnore, + archiveNotificationsForEntity, deselectAllDraftEntities, + incomingOrOutgoingDraftLinksToIgnore, + refetchDraftEntities, + selectedDraftEntities, + selectedDraftEntityIds, ]); const [ @@ -222,15 +216,6 @@ export const DraftEntitiesBulkActionsDropdown: FunctionComponent<{ >(updateEntitiesMutation); const acceptAllSelectedDraftEntities = useCallback(async () => { - const relatedGraphChangeNotifications = - notifications?.filter( - ({ kind, occurredInEntity }) => - kind === "graph-change" && - selectedDraftEntityIds.includes( - occurredInEntity.metadata.recordId.entityId, - ), - ) ?? []; - await updateEntities({ variables: { entityUpdates: [ @@ -244,24 +229,24 @@ export const DraftEntitiesBulkActionsDropdown: FunctionComponent<{ }, }); - await markNotificationsAsRead({ - notificationEntities: relatedGraphChangeNotifications.map( - ({ entity }) => entity, + await Promise.all( + selectedDraftEntities.map((entity) => + markNotificationsAsReadForEntity({ + targetEntityId: entity.entityId, + }), ), - }); + ); await refetchDraftEntities(); deselectAllDraftEntities(); }, [ - notifications, - markNotificationsAsRead, - selectedDraftEntityIds, - selectedDraftEntities, + deselectAllDraftEntities, leftOrRightDraftEntitiesToAccept, - updateEntities, + markNotificationsAsReadForEntity, refetchDraftEntities, - deselectAllDraftEntities, + selectedDraftEntities, + updateEntities, ]); const [ diff --git a/apps/hash-frontend/src/shared/draft-entities-context.tsx b/apps/hash-frontend/src/pages/actions.page/draft-entities-context.tsx similarity index 80% rename from apps/hash-frontend/src/shared/draft-entities-context.tsx rename to apps/hash-frontend/src/pages/actions.page/draft-entities-context.tsx index 9b44cd09240..aaf27a4e267 100644 --- a/apps/hash-frontend/src/shared/draft-entities-context.tsx +++ b/apps/hash-frontend/src/pages/actions.page/draft-entities-context.tsx @@ -13,10 +13,11 @@ import { createContext, useContext, useMemo, useState } from "react"; import type { GetEntitySubgraphQuery, GetEntitySubgraphQueryVariables, -} from "../graphql/api-types.gen"; -import { getEntitySubgraphQuery } from "../graphql/queries/knowledge/entity.queries"; -import { useAuthInfo } from "../pages/shared/auth-info-context"; -import { pollInterval } from "./poll-interval"; +} from "../../graphql/api-types.gen"; +import { getEntitySubgraphQuery } from "../../graphql/queries/knowledge/entity.queries"; +import { useDraftEntitiesCount } from "../../shared/draft-entities-count-context"; +import { pollInterval } from "../../shared/poll-interval"; +import { useAuthInfo } from "../shared/auth-info-context"; export type DraftEntitiesContextValue = { draftEntities?: Entity[]; @@ -38,6 +39,10 @@ export const useDraftEntities = () => { return draftEntitiesContext; }; +/** + * Context to provide full information of draft entities, for use in the actions page. + * A separate app-wide context provides simply a count of draft entities. + */ export const DraftEntitiesContextProvider: FunctionComponent< PropsWithChildren > = ({ children }) => { @@ -48,9 +53,11 @@ export const DraftEntitiesContextProvider: FunctionComponent< const { authenticatedUser } = useAuthInfo(); + const { refetch: refetchDraftEntitiesCount } = useDraftEntitiesCount(); + const { data: draftEntitiesData, - refetch, + refetch: refetchFullData, loading, } = useQuery( getEntitySubgraphQuery, @@ -104,10 +111,17 @@ export const DraftEntitiesContextProvider: FunctionComponent< draftEntitiesSubgraph, loading, refetch: async () => { - await refetch(); + await refetchFullData(); + await refetchDraftEntitiesCount(); }, }), - [draftEntities, draftEntitiesSubgraph, loading, refetch], + [ + draftEntities, + draftEntitiesSubgraph, + loading, + refetchFullData, + refetchDraftEntitiesCount, + ], ); return ( diff --git a/apps/hash-frontend/src/pages/actions.page/draft-entities.tsx b/apps/hash-frontend/src/pages/actions.page/draft-entities.tsx index 9e97636ca2f..d89e5e9aa30 100644 --- a/apps/hash-frontend/src/pages/actions.page/draft-entities.tsx +++ b/apps/hash-frontend/src/pages/actions.page/draft-entities.tsx @@ -17,7 +17,6 @@ import { useState, } from "react"; -import { useDraftEntities } from "../../shared/draft-entities-context"; import { Button } from "../../shared/ui"; import type { MinimalActor } from "../../shared/use-actors"; import { useActors } from "../../shared/use-actors"; @@ -30,6 +29,7 @@ import { getDraftEntityTypes, isFilerStateDefaultFilterState, } from "./draft-entities/draft-entities-filters"; +import { useDraftEntities } from "./draft-entities-context"; import { DraftEntity } from "./draft-entity"; const incrementNumberOfEntitiesToDisplay = 20; diff --git a/apps/hash-frontend/src/pages/actions.page/draft-entity.tsx b/apps/hash-frontend/src/pages/actions.page/draft-entity.tsx index 1e96a4cff0d..efd3ae37c10 100644 --- a/apps/hash-frontend/src/pages/actions.page/draft-entity.tsx +++ b/apps/hash-frontend/src/pages/actions.page/draft-entity.tsx @@ -6,11 +6,11 @@ import { Box, Checkbox, Typography } from "@mui/material"; import type { FunctionComponent } from "react"; import { useMemo, useState } from "react"; -import { useDraftEntities } from "../../shared/draft-entities-context"; import { ArrowUpRightRegularIcon } from "../../shared/icons/arrow-up-right-regular-icon"; import { Link } from "../../shared/ui"; import { EntityEditorSlideStack } from "../shared/entity-editor-slide-stack"; import { useEntityHref } from "../shared/use-entity-href"; +import { useDraftEntities } from "./draft-entities-context"; import { DraftEntityActionButtons } from "./draft-entity/draft-entity-action-buttons"; import { DraftEntityProvenance } from "./draft-entity/draft-entity-provenance"; import { DraftEntityType } from "./draft-entity/draft-entity-type"; diff --git a/apps/hash-frontend/src/pages/actions.page/draft-entity/draft-entity-action-buttons.tsx b/apps/hash-frontend/src/pages/actions.page/draft-entity/draft-entity-action-buttons.tsx index 6e44e8c84f1..cefcb42706c 100644 --- a/apps/hash-frontend/src/pages/actions.page/draft-entity/draft-entity-action-buttons.tsx +++ b/apps/hash-frontend/src/pages/actions.page/draft-entity/draft-entity-action-buttons.tsx @@ -7,16 +7,20 @@ import type { FunctionComponent } from "react"; import { CheckRegularIcon } from "../../../shared/icons/check-regular-icon"; import { AcceptDraftEntityButton } from "../../shared/accept-draft-entity-button"; import { DiscardDraftEntityButton } from "../../shared/discard-draft-entity-button"; +import { useDraftEntities } from "../draft-entities-context"; export const DraftEntityActionButtons: FunctionComponent<{ entity: Entity; subgraph: Subgraph; }> = ({ entity, subgraph }) => { + const { refetch } = useDraftEntities(); + return ( } @@ -40,7 +44,7 @@ export const DraftEntityActionButtons: FunctionComponent<{ size="xs" variant="primary" startIcon={} - onAcceptedEntity={null} + onAcceptedEntity={refetch} > Accept diff --git a/apps/hash-frontend/src/pages/notifications.page.tsx b/apps/hash-frontend/src/pages/notifications.page.tsx index dc4fcbdbae5..918f52bcf99 100644 --- a/apps/hash-frontend/src/pages/notifications.page.tsx +++ b/apps/hash-frontend/src/pages/notifications.page.tsx @@ -10,7 +10,7 @@ import { NextSeo } from "next-seo"; import type { NextPageWithLayout } from "../shared/layout"; import { getLayoutWithSidebar } from "../shared/layout"; import { NotificationsTable } from "./notifications.page/notifications-table"; -import { NotificationsWithLinksContextProvider } from "./shared/notifications-with-links-context"; +import { NotificationsWithLinksContextProvider } from "./notifications.page/notifications-with-links-context"; import { TopContextBar } from "./shared/top-context-bar"; const NotificationsPage: NextPageWithLayout = () => { diff --git a/apps/hash-frontend/src/pages/notifications.page/notifications-table.tsx b/apps/hash-frontend/src/pages/notifications.page/notifications-table.tsx index 0341c54f8d9..074805c3de1 100644 --- a/apps/hash-frontend/src/pages/notifications.page/notifications-table.tsx +++ b/apps/hash-frontend/src/pages/notifications.page/notifications-table.tsx @@ -35,8 +35,8 @@ import type { GraphChangeNotification, Notification, PageRelatedNotification, -} from "../shared/notifications-with-links-context"; -import { useNotificationsWithLinks } from "../shared/notifications-with-links-context"; +} from "./notifications-with-links-context"; +import { useNotificationsWithLinks } from "./notifications-with-links-context"; const Table = styled(MuiTable)(({ theme }) => ({ borderCollapse: "separate", @@ -166,12 +166,14 @@ const NotificationRow: FunctionComponent<{ notification: Notification }> = ({ notification, }) => { const { markNotificationAsRead } = useNotificationCount(); + const { refetch } = useNotificationsWithLinks(); const handleNotificationClick = useCallback(async () => { await markNotificationAsRead({ notificationEntityId: notification.entity.entityId, }); - }, [markNotificationAsRead, notification]); + refetch(); + }, [markNotificationAsRead, notification, refetch]); const ownedById = useMemo( () => diff --git a/apps/hash-frontend/src/pages/shared/notifications-with-links-context.tsx b/apps/hash-frontend/src/pages/notifications.page/notifications-with-links-context.tsx similarity index 98% rename from apps/hash-frontend/src/pages/shared/notifications-with-links-context.tsx rename to apps/hash-frontend/src/pages/notifications.page/notifications-with-links-context.tsx index 6391e8a80f6..c8bdc131cad 100644 --- a/apps/hash-frontend/src/pages/shared/notifications-with-links-context.tsx +++ b/apps/hash-frontend/src/pages/notifications.page/notifications-with-links-context.tsx @@ -48,7 +48,7 @@ import { getEntitySubgraphQuery } from "../../graphql/queries/knowledge/entity.q import type { MinimalUser } from "../../lib/user-and-org"; import { constructMinimalUser } from "../../lib/user-and-org"; import { pollInterval } from "../../shared/poll-interval"; -import { useAuthInfo } from "./auth-info-context"; +import { useAuthInfo } from "../shared/auth-info-context"; export type PageMentionNotification = { kind: "page-mention"; @@ -97,6 +97,7 @@ export type Notification = PageRelatedNotification | GraphChangeNotification; type NotificationsWithLinksContextValue = { notifications?: Notification[]; + refetch: () => void; }; export const NotificationsWithLinksContext = @@ -124,7 +125,7 @@ export const useNotificationsWithLinksContextValue = (): NotificationsWithLinksContextValue => { const { authenticatedUser } = useAuthInfo(); - const { data: notificationsWithOutgoingLinksData } = useQuery< + const { data: notificationsWithOutgoingLinksData, refetch } = useQuery< GetEntitySubgraphQuery, GetEntitySubgraphQueryVariables >(getEntitySubgraphQuery, { @@ -498,9 +499,13 @@ export const useNotificationsWithLinksContextValue = return derivedNotifications; }, [notificationsSubgraph]); - return { notifications }; + return { notifications, refetch }; }; +/** + * Context to provide full information on notifications, for use on the notifications page. + * A separate app-wide context provides only a count of notifications. + */ export const NotificationsWithLinksContextProvider: FunctionComponent< PropsWithChildren > = ({ children }) => { diff --git a/apps/hash-frontend/src/pages/shared/accept-draft-entity-button.tsx b/apps/hash-frontend/src/pages/shared/accept-draft-entity-button.tsx index 8b9186a827c..daa1912a07b 100644 --- a/apps/hash-frontend/src/pages/shared/accept-draft-entity-button.tsx +++ b/apps/hash-frontend/src/pages/shared/accept-draft-entity-button.tsx @@ -15,13 +15,12 @@ import type { UpdateEntityMutationVariables, } from "../../graphql/api-types.gen"; import { updateEntityMutation } from "../../graphql/queries/knowledge/entity.queries"; -import { useDraftEntities } from "../../shared/draft-entities-context"; +import { useDraftEntitiesCount } from "../../shared/draft-entities-count-context"; import { CheckRegularIcon } from "../../shared/icons/check-regular-icon"; import { useNotificationCount } from "../../shared/notification-count-context"; import type { ButtonProps } from "../../shared/ui"; import { Button } from "../../shared/ui"; import { LinkLabelWithSourceAndDestination } from "./link-label-with-source-and-destination"; -import { useNotificationsWithLinks } from "./notifications-with-links-context"; const LeftOrRightEntityEndAdornment: FunctionComponent<{ isDraft: boolean; @@ -136,37 +135,15 @@ export const AcceptDraftEntityButton: FunctionComponent< UpdateEntityMutationVariables >(updateEntityMutation); - const { refetch: refetchDraftEntities } = useDraftEntities(); + const { refetch: refetchDraftEntitiesCount } = useDraftEntitiesCount(); - const { markNotificationAsRead } = useNotificationCount(); - const { notifications } = useNotificationsWithLinks(); - - /** - * Notifications are no longer created for draft entities, but they will exist for existing draft entities. - * Can be removed in the future – change to stop notifs for draft entities made in March 2024. - */ - const markRelatedGraphChangeNotificationsAsRead = useCallback( - async (params: { draftEntity: Entity }) => { - const relatedGraphChangeNotifications = - notifications?.filter( - ({ kind, occurredInEntity }) => - kind === "graph-change" && - occurredInEntity.metadata.recordId.entityId === - params.draftEntity.metadata.recordId.entityId, - ) ?? []; - - await Promise.all( - relatedGraphChangeNotifications.map((notification) => - markNotificationAsRead({ notificationEntity: notification.entity }), - ), - ); - }, - [notifications, markNotificationAsRead], - ); + const { markNotificationsAsReadForEntity } = useNotificationCount(); const acceptDraftEntity = useCallback( async (params: { draftEntity: Entity }) => { - await markRelatedGraphChangeNotificationsAsRead(params); + await markNotificationsAsReadForEntity({ + targetEntityId: params.draftEntity.entityId, + }); const response = await updateEntity({ variables: { @@ -178,7 +155,7 @@ export const AcceptDraftEntityButton: FunctionComponent< }, }); - await refetchDraftEntities(); + await refetchDraftEntitiesCount(); if (!response.data) { throw new Error("An error occurred accepting the draft entity."); @@ -186,11 +163,7 @@ export const AcceptDraftEntityButton: FunctionComponent< return new Entity(response.data.updateEntity); }, - [ - updateEntity, - refetchDraftEntities, - markRelatedGraphChangeNotificationsAsRead, - ], + [markNotificationsAsReadForEntity, updateEntity, refetchDraftEntitiesCount], ); const handleAccept = useCallback(async () => { diff --git a/apps/hash-frontend/src/pages/shared/discard-draft-entity-button.tsx b/apps/hash-frontend/src/pages/shared/discard-draft-entity-button.tsx index b971f2ce0ef..d7dd51748bb 100644 --- a/apps/hash-frontend/src/pages/shared/discard-draft-entity-button.tsx +++ b/apps/hash-frontend/src/pages/shared/discard-draft-entity-button.tsx @@ -16,11 +16,9 @@ import type { ArchiveEntityMutationVariables, } from "../../graphql/api-types.gen"; import { archiveEntityMutation } from "../../graphql/queries/knowledge/entity.queries"; -import { useDraftEntities } from "../../shared/draft-entities-context"; import { useNotificationCount } from "../../shared/notification-count-context"; import type { ButtonProps } from "../../shared/ui"; import { Button } from "../../shared/ui"; -import { useNotificationsWithLinks } from "./notifications-with-links-context"; export const DiscardDraftEntityButton: FunctionComponent< { @@ -34,34 +32,7 @@ export const DiscardDraftEntityButton: FunctionComponent< onDiscardedEntity, ...buttonProps }) => { - const { refetch: refetchDraftEntities } = useDraftEntities(); - - const { archiveNotification } = useNotificationCount(); - - const { notifications } = useNotificationsWithLinks(); - - const archiveRelatedNotifications = useCallback( - async (params: { draftEntity: Entity }) => { - const relatedNotifications = notifications?.filter( - (notification) => - notification.occurredInEntity.metadata.recordId.entityId === - params.draftEntity.metadata.recordId.entityId, - ); - - if (!relatedNotifications) { - return; - } - - await Promise.all( - relatedNotifications.map((notification) => { - return archiveNotification({ - notificationEntity: notification.entity, - }); - }), - ); - }, - [notifications, archiveNotification], - ); + const { archiveNotificationsForEntity } = useNotificationCount(); const [archiveEntity] = useMutation< ArchiveEntityMutation, @@ -70,15 +41,16 @@ export const DiscardDraftEntityButton: FunctionComponent< const discardDraftEntity = useCallback( async (params: { draftEntity: Entity }) => { - await archiveRelatedNotifications(params); + await archiveNotificationsForEntity({ + targetEntityId: params.draftEntity.entityId, + }); await archiveEntity({ variables: { entityId: params.draftEntity.metadata.recordId.entityId, }, }); - await refetchDraftEntities(); }, - [archiveEntity, archiveRelatedNotifications, refetchDraftEntities], + [archiveEntity, archiveNotificationsForEntity], ); const [ diff --git a/apps/hash-frontend/src/shared/draft-entities-count-context.tsx b/apps/hash-frontend/src/shared/draft-entities-count-context.tsx new file mode 100644 index 00000000000..04c955cdb62 --- /dev/null +++ b/apps/hash-frontend/src/shared/draft-entities-count-context.tsx @@ -0,0 +1,92 @@ +import { useQuery } from "@apollo/client"; +import { + currentTimeInstantTemporalAxes, + zeroedGraphResolveDepths, +} from "@local/hash-isomorphic-utils/graph-queries"; +import type { FunctionComponent, PropsWithChildren } from "react"; +import { createContext, useContext, useMemo } from "react"; + +import type { + GetEntitySubgraphQuery, + GetEntitySubgraphQueryVariables, +} from "../graphql/api-types.gen"; +import { getEntitySubgraphQuery } from "../graphql/queries/knowledge/entity.queries"; +import { useAuthInfo } from "../pages/shared/auth-info-context"; +import { pollInterval } from "./poll-interval"; + +export type DraftEntitiesCountContextValue = { + count?: number; + loading: boolean; + refetch: () => Promise; +}; + +export const DraftEntitiesCountContext = + createContext(null); + +export const useDraftEntitiesCount = () => { + const draftEntitiesContext = useContext(DraftEntitiesCountContext); + + if (!draftEntitiesContext) { + throw new Error("DraftEntitiesCountContext missing"); + } + + return draftEntitiesContext; +}; + +export const DraftEntitiesCountContextProvider: FunctionComponent< + PropsWithChildren +> = ({ children }) => { + const { authenticatedUser } = useAuthInfo(); + + const { + data: draftEntitiesData, + refetch, + loading, + } = useQuery( + getEntitySubgraphQuery, + { + variables: { + request: { + filter: { + all: [ + { + // @ts-expect-error -- Support null in Path parameter in structural queries in Node + // @see https://linear.app/hash/issue/H-1207 + notEqual: [{ path: ["draftId"] }, null], + }, + { + equal: [{ path: ["archived"] }, { parameter: false }], + }, + ], + }, + temporalAxes: currentTimeInstantTemporalAxes, + graphResolveDepths: zeroedGraphResolveDepths, + includeCount: true, + includeDrafts: true, + limit: 0, + }, + includePermissions: false, + }, + pollInterval, + fetchPolicy: "network-only", + skip: !authenticatedUser, + }, + ); + + const value = useMemo( + () => ({ + count: draftEntitiesData?.getEntitySubgraph.count ?? undefined, + loading, + refetch: async () => { + await refetch(); + }, + }), + [draftEntitiesData, loading, refetch], + ); + + return ( + + {children} + + ); +}; diff --git a/apps/hash-frontend/src/shared/layout/layout-with-header/page-header.tsx b/apps/hash-frontend/src/shared/layout/layout-with-header/page-header.tsx index c549567853d..3e2fe88700d 100644 --- a/apps/hash-frontend/src/shared/layout/layout-with-header/page-header.tsx +++ b/apps/hash-frontend/src/shared/layout/layout-with-header/page-header.tsx @@ -4,7 +4,7 @@ import type { FunctionComponent, ReactNode } from "react"; import { useHashInstance } from "../../../components/hooks/use-hash-instance"; import { useLogoutFlow } from "../../../components/hooks/use-logout-flow"; import { useAuthInfo } from "../../../pages/shared/auth-info-context"; -import { useDraftEntities } from "../../draft-entities-context"; +import { useDraftEntitiesCount } from "../../draft-entities-count-context"; import { CheckRegularIcon } from "../../icons/check-regular-icon"; import { HashLockup } from "../../icons/hash-lockup"; import { Button, Link } from "../../ui"; @@ -37,7 +37,7 @@ export const PageHeader: FunctionComponent = () => { const { authenticatedUser } = useAuthInfo(); const { hashInstance } = useHashInstance(); const { logout } = useLogoutFlow(); - const { draftEntities } = useDraftEntities(); + const { count: draftEntitiesCount } = useDraftEntitiesCount(); return ( { sx={{ color: theme.palette.blue[70] }} /> } - count={draftEntities?.length} + count={draftEntitiesCount} />
diff --git a/apps/hash-frontend/src/shared/layout/layout-with-sidebar/sidebar.tsx b/apps/hash-frontend/src/shared/layout/layout-with-sidebar/sidebar.tsx index 083c79653c8..2375e466359 100644 --- a/apps/hash-frontend/src/shared/layout/layout-with-sidebar/sidebar.tsx +++ b/apps/hash-frontend/src/shared/layout/layout-with-sidebar/sidebar.tsx @@ -17,7 +17,7 @@ import { import { useHashInstance } from "../../../components/hooks/use-hash-instance"; import { useEnabledFeatureFlags } from "../../../pages/shared/use-enabled-feature-flags"; import { useActiveWorkspace } from "../../../pages/shared/workspace-context"; -import { useDraftEntities } from "../../draft-entities-context"; +import { useDraftEntitiesCount } from "../../draft-entities-count-context"; import { ArrowRightToLineIcon } from "../../icons"; import { BoltLightIcon } from "../../icons/bolt-light-icon"; import { InboxIcon } from "../../icons/inbox-icon"; @@ -74,7 +74,7 @@ export const PageSidebar: FunctionComponent = () => { const { numberOfUnreadNotifications } = useNotificationCount(); - const { draftEntities } = useDraftEntities(); + const { count: draftEntitiesCount } = useDraftEntitiesCount(); const workersSection = useMemo( () => @@ -129,7 +129,7 @@ export const PageSidebar: FunctionComponent = () => { }); } - const numberOfPendingActions = draftEntities?.length ?? 0; + const numberOfPendingActions = draftEntitiesCount ?? 0; return [ { @@ -171,7 +171,7 @@ export const PageSidebar: FunctionComponent = () => { : []), ]; }, [ - draftEntities, + draftEntitiesCount, numberOfUnreadNotifications, enabledFeatureFlags, preferences, diff --git a/apps/hash-frontend/src/shared/notification-count-context.tsx b/apps/hash-frontend/src/shared/notification-count-context.tsx index cdbda7002f9..abf17021242 100644 --- a/apps/hash-frontend/src/shared/notification-count-context.tsx +++ b/apps/hash-frontend/src/shared/notification-count-context.tsx @@ -1,9 +1,10 @@ -import { useMutation, useQuery } from "@apollo/client"; +import { useLazyQuery, useMutation, useQuery } from "@apollo/client"; import type { EntityId } from "@local/hash-graph-types/entity"; import type { BaseUrl } from "@local/hash-graph-types/ontology"; import { currentTimeInstantTemporalAxes, generateVersionedUrlMatchingFilter, + mapGqlSubgraphFieldsFragmentToSubgraph, pageOrNotificationNotArchivedFilter, zeroedGraphResolveDepths, } from "@local/hash-isomorphic-utils/graph-queries"; @@ -13,6 +14,9 @@ import type { Notification, ReadAtPropertyValueWithMetadata, } from "@local/hash-isomorphic-utils/system-types/commentnotification"; +import type { EntityRootType } from "@local/hash-subgraph"; +import { extractEntityUuidFromEntityId } from "@local/hash-subgraph"; +import { getRoots } from "@local/hash-subgraph/stdlib"; import type { FunctionComponent, PropsWithChildren } from "react"; import { createContext, useCallback, useContext, useMemo } from "react"; @@ -35,18 +39,20 @@ import { pollInterval } from "./poll-interval"; export type NotificationCountContextValues = { numberOfUnreadNotifications?: number; loading: boolean; - refetch: () => Promise; markNotificationAsRead: (params: { notificationEntityId: EntityId; }) => Promise; - markNotificationsAsRead: (params: { - notificationEntityIds: EntityId[]; + /** + * Mark notifications as read if they link to a specific entity + */ + markNotificationsAsReadForEntity: (params: { + targetEntityId: EntityId; }) => Promise; - archiveNotification: (params: { - notificationEntityId: EntityId; - }) => Promise; - archiveNotifications: (params: { - notificationEntityIds: EntityId[]; + /** + * Archive notifications if they link to a specific entity + */ + archiveNotificationsForEntity: (params: { + targetEntityId: EntityId; }) => Promise; }; @@ -63,6 +69,15 @@ export const useNotificationCount = () => { return notificationCountContext; }; +/** + * This is app-wide context to provide: + * 1. The count of notifications + * 2. The ability to mark notifications as + * - read: keeps them visible on the notifications page + * - archived: they will no longer be visible, unless specifically sought out + * + * The notifications page has separate context which requests all notification data. + */ export const NotificationCountContextProvider: FunctionComponent< PropsWithChildren > = ({ children }) => { @@ -106,14 +121,76 @@ export const NotificationCountContextProvider: FunctionComponent< }, ); - const refetch = useCallback(async () => { - await refetchNotificationCount(); - }, [refetchNotificationCount]); + const [getEntitySubgraph] = useLazyQuery< + GetEntitySubgraphQuery, + GetEntitySubgraphQueryVariables + >(getEntitySubgraphQuery, { + fetchPolicy: "network-only", + }); const [updateEntity] = useMutation< UpdateEntityMutation, UpdateEntityMutationVariables - >(updateEntityMutation); + >(updateEntityMutation, { + onCompleted: () => refetchNotificationCount(), + }); + + const [updateEntities] = useMutation< + UpdateEntitiesMutation, + UpdateEntitiesMutationVariables + >(updateEntitiesMutation, { + onCompleted: () => refetchNotificationCount(), + }); + + const getNotificationsLinkingToEntity = useCallback( + async ({ targetEntityId }: { targetEntityId: EntityId }) => { + const relatedNotificationData = await getEntitySubgraph({ + variables: { + includePermissions: false, + request: { + filter: { + all: [ + { + equal: [ + { path: ["ownedById"] }, + { parameter: authenticatedUser?.accountId }, + ], + }, + generateVersionedUrlMatchingFilter( + systemEntityTypes.notification.entityTypeId, + { ignoreParents: false }, + ), + { + equal: [ + { path: ["outgoingLinks", "rightEntity", "uuid"] }, + { + parameter: extractEntityUuidFromEntityId(targetEntityId), + }, + ], + }, + ], + }, + graphResolveDepths: zeroedGraphResolveDepths, + temporalAxes: currentTimeInstantTemporalAxes, + includeDrafts: false, + }, + }, + }); + + if (!relatedNotificationData.data?.getEntitySubgraph.subgraph) { + return []; + } + + const subgraph = mapGqlSubgraphFieldsFragmentToSubgraph< + EntityRootType + >(relatedNotificationData.data.getEntitySubgraph.subgraph); + + const notifications = getRoots(subgraph); + + return notifications; + }, + [authenticatedUser?.accountId, getEntitySubgraph], + ); const markNotificationAsRead = useCallback< NotificationCountContextValues["markNotificationAsRead"] @@ -145,28 +222,27 @@ export const NotificationCountContextProvider: FunctionComponent< }, }, }); - - await refetch(); }, - [updateEntity, refetch], + [updateEntity], ); - const [updateEntities] = useMutation< - UpdateEntitiesMutation, - UpdateEntitiesMutationVariables - >(updateEntitiesMutation); - - const markNotificationsAsRead = useCallback< - NotificationCountContextValues["markNotificationsAsRead"] + const markNotificationsAsReadForEntity = useCallback< + NotificationCountContextValues["markNotificationsAsReadForEntity"] >( async (params) => { const now = new Date(); - await updateEntities({ - variables: { - entityUpdates: params.notificationEntityIds.map( - (notificationEntityId) => ({ - entityId: notificationEntityId, + const { targetEntityId } = params; + + const notifications = await getNotificationsLinkingToEntity({ + targetEntityId, + }); + + if (notifications.length) { + await updateEntities({ + variables: { + entityUpdates: notifications.map((notification) => ({ + entityId: notification.metadata.recordId.entityId, propertyPatches: [ { op: "add", @@ -182,59 +258,29 @@ export const NotificationCountContextProvider: FunctionComponent< } satisfies ReadAtPropertyValueWithMetadata, }, ], - }), - ), - }, - }); - - await refetch(); + })), + }, + }); + } }, - [updateEntities, refetch], + [getNotificationsLinkingToEntity, updateEntities], ); - const archiveNotification = useCallback< - NotificationCountContextValues["archiveNotification"] + const archiveNotificationsForEntity = useCallback< + NotificationCountContextValues["archiveNotificationsForEntity"] >( async (params) => { - const { notificationEntityId } = params; + const { targetEntityId } = params; - await updateEntity({ - variables: { - entityUpdate: { - entityId: notificationEntityId, - propertyPatches: [ - { - op: "add", - path: [ - "https://hash.ai/@hash/types/property-type/archived/" satisfies keyof Notification["properties"] as BaseUrl, - ], - property: { - value: true, - metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/boolean/v/1", - }, - } satisfies ArchivedPropertyValueWithMetadata, - }, - ], - }, - }, + const notifications = await getNotificationsLinkingToEntity({ + targetEntityId, }); - await refetch(); - }, - [updateEntity, refetch], - ); - - const archiveNotifications = useCallback< - NotificationCountContextValues["archiveNotifications"] - >( - async (params) => { - await updateEntities({ - variables: { - entityUpdates: params.notificationEntityIds.map( - (notificationEntityId) => ({ - entityId: notificationEntityId, + if (notifications.length) { + await updateEntities({ + variables: { + entityUpdates: notifications.map((notification) => ({ + entityId: notification.metadata.recordId.entityId, propertyPatches: [ { op: "add", @@ -250,34 +296,29 @@ export const NotificationCountContextProvider: FunctionComponent< } satisfies ArchivedPropertyValueWithMetadata, }, ], - }), - ), - }, - }); - await refetch(); + })), + }, + }); + } }, - [updateEntities, refetch], + [getNotificationsLinkingToEntity, updateEntities], ); const value = useMemo( () => ({ - archiveNotification, - archiveNotifications, + archiveNotificationsForEntity, loading: loadingNotificationCount, markNotificationAsRead, - markNotificationsAsRead, + markNotificationsAsReadForEntity, numberOfUnreadNotifications: - notificationCountData?.getEntitySubgraph?.count, - refetch, + notificationCountData?.getEntitySubgraph.count ?? undefined, }), [ - archiveNotification, - archiveNotifications, + archiveNotificationsForEntity, loadingNotificationCount, markNotificationAsRead, - markNotificationsAsRead, + markNotificationsAsReadForEntity, notificationCountData, - refetch, ], ); diff --git a/libs/@local/hash-isomorphic-utils/src/graphql/type-defs/knowledge/entity.typedef.ts b/libs/@local/hash-isomorphic-utils/src/graphql/type-defs/knowledge/entity.typedef.ts index edfaf5af0fe..183f0df636d 100644 --- a/libs/@local/hash-isomorphic-utils/src/graphql/type-defs/knowledge/entity.typedef.ts +++ b/libs/@local/hash-isomorphic-utils/src/graphql/type-defs/knowledge/entity.typedef.ts @@ -24,7 +24,7 @@ export const entityTypedef = gql` } type GetEntitySubgraphResponse { - count?: Int + count: Int closedMultiEntityTypes: ClosedMultiEntityTypesRootMap definitions: ClosedMultiEntityTypesDefinitions userPermissionsOnEntities: UserPermissionsOnEntities! From dfd8c3bf9b5107710252f3fd038c691464c87955 Mon Sep 17 00:00:00 2001 From: Ciaran Morinan Date: Mon, 9 Dec 2024 16:30:20 +0000 Subject: [PATCH 4/5] remove console.log, revert tsconfig change --- apps/hash-api/src/graph/knowledge/primitive/entity.ts | 2 -- libs/@local/harpc/client/typescript/tsconfig.json | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/hash-api/src/graph/knowledge/primitive/entity.ts b/apps/hash-api/src/graph/knowledge/primitive/entity.ts index 37eb3d5ca50..7942a671bf8 100644 --- a/apps/hash-api/src/graph/knowledge/primitive/entity.ts +++ b/apps/hash-api/src/graph/knowledge/primitive/entity.ts @@ -237,8 +237,6 @@ export const getEntitySubgraphResponse: ImpureGraphFunction< } } - console.log({ rest, params }); - return { closedMultiEntityTypes, definitions: definitions diff --git a/libs/@local/harpc/client/typescript/tsconfig.json b/libs/@local/harpc/client/typescript/tsconfig.json index d388501d083..ab21763bae7 100644 --- a/libs/@local/harpc/client/typescript/tsconfig.json +++ b/libs/@local/harpc/client/typescript/tsconfig.json @@ -1,7 +1,7 @@ { "extends": "@local/tsconfig/legacy-base-tsconfig-to-refactor.json", "compilerOptions": { - "lib": ["ES2023", "ESNext"], + "lib": ["dom", "dom.iterable", "ES2023", "ESNext"], "module": "NodeNext", "moduleResolution": "NodeNext", "types": ["vitest/importMeta"] From 1a3fa714b60a55bd46b0e01ed0f245405f8d0f45 Mon Sep 17 00:00:00 2001 From: Ciaran Morinan Date: Wed, 11 Dec 2024 11:32:15 +0000 Subject: [PATCH 5/5] bug / styling fixes --- apps/hash-frontend/src/pages/actions.page.tsx | 2 +- .../actions.page/draft-entity/draft-entity-chip.tsx | 4 ++-- .../actions.page/draft-entity/draft-entity-type.tsx | 10 +++++++++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/hash-frontend/src/pages/actions.page.tsx b/apps/hash-frontend/src/pages/actions.page.tsx index 1fb7ae99929..0f00c38cdec 100644 --- a/apps/hash-frontend/src/pages/actions.page.tsx +++ b/apps/hash-frontend/src/pages/actions.page.tsx @@ -220,4 +220,4 @@ ActionsPageOuter.getLayout = (page) => fullWidth: true, }); -export default ActionsPage; +export default ActionsPageOuter; diff --git a/apps/hash-frontend/src/pages/actions.page/draft-entity/draft-entity-chip.tsx b/apps/hash-frontend/src/pages/actions.page/draft-entity/draft-entity-chip.tsx index 2a9708d7090..cacd334671f 100644 --- a/apps/hash-frontend/src/pages/actions.page/draft-entity/draft-entity-chip.tsx +++ b/apps/hash-frontend/src/pages/actions.page/draft-entity/draft-entity-chip.tsx @@ -6,7 +6,6 @@ export const DraftEntityChip = styled(Chip)(({ theme, clickable }) => ({ background: theme.palette.common.white, borderColor: theme.palette.gray[30], fontWeight: 500, - fontSize: 12, textTransform: "none", ...(clickable ? { @@ -20,6 +19,7 @@ export const DraftEntityChip = styled(Chip)(({ theme, clickable }) => ({ color: theme.palette.gray[50], }, [`& .${chipClasses.label}`]: { - padding: theme.spacing(0.5, 1.25), + padding: theme.spacing(0.3, 1.25), + fontSize: 12, }, })); diff --git a/apps/hash-frontend/src/pages/actions.page/draft-entity/draft-entity-type.tsx b/apps/hash-frontend/src/pages/actions.page/draft-entity/draft-entity-type.tsx index 4a9f01127f3..127cae8dd9c 100644 --- a/apps/hash-frontend/src/pages/actions.page/draft-entity/draft-entity-type.tsx +++ b/apps/hash-frontend/src/pages/actions.page/draft-entity/draft-entity-type.tsx @@ -76,7 +76,14 @@ export const DraftEntityType: FunctionComponent<{ alignItems: "center", }} > - + palette.gray[50]} @@ -90,6 +97,7 @@ export const DraftEntityType: FunctionComponent<{ (allOf) => allOf.$ref === linkEntityTypeUrl, ) } + sx={{ mr: 0.5 }} /> {entityType.schema.title}