Discussion on syncing user data and customizing the Sanity studio based on user access.
14 replies
Last updated: Sep 13, 2022
S
Hi! I'm trying to create a document for all users like this: https://www.sanity.io/schemas/create-a-document-for-all-current-project-users-68b6f0db but I really want it to try and sync each time the studio loads. Any ideas on how to go about this?
I've tried doing this:
https://www.sanity.io/schemas/custom-default-desk-pane-35148d61 but it doesn't load with a custom desk structure. I've also tried making my desk structure into a React component but that doesn't work.
I've tried doing this:
https://www.sanity.io/schemas/custom-default-desk-pane-35148d61 but it doesn't load with a custom desk structure. I've also tried making my desk structure into a React component but that doesn't work.
Sep 6, 2022, 5:01 PM
S
I think I found a way to do this, but it feels illegal:
Basically made the Desk structure async..
Basically made the Desk structure async..
const DeskStructure = async () => { await syncUsers() return S.list() }
Sep 6, 2022, 5:15 PM
S
Wait where do you want to get the user docs into? This seems indeed strange to do. Can you give me more input, so I can try understand what your goal is?
Sep 8, 2022, 2:04 PM
S
(this still makes me giggle btw: I think I found a way to do this, but it feels illegal)
Sep 8, 2022, 2:08 PM
S
Hi Saskia! I have a studio that runs 5 different frontend sites. We've organized it so that most documents (pages/articles etc) reference a "domain document" and fetch the correct frontend using multiple deployments in Vercel and environment variables to set the domain id.
Now we want to have a different view for the editors based on which page they can access. This is purely visual I know since no enterprise, but works well for us.
The jist is:
• Sync Sanity users to a document called 'sanityUser' on each studio load.
• The sanityUser document contains an array of references to domains, the "sanity id" of the user, as well as a "superadmin" boolean
• In the DeskStructure we then find the current users ID and find the corresponding document. We then filter the desk structure based on their access
Now we want to have a different view for the editors based on which page they can access. This is purely visual I know since no enterprise, but works well for us.
The jist is:
• Sync Sanity users to a document called 'sanityUser' on each studio load.
• The sanityUser document contains an array of references to domains, the "sanity id" of the user, as well as a "superadmin" boolean
• In the DeskStructure we then find the current users ID and find the corresponding document. We then filter the desk structure based on their access
Sep 8, 2022, 2:40 PM
S
If you are interested it looks like this:
// Desk structure const DeskStructure = async () => { await syncUsers() const currentUser = await userStore.getCurrentUser() const { superAdmin, siteAccess } = await studioClient.fetch( `*[_type == 'sanityUser' && id == $id][0]{ superAdmin, "siteAccess": siteAccess[]._ref }`, { id: currentUser.id } ) if (!superAdmin) { return S.documentTypeList("domain") .filter("_id in $siteAccess") .params({ siteAccess }) .title("Nettsider") .child((domainID) => domainDocumentList(domainID)) } // Superadmin view return S.list() }
// Sync users import client from "part:@sanity/base/client" import cq from "concurrent-queue" import userStore from "part:@sanity/base/user" const studioClient = client.withConfig({ apiVersion: "2022-03-25" }) // Create a queue to limit the rate at which you write changes to Sanity let queue = cq() .limit({ concurrency: 2 }) .process(function (task) { return new Promise(function (resolve, reject) { setTimeout(resolve.bind(undefined, task), 1000) }) }) const syncUsers = async () => { //query for all members, then use the userStore to get their details const [allUsers, existingUsers] = await Promise.all([ studioClient.fetch(`*[_id in path('_.groups.*')].members[@ != 'everyone']`), studioClient.fetch(`*[_type == "sanityUser"].id`), ]) // Filter to to the users that are not already existing const newUsers = allUsers .flat() .filter((user) => !existingUsers.includes(user)) if (newUsers.length == 0) return // Fetch the user details from the userStore const userDetails = await userStore.getUsers(newUsers) for (const user of userDetails) { const doc = { _type: "sanityUser", _id: "sanityUser." + user.id, id: user.id, name: user.displayName, } queue(doc).then(async () => { //create the doc via the client studioClient .create(doc) .then((updatedDoc) => { console.log( `Hurray, the doc is updated! New document:${updatedDoc._id}` ) }) .catch((err) => { console.error("Oh no, the update failed: ", err.message) }) }) } } export default syncUsers
Sep 8, 2022, 2:43 PM
S
So it works haha. And I think this technique can be used to fully customize the studio based on document types etc 😄
Sep 8, 2022, 2:54 PM
S
I will def have a more detailed look on Monday and try out your approach 🫡If it's illegal we will both go to jail then
🚨 #partnersInCrime
🚨 #partnersInCrime
Sep 11, 2022, 8:36 PM
S
I am just spitballing here, but maybe another approach (not sure if better or worse) would be to get some thing working in the stucture builder `hidden doc types`….
// /deskStructure.js // Hide document types that we already have a structure definition for const hiddenDocTypes = (listItem) => ![ "siteSettings", //some async functionality here ].includes(listItem.getId()); export default () => S.list() .title('Content') .items([ site1Docs, S.divider(), // your other desk partitions S.divider(), siteSettings, ...S.documentTypeListItems().filter(hiddenDocTypes) ])
Sep 13, 2022, 12:15 PM
S
This def works and is a solution we've used a lot, but it doesn't show a different view based on what user is logged in
Sep 13, 2022, 12:33 PM
S
i mean, that you could try the same kind of rendering which you have now, but use the userStore info … dont know if it works, but I am always for testing our performance…
Sep 13, 2022, 12:41 PM
S
And tbh, as long as it works, I would try stuff, thats the beauty of open source right?
Sep 13, 2022, 12:42 PM
S
Indeed, very happy with this discovery as this means we can basically make custom roles on the free plan
Sep 13, 2022, 12:45 PM
S
Everyone of course has the same access via the actual API etc but this will suit our projects nicely
Sep 13, 2022, 12:46 PM
S
yeah its more render access, but a workaround.
Sep 13, 2022, 1:12 PM
Sanity– build remarkable experiences at scale
Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.