FluidFramework icon indicating copy to clipboard operation
FluidFramework copied to clipboard

Draft PR for adding support for custom attribution

Open jatgarg opened this issue 1 year ago • 1 comments

Description

E2E/Fuzz/Unit Tests are not added in this PR since this solution is in discussion.

Attribution means who inserted/annotated the text and at what time. Currently FF only supports attribution for the text and attribution for the props in the shared string. This means that the App can only get info about the user Id and the time at which a text is inserted/annotated like bold/italic or any other prop. We don’t allow app to store any other attribution data related to piece of text. For example,

1.) App wants to add a prop called DataSource which tells whether the source of text was from a template or not (called DataSource attribution prop on shared string).

2.) For copy paste scenario, where the user could be anyone outside the users of doc/org or even inside the doc, we need to let the app insert that custom attribution info which cannot be extracted from the op.

3.) Some copilot attribution props like “onBehalfOf” etc which tells us the user on behald of whom the text was inserted by the copilot.

Solution 2 link here: https://github.com/microsoft/FluidFramework/pull/22053

Solution:

1.) Add another type of key alongside the type of attribution keys which we already have. CustomAttributionKey = {type: “custom”, id: string } App will call createCustomAttributionKey() on the runtime attributor with the attribution data the user wants to store which will return custom attribution keys to the app. API on runtime attributor: createCustomAttributorKey( attributionInfoList: CustomAttributionInfo[], ): CustomAttributionKey[];

We will take an array of attributes object, so that user does not have to call it multiple times to create multiple keys before let's say passing those keys to insertText in shared string. The ids in the custom attribution keys would be generated using id compressor to keep them short and if id compressor is not available, then we will fall back to uuids.

2.) App will use these keys to pass to the shared string Apis like insertText() in props object. It can pass multiple keys at once as we can have multiple keys for a piece of text at different offsets like in copy paste scenario. This is represented by ICustomAttributionKeyList which can be added to props by utility api like: insertCustomAttributionPropInPropertySet()

We will define a channel name for the AttributionCollection for the segment which will be reserved for providing the custom keys generated above. Let’s call it: const customAttributionKeysPropName = “CAK-guid” where CAK is abbreviation for Custom Attribution Key. Just having a guid so as to avoid probable collision with other props which a user could insert and we will also match the type of this prop to make sure it is really meant for supplying custom attribution keys from the app.

sharedstring.insertText(pos, text, { customAttributionKeysPropName: [{offset: 0, key: CustomAttributionKey1}, {offset: 5, Key: CustomeAttributionKey2 }]}. This info will be stored in the attribution collection on the main collection once it is processed and this prop will be deleted from the props once consumed. We will only allow app to insert all this info only on insertion as this should not be changed once supplied.

3.) Transfer of above knowledge to other clients: We will add an API in container runtime class which will allow to submit external ops and then allow attributor to supply a external op processor so that other clients can process the external attributor op and add the custom attribution keys for query and summary later. public submitExternalOps(innerType: string, contents: unknown, localOpMetadata)

For processing of these ops at other clients, the runtime attributor will add an op processor to the constructor.
export interface IExternalOpProcessor { opProcessor: ( op: ContainerRuntimeExternalOp, local: boolean, localOpMetadata?: unknown, ) => boolean; stashedOpProcessor: (op: ContainerRuntimeExternalOp) => Promise; }

4.) Clients can then use the current api: attributor.getAtOffset(offset, cannelName) to get the custom attribution keys. Ex. attributor.getAtOffset (0, customAttributionKeysPropName): CustomAttributionKey[]

5.) Which can used to query the attributor to get the corresponding Attribution Info. Ex. Attributor.getCustomAttributionInfo(customAttributionKey): CustomAttributionInfo.

jatgarg avatar Jul 13 '24 03:07 jatgarg

@fluid-example/bundle-size-tests: +2.16 KB
Metric NameBaseline SizeCompare SizeSize Diff
aqueduct.js 457.54 KB 458.06 KB +527 Bytes
azureClient.js 555.3 KB 555.83 KB +539 Bytes
connectionState.js 680 Bytes 680 Bytes No change
containerRuntime.js 258.68 KB 259.18 KB +504 Bytes
fluidFramework.js 391.32 KB 391.33 KB +14 Bytes
loader.js 134.07 KB 134.08 KB +14 Bytes
map.js 42.12 KB 42.12 KB +7 Bytes
matrix.js 145.63 KB 145.63 KB +7 Bytes
odspClient.js 523.08 KB 523.61 KB +541 Bytes
odspDriver.js 97.17 KB 97.19 KB +21 Bytes
odspPrefetchSnapshot.js 42.27 KB 42.29 KB +14 Bytes
sharedString.js 162.64 KB 162.65 KB +7 Bytes
sharedTree.js 381.83 KB 381.84 KB +7 Bytes
Total Size 3.27 MB 3.27 MB +2.16 KB

Baseline commit: 276162baa4806a4fafa534706a02d95a1f34fd0c

Generated by :no_entry_sign: dangerJS against cdb254e92357a56297bc21f426abed36b5e381d9

msfluid-bot avatar Jul 13 '24 04:07 msfluid-bot

This PR has been automatically marked as stale because it has had no activity for 60 days. It will be closed if no further activity occurs within 8 days of this comment. Thank you for your contributions to Fluid Framework!