Repository: toeverything/AFFiNE
File: packages/frontend/core/src/modules/peek-view/view/doc-preview/doc-peek-view.tsx (TypeScript)

Code before:
        // chat panel open is already handled in <DetailPageImpl />
      }
    };
    disposables.push(
      AIProvider.slots.requestOpenWithChat.subscribe(openHandler)
    );
    disposables.push(
      AIProvider.slots.requestSendWithChat.subscribe(openHandler)
    );
    return () => disposables.forEach(d => d.unsubscribe());
  }, [doc, peekView, workbench, workspace.id]);

  const openOutlinePanel = useCallback(() => {
    workbench.openDoc(doc.id);
    workbench.openSidebar();
    workbench.activeView$.value.activeSidebarTab('outline');
    peekView.close();
  }, [doc, peekView, workbench]);

  const canEdit = useLiveData(guardService.can$('Doc_Update', doc.id));
  const canAccess = useLiveData(guardService.can$('Doc_Read', doc.id));

  const readonly = !canEdit || isInTrash;

  if (!canAccess) {
    return <PageNotFound noPermission />;
  }

  return (
    <AffineErrorBoundary>
      <Scrollable.Root>
        <Scrollable.Viewport
          className={clsx('affine-page-viewport', styles.affineDocViewport)}
        >
          <Suspense fallback={<PageDetailSkeleton />}>
            <BlockSuiteEditor
              className={styles.editor}
              mode={mode}
              page={doc.blockSuiteDoc}
              readonly={readonly}
              onEditorReady={handleOnEditorReady}
              defaultOpenProperty={defaultOpenProperty}
            />
          </Suspense>
        </Scrollable.Viewport>
        <Scrollable.Scrollbar />
      </Scrollable.Root>
      {!BUILD_CONFIG.isMobileEdition && !BUILD_CONFIG.isMobileWeb ? (
        <EditorOutlineViewer
          editor={editorElement?.host ?? null}
          show={mode === 'page'}

Review comment (security):
<!--__GRAPHITE_HTML_TAG_START__--><p class='graphite__hidden'><i>[Re: line +229]</i></p><!--__GRAPHITE_HTML_TAG_END__-->
check permission here
<!--__GRAPHITE_HTML_TAG_START__--><p class='graphite__hidden'>See this comment inline on <a href="https://app.graphite.dev/github/pr/toeverything/AFFiNE/10927?utm_source=unchanged-line-comment">Graphite</a>.</p><!--__GRAPHITE_HTML_TAG_END__-->

Code after:
        // chat panel open is already handled in <DetailPageImpl />
      }
    };
    disposables.push(
      AIProvider.slots.requestOpenWithChat.subscribe(openHandler)
    );
    disposables.push(
      AIProvider.slots.requestSendWithChat.subscribe(openHandler)
    );
    return () => disposables.forEach(d => d.unsubscribe());
  }, [doc, peekView, workbench, workspace.id]);

  const openOutlinePanel = useCallback(() => {
    workbench.openDoc(doc.id);
    workbench.openSidebar();
    workbench.activeView$.value.activeSidebarTab('outline');
    peekView.close();
  }, [doc, peekView, workbench]);

  const canEdit = useLiveData(guardService.can$('Doc_Update', doc.id));

  const readonly = !canEdit || isInTrash;

  return (
    <AffineErrorBoundary>
      <Scrollable.Root>
        <Scrollable.Viewport
          className={clsx('affine-page-viewport', styles.affineDocViewport)}
        >
          <Suspense fallback={<PageDetailSkeleton />}>
            <BlockSuiteEditor
              className={styles.editor}
              mode={mode}
              page={doc.blockSuiteDoc}
              readonly={readonly}
              onEditorReady={handleOnEditorReady}
              defaultOpenProperty={defaultOpenProperty}
            />
          </Suspense>
        </Scrollable.Viewport>
        <Scrollable.Scrollbar />
      </Scrollable.Root>
      {!BUILD_CONFIG.isMobileEdition && !BUILD_CONFIG.isMobileWeb ? (
        <EditorOutlineViewer
          editor={editorElement?.host ?? null}
          show={mode === 'page'}
          openOutlinePanel={openOutlinePanel}
        />
      ) : null}
    </AffineErrorBoundary>
  );