-
-
Notifications
You must be signed in to change notification settings - Fork 335
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
#1047 access signaling using workspace/doc icon #1048
base: main
Are you sure you want to change the base?
Conversation
This PR signals access of each workspace and document using their icons. The color of icon is different for each access level: * shared with everyone or anonymous -> icon is green; * shared with other people than yourself (the owner) but not with everybody -> icon is yellow; * shared only with you (the owner)-> icon is gray.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, it seems to me like this is a good idea, indeed!
I think of color-blind people, which may not see the differences between these colors. I suggest that we could also introduce other icons. What do you think?
Sure, I'll do it. |
I agree that it is a good idea to private, shared, and link-shared (public) documents, and workspaces. Currently, only link-shared documents are distinguished, with an icon. For comparison, Google Drive distinguishes private vs shared, for both folders and documents, but using a different icon for folders, and adding an icon (similar to ours) for shared docs. We do need a better design here. In particular, like @fflorent suggested, we should probably distinguish with different icons, rather than with color. Cc'ing @lusebille , in case she can suggest something simple. Let me also mention an idea that's come up: to allow users to specify an emoji as an icon to identify documents (and maybe workspaces?), similar to how we allow this for pages within documents (see https://support.getgrist.com/page-widgets/#pages). Just noting that as a reason to use a separate icon to indicate access. |
Hi I made mocks for this ticket, my proposal is to keep only clear / simple icon ( I've designed some ) , I suggest using only different icons and make folder icons a bit bigger (for be readable ) @fflorent @dsagal @hexaltation and the link to icons (design system file ) |
Hmm, these look nice and make sense, but Grist already uses the "two-people" icon to represent a link-shared (public) document, and I am a bit worried about changing the meaning of an existing icon. The second concern is that we had made an intentional choice to use a green icon for publicly-shared documents, to make them stand out since this is a potentially sensitive situation (higher risk of accidental oversharing). With the new design, such documents stand out much less (there is no difference in color or icon placement, only in which icon it is). @lusebille , what do you think about these concerns? |
I think I'm not sure to understand correctly the difference of each case ,
I think I may need a clear explanation of all those cases ( we can see that on monday ) |
Correct, "public" (also known as "link-shared") gives access to anyone with a link. But it is only available for a document, not for a workspace.
There is no option with this phrasing, although "inherit access" does something similar (more below).
This is controlled by which users the document is shared with. If the list in the dialog includes only one owner, then it's private to them, if it includes anyone else, then it's "some people". "Inherit access" option works as follows:
Inheriting access does not overlap with the "public access" setting, because workspaces don't support "public access", so there is nothing for documents to inherit. |
Thanks for the explanation 🙏 So I suggest that (figma link should be ok ) https://www.figma.com/design/wcpetFt6aOKzTszcvPPWLQ/%5B05%2F24%5D-Grist-Design?node-id=294-15776&t=DHxvpRmX7yNUOfCW-1
|
I like the earlier design for being clearer and simpler. May we can reduce the possible confusion from changing the meaning of the "people" icon (from meaning "public" to meaning "shared") this way?
For showing details for "shared with other people", I think people would find it helpful, but there are several considerations to keep in mind:
|
Ticket is ready from design side https://www.figma.com/design/ze7cIn7QZlMjswn38bdJKE/Ticket-1048?node-id=0-1&t=NcgwSdR6FWOMZGhQ-1 I also joined the icones as svgs |
Thank you @lusebille ! This design looks good, and approved. @florentinap , how do you feel about updating your implementation with the new design? |
Applied suggestions from PR; changed icons and remove colors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @florentinap, I am really looking forward seeing it landed!
@@ -134,7 +134,7 @@ function createLoadedDocMenu(owner: IDisposableOwner, home: HomeModel) { | |||
hasFeaturedTemplates ? t("More Examples and Templates") : t("Examples and Templates") | |||
) : | |||
page === 'trash' ? t("Trash") : | |||
workspace && [css.docHeaderIcon('Folder'), workspaceName(home.app, workspace)] | |||
workspace && [css.docHeaderIcon(workspace.shareType === 'public' ? 'Folder' : 'FolderPrivate'), workspaceName(home.app, workspace)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you address the warnings here?
You may use yarn lint
to find them (yarn lint:fix
to fix those which can be).
roles.getWeakestRole(<roles.Role>user.parentAccess, <roles.Role>maxInheritedRole)); | ||
}); | ||
if (permissionDataUsers?.length > 1) { | ||
ws.shareType = permissionDataUsers.find((user) => user.email === EVERYONE_EMAIL || user.email === ANONYMOUS_USER_EMAIL || user.id !== scope.userId) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't (user) => user.id !== scope.userId
be enough? I don't expect a user to connect using the everyone
or the anonymous
special accounts. Or is there some subtleties that would explain the other conditions?
@@ -119,6 +119,7 @@ export interface Workspace extends WorkspaceProperties { | |||
org: Organization; | |||
orgDomain?: string; | |||
access: roles.Role; | |||
shareType?: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we could take advantage of TypeScript and that this model is shared between the client and the server to constrain the values of shareType
. Either by using an enum or by typing to the expected values ('private' | 'public'
).
Also I wonder if based on what I see in the code, when the workspace is not private
, it should not be considered as shared
rather than public
(the latest suggesting that it can be viewed even by anonymous users). What do you think?
@@ -161,6 +162,7 @@ export interface Document extends DocumentProperties { | |||
id: string; | |||
workspace: Workspace; | |||
access: roles.Role; | |||
shareType?: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as above regarding the type (enum or using a union the possible values).
? 'public' | ||
: 'private'; | ||
|
||
for(const doc of ws.docs) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a bit of styling (sorry, we should have them defined in eslint rules):
for(const doc of ws.docs) { | |
for (const doc of ws.docs) { |
doc.shareType = permissionDataUsersDoc.find((user) => user.email === EVERYONE_EMAIL | ||
|| user.email === ANONYMOUS_USER_EMAIL) | ||
? 'public' | ||
: permissionDataUsersDoc.find((user) => user.id !== scope.userId) | ||
? 'shared' | ||
: 'private'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest that we may take advantage of a Set
and the getAnonymousUserId
and getEveryoneUserId
to simplify a bit the code:
const userIds = new Set(permissionDataUsersDoc.map(user => user.id));
if (userIds.size === 1 && userIds.has(scope.userId)) { // Note from Florent: I wonder if the second condition is even necessary
doc.shareType = 'private';
} else if (userIds.has(this.getEveryoneUserId()) || userIds.has(this.getAnonymousUserId()) {
doc.shareType = 'public';
else {
doc.shareType = 'shared';
}
@@ -692,6 +692,36 @@ export class HomeDBManager extends EventEmitter { | |||
ws.owner = o.owner; | |||
// Include the org's domain so that the UI can build doc URLs that include the org. | |||
ws.orgDomain = o.domain; | |||
|
|||
// Include shareType based on users permissions to set icon color | |||
const {maxInheritedRole, users } = this.unwrapQueryResult( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpicking for the styling consistency:
const {maxInheritedRole, users } = this.unwrapQueryResult( | |
const { maxInheritedRole, users } = this.unwrapQueryResult( |
return !!roles.getStrongestRole(user.access, | ||
roles.getWeakestRole(<roles.Role>user.parentAccess, <roles.Role>maxInheritedRole)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are much chances that I misunderstand something. Please don't hesitate to tell me if I am wrong :).
I expect this expression roles.getStrongestRole(user.access, roles.getWeakestRole(<roles.Role>user.parentAccess, <roles.Role>maxInheritedRole));
to return the effective role as described in the comment above.
So we filter anyone having at least a direct access or an inherited access.
It would thus be equivalent to:
const hasDirectAccess = Boolean(user.access);
const hasInheritedAccess = Boolean(roles.getWeakestRole(<roles.Role>user.parentAccess, <roles.Role>maxInheritedRole)));
return hasDirectAccess || hasInheritedAccess;
If so, if you prefer your current implementation, could you add a comment to clarify the that?
This PR signals access of each workspace and document using their icons. The color of icon is different for each access level:
Update: new icons