Skip to content

Fix: some miscellaneous & tiny bugs #193

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 4, 2023
Merged

Conversation

li-xin-yi
Copy link
Collaborator

@li-xin-yi li-xin-yi commented Jan 4, 2023

  1. disable richNode editing & codeNode copying for guest users
  2. fix the bug: a guest user sees the pasted pod increases on its size endlessly.
  3. fix the bug: a pasted pod's position is not up-to-date when adding.
  4. extend node types when observing adding nodes in nodesMap
  5. refactor the code about the privilege management in front-end, hide the detailed role info to simplify the code

More details can be found in comments.

Suggestions:

  • Many functions in canvas.tsx can be moved into lib/utils.tsx like dbtype2nodetype to make canvas.tsx more clear.
  • For a guest user, the runtime should not be loaded from the beginning, it wastes resource.

Other works on the way:

@li-xin-yi
Copy link
Collaborator Author

li-xin-yi commented Jan 4, 2023

Update: Fix the selection issue for guest users. Now they can also multi-select pods like other users. (pre-requirement for multi-pod copy by guests)

Comment on lines 165 to 133
const role = useStore(store, (state) => state.role);
const isGuest = useStore(store, (state) => state.isGuest());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two reasons pull me back from this change.

  1. Here, isGuest is the result of calling a Zustand action function state.isGuest(). I have never seen such usage before, and I doubt that it might be incompatible with zustand's ability to "Renders components only on changes". I.e., isGuest might not be able to trigger a re-render if store.role changes. Thus, I don't think we want to use this pattern.

  2. Also, it adds two more actions (isGuest and isOwner) in Zustand store (which are effectively global functions). We want to keep Zustand store lean, only those states and state mutators.

For reference, below is Zustand store's typical usage pattern: state and state mutators:

const useFishStore = create((set) => ({
  salmon: 1,
  tuna: 2,
  deleteEverything: () => set({}, true), // clears the entire store, actions included
  deleteTuna: () => set((state) => omit(state, ['tuna']), true),
}))

Back to our problem, we could define isGuest and isOwner as functions, and use isGuest(role) here, e.g.,

// store/index.tsx or some utils.tsx
export const isGuest = (role) => role === RoleType.GUEST

// Code.tsx
import {isGuest} from ...
function Component() {
  const role = useStore(..., state.role)
  ...
  return <Box>{isGuest(role) && <Box>I'm guest</Box>}</Box>
}

Copy link
Collaborator

@lihebi lihebi Jan 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I would remove enum RoleType and just use this (which is still type-safe):

// repoStateSlice.tsx
export interface RepoStateSlice {
  ...
  role: "owner" | "guest" | "collaborator";
  ...
}

// Code.tsx
function Component() {
  const role = useStore(..., state.role)
  ...
  return <Box>{role === "guest" && <Box>I'm guest</Box>}</Box>
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sure it must re-render when role changes because I set all the initial role as GUEST in the beginning, and it re-enables editing when the repo loads successfully for non-guest users. It's a function call evaluated in real-time, not a function declaration.

I just feel it may be problematic to expose the explicit role info to other components. We just need to know it abstractly. I have two ideas to do that:

  1. Instead of setting role in store, split it to two fields isGuest: boolean and isOwner: boolean.
  2. Similar to your solution, but hide the actual role like:
// store/index.tsx or some utils.tsx
export const checkGuest = (role) => role === RoleType.GUEST

// Code.tsx
import {isGuest} from ...
function Component() {
  const isGuest = useStore(..., checkGuest(state.role))
  ...
  return <Box>{isGuest && <Box>I'm guest</Box>}</Box>
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Instead of setting role in store, split it to two fields isGuest: boolean and isOwner: boolean.

This will leave space for bugs, e.g. we can set both isGuest and isOwner to true.

  1. Similar to your solution, but hide the actual role like:

Sounds good, let's use this.

@li-xin-yi
Copy link
Collaborator Author

li-xin-yi commented Jan 4, 2023

Update: I finally removed the enum type and change it to role: "OWNER" | "COLLABORATOR" | "GUEST" (uppercase due to constant declaration).

There are still three known issues in this PR:

  1. Auto-unselection on focusing codeNode/richNode doesn't work when the user is a guest. It seems to inactivate drag-handler settings of nodes when nodesDraggable=false, so no matter you click on any place inside the node, it will be selected immediately.
  2. There exists some precision errors (or bias) when writing a float number into DB or in reverse. The node position coordinates become float numbers after dragging. So when you re-enter the repo after some drag operations, you may see some errors threw by verifyConsistency:
    image

A possible solution: stop using !== to compare floats (many classic issues can be referenced in IEEE 754), you can use something like:

if (Math.abs(node1.position.x-node2.position.x) > Number.EPSILON) {
...
}
  1. I set editable=false in Remirror component for guest users, the text cursor cannot be displayed in the node anymore, which means a guest cannot even select some texts. This is a totally different behavior from the official demo in storybook. But when you double-click on the text, the floating toolbar shows up, you can still bold, underscore, or highlight all texts. To solve the problem temporarily, you can implement the "read-only editor" manually by:
            onChange={(parameter) => {
              if(isGuest && parameter.tr?.docChanged) return;
              ...
            }}

But I feel many features are really wired in Remirror. If you have time, can you investigate it more and find any clue?

@lihebi
Copy link
Collaborator

lihebi commented Jan 4, 2023

3. the text cursor cannot be displayed in the node anymore, which means a guest cannot even select some texts.

It is because reactflow nodes have user-select: "none" CSS property. We just need to set it back:

<Box sx={{userSelect: "text", cursor: "auto"}}>
  ...
  <Remirror/>
  ...
</Box>

Let's fix it in another PR.

Copy link
Collaborator

@lihebi lihebi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, Xinyi!

@lihebi lihebi merged commit b118b80 into codepod-io:main Jan 4, 2023
@lihebi
Copy link
Collaborator

lihebi commented Jan 4, 2023

sx={{userSelect: "text", cursor: "auto"}}

For reference, PR #196 allows text selection in result block.

@li-xin-yi li-xin-yi deleted the fix/misc branch January 5, 2023 00:25
@li-xin-yi li-xin-yi mentioned this pull request Jan 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants