Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workspace-dep-closures.json
Original file line number Diff line number Diff line change
Expand Up @@ -4595,6 +4595,7 @@
"crates/properties",
"crates/rate_limit",
"crates/remote_env_var",
"crates/share_permission_db_utils",
"crates/system_properties",
"crates/workspace-hack"
],
Expand Down Expand Up @@ -4659,6 +4660,7 @@
"crates/properties",
"crates/rate_limit",
"crates/remote_env_var",
"crates/share_permission_db_utils",
"crates/system_properties",
"crates/workspace-hack"
],
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

56 changes: 56 additions & 0 deletions apps/web/src/lib/core/component/TopBar/ShareButton.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ beforeEach(() => {
mocks.updateChatPermissions.mockResolvedValue({ isErr: () => false });
mocks.updateCallTeamShare.mockResolvedValue({ isErr: () => false });
mocks.editProject.mockResolvedValue({ isErr: () => false });
mocks.updateDatabasePermissions.mockResolvedValue({ isErr: () => false });
mocks.editDocument.mockResolvedValue({ isErr: () => false });
Object.defineProperty(navigator, 'clipboard', {
configurable: true,
Expand Down Expand Up @@ -1542,6 +1543,61 @@ it('database sharing reads its block permissions and disables public links', ()
expect(screen.queryByText('Anyone with the link')).toBeNull();
});

describe('database team sharing', () => {
function mountDatabaseShare() {
mocks.blockPermissionsRead.mockReturnValue({
isErr: () => false,
value: {
id: 'database-id',
owner: ME,
teamShareAccessLevel: null,
channelSharePermissions: [],
},
});
render(() => (
<ShareModal
id="database-id"
itemType="database"
blockAlias="database"
owner={ME}
name="Ideas"
userPermissions={Permissions.OWNER}
open
onOpenChange={vi.fn()}
/>
));
}

it('lets the owner share the database with their team through its permissions endpoint', async () => {
mocks.hasTeam = true;
mountDatabaseShare();

expect(
screen.getByText("Share this database directly with the owner's team.")
).toBeTruthy();
fireEvent.click(
screen.getByRole('button', { name: 'Set Team access level edit' })
);

await vi.waitFor(() =>
expect(mocks.updateDatabasePermissions).toHaveBeenCalledWith({
id: 'database-id',
teamShareAccessLevel: 'edit',
})
);
expect(mocks.editDocument).not.toHaveBeenCalled();
});

it('hides database team access when the owner has no team', () => {
mocks.hasTeam = false;
mountDatabaseShare();

expect(
screen.queryByRole('group', { name: 'Team access level' })
).toBeNull();
});
});

describe('form share roles', () => {
it.each([false, true])(
'shows form link sharing in the native link area (mobile: %s)',
Expand Down
5 changes: 5 additions & 0 deletions apps/web/src/lib/core/component/TopBar/ShareButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1363,6 +1363,11 @@ export function ShareModal(props: ShareModalProps) {
id: props.id,
sharePermission,
});
} else if (props.itemType === 'database') {
result = await updateDatabaseSharePermissions({
id: props.id,
...sharePermission,
});
} else {
result = await storageServiceClient.editDocument({
sharePermission,
Expand Down
1 change: 1 addition & 0 deletions apps/web/src/lib/core/component/TopBar/linkShare.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const TEAM_SHAREABLE_ITEM_TYPES: ReadonlySet<ShareItemType> =
'agent_session',
'initiative',
'crm_pipeline',
'database',
]);

export function isTeamShareSupportedForItem(itemType: ShareItemType): boolean {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 12 additions & 2 deletions apps/web/src/lib/service-clients/service-storage/openapi.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion crates/databases/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ service with Axum, agent-tool and Postgres adapters.

## Boundaries

- Depends on: `entity_access` (permission scoping), `properties` (cell values),
- Depends on: `entity_access` (permission scoping), `entity_access_db_utils` and
`share_permission_db_utils` (channel grants and the team share), `properties` (cell values),
`macro_event_broker`/`macro_event_topics` (change notifications),
`connection_gateway_client` (liveness), `entity_mutation` (rename/trash/restore).
- Used by: `databases_sql` (agent SQL), `crm` and `forms` (own storage via
Expand Down Expand Up @@ -55,6 +56,11 @@ service with Axum, agent-tool and Postgres adapters.
other (see README "Storage and app entities").
- Column type changes must convert every value or refuse with the misfit count;
never silently drop data outside an explicit delete.
- Sharing (`src/domain/sharing.rs`): channel grants and a team share; no share
link. The team share's state lives in a `SharePermission` row that
`database_entities.share_permission_id` points at, made the first time the
owner sets it, and its grant is a team-source `entity_access` row that rows,
listing and Soup read like any other. Only the actual owner may change it.

## Related

Expand Down
3 changes: 3 additions & 0 deletions crates/databases/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ postgres = [
"dep:anyhow",
"dep:entity_access_db_utils",
"dep:properties",
"dep:share_permission_db_utils",
"dep:sqlx",
"outbound",
]
Expand Down Expand Up @@ -72,6 +73,7 @@ schemars = { workspace = true, optional = true }
serde = { workspace = true }
serde_json = { workspace = true }
sha2 = { workspace = true }
share_permission_db_utils = { path = "../share_permission_db_utils", optional = true }
sqlx = { workspace = true, optional = true }
strum = { workspace = true }
thiserror = { workspace = true }
Expand All @@ -85,6 +87,7 @@ workspace-hack = { version = "0.1", path = "../workspace-hack" }
[dev-dependencies]
entity_access = { path = "../entity_access", default-features = false, features = ["outbound"] }
macro_db_migrator = { path = "../macro_db_migrator" }
model_owner = { path = "../model_owner" }
# The palette the fakes colour new options from.
properties = { path = "../properties", default-features = false }
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
Expand Down
12 changes: 9 additions & 3 deletions crates/databases/src/domain/models/schema_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,15 @@ pub enum SharingError {
/// Share links are not supported for databases.
#[error("Databases cannot be shared by link yet.")]
LinkShare,
/// Team shares are not supported for databases.
#[error("Databases cannot be shared with a team yet.")]
TeamShare,
/// The owner is not on a team to share with.
#[error("Join a team to share this database with it.")]
NoTeam,
/// A team share must grant view, comment, or edit access.
#[error("Share with your team for view, comment, or edit access.")]
InvalidTeamLevel,
/// Ownership, team membership, or the team share changed meanwhile.
#[error("This database's sharing changed. Refresh and try again.")]
Changed,
/// A request changes more channel grants than any may.
#[error("Share with at most {max} channels at a time.")]
TooManyChannels {
Expand Down
Loading
Loading