keystatic icon indicating copy to clipboard operation
keystatic copied to clipboard

Enhancement: more configurable collection path

Open florian-lefebvre opened this issue 2 years ago • 15 comments

Current state

Currently, the path is always static except for the slug, specified by slugField.

The problem

Projects often require more custom paths, e.g.: locales, publish date

Proposal

Make the collection config an intersection like so (pseudocode):

type Collection = { /* base props */}
	& (
		{
			path: string // with * validation
			slugField: keyof fields	
		}
		| {
			path: (fields: Record<string, any>) => string // with * validation
			slugField: keyof fields // might not be required, we could manually specify the field by interpolation instead
		}
	)

Examples

Locales

export default defineConfig({
	// ...
	collections: {
		blog: collection({
			label: "Blog",
			path: ({ locale }) => `src/content/blog/${locale}/*`
			schema: {
				// ...
				locale: fields.text({ label: "Locale" }) // could be a relationship, whatever
			}
		})
	}
})

Publish date

export default defineConfig({
	// ...
	collections: {
		blog: collection({
			label: "Blog",
			path: ({ publishDate }) => `src/content/blog/${publishDate}.*`
			schema: {
				// ...
				publishDate: fields.date({ label: "Published date" })
			}
		})
	}
})

florian-lefebvre avatar Jun 18 '23 18:06 florian-lefebvre

Noted on the use case here 👍

We're pretty keen on keeping slugs static (i.e not having a function you need to call in order to know where entries live) because we need to load the content directly from GitHub over their API, and knowing that as part of static config is very helpful. The challenge with allowing a function to define it is that it becomes non-deterministic, while that's not the case in your examples above, there'd be nothing stopping you from doing:

path: () => `/content/${date.now()}/*`

... chaos 💥

However we've discussed supporting support multiple slugFields as an alternative, which may solve the problem:

export default defineConfig({
	// ...
	collections: {
		blog: collection({
			// ...
			slugFields: ['locale', 'slug'],
			path: 'src/content/blog/*/*', // stars are replaced with values in order of the keys in the array above
			schema: {
				// ...
				slug: fields.slug(/* ... */),
				locale: fields.text({ label: "Locale" })
			}
		})
	}
})

What do you think? sound useful? can you see any limitations with this approach, if we added it, that you couldn't work around?

JedWatson avatar Jun 26 '23 11:06 JedWatson

Sounds good 👍, a few thoughts:

  • It should be also applied for usage with documents fields
  • Maybe we could push this a bit further with Typescript string interpolation

Right now, path requires either * or ** to be included. By setting the slugFields, we could pass them to the path type to force including [locale] and [slug] in the path. I don't know if this is possible though 🤔.

Wdyt?

florian-lefebvre avatar Jun 26 '23 12:06 florian-lefebvre

I had a chat with the team today about it, and there's some nuance that we need to solve, but I've put it on the roadmap.

I like your idea about using the name of the field in the path too, we'll see what we can come up with and whether that's possible 🙂

Can you expand a bit more on what you mean by "it should be applied for usage with document fields" too?

JedWatson avatar Jun 28 '23 13:06 JedWatson

Awesome thanks! My bad, I just checked my schema and I thought putting format: { contentField: 'document' } changed the key to set for the path. Nevermind!

florian-lefebvre avatar Jun 28 '23 13:06 florian-lefebvre

Hey @JedWatson, hope you're doing well! Do you have any ETA about this? Or could I help in any way, maybe with some guidance? It has become a must for the project I'm working on and I can dedicate a bit of time to make changes to keystatic

florian-lefebvre avatar Jul 26 '23 15:07 florian-lefebvre

Sounds good 👍, a few thoughts:

  • It should be also applied for usage with documents fields
  • Maybe we could push this a bit further with Typescript string interpolation

Right now, path requires either * or ** to be included. By setting the slugFields, we could pass them to the path type to force including [locale] and [slug] in the path. I don't know if this is possible though 🤔.

Wdyt?

@JedWatson have a look at https://www.typescriptlang.org/play#code/C4TwDgpgBAxgFhGBrACgQ2HAPAZQDYCuA5lBAB7AQB2AJgM5R3ABOAllUQDRQAqpF1eoxbsiAPigBeKAG18xALr9KtBjIBQUKPJLkVQtFRBQA-FAAUfPYIYADACQBvQyAC+9pzvfOjr26e1CEgAuKCoIADcIZgBKKFDwqOZ1BU0AnjSEyOiAbnV1GAB7KiZYZggMCABhQrw8RGBWYqkoXCDlG2E2Dm50TA7VLtExczS6IIAxVgg8elCdGQVONLAMOFD4RFQ1tuJetbF1GNCIwtYaKQlHVzyC4tKyFphyypq6hqaqcxkAIjQf7g-ABGPyWUB+eEK5QAtgBaVhgOgEaEAensaBRADNCoUgWhmD8YnkgA

Credits to SuperKXT on Matt's TS Wizards Discord server

EDIT: more realistic version https://www.typescriptlang.org/play#code/C4TwDgpgBAxgFhGBrACgQ2HAPAZQDYCuA5lBAB7AQB2AJgM5R3ABOAllUQDRQAqpF1eoxbsiAPigBeKAG18xALr9KtBjIBQUKPJLkVQtFRBQA-FAAUfPYIYADACQBvQyAC+9pzvfOjr26e1CEgAuKCoIADcIZgBKKFDwqOZ1BU0AnjSEyOiAbnV1UEgoAGEAezw8RGBWUqpcIOUbYTYObnRMRtVm0QlpRzS6IIAxVgg8elCdGQU8rTAMOFD4RFQF+uI2hbE81zz1GFqmWGYIDAgyiqqaqikodd0BLqYWrih2uE6hZ57zNIPLmDVWqhC6VQHXe6bTBidRxSQSf5goFUPYHKhHMi3GAnM6gq61cyORjDUbjOihGQAIholIU3HmmFClPsNKgrhiewAZgQqODasdTpQylROawiFg0joGNYugAlRClZg0LDfVrdDhiThpd7Sx5CeUHJVYJAQEClTmBYh0biq8RarR4vnoz4MfpaLQyJBQdhQE1mi1ShShImDYgjMYTS1EOiehTTHJQBmLN4LGNIJS7NKudRicxo0VEYN-cpI67kqBu92e703P3mkol-HooOyNLu2AIZDvLCO5FpuOU0NEcNk2kyKgEAC2ACNonSGwC+7GqUnaTD20oZUJx9lmKl21ozCGSRHy72y8vByfRzNEwsskk2W33SDG07+7M2Ts4pWTsACMwNz5mKOz5GiRzGNI2KCuctQFoSaQAPSIVoAB6JjFouZZFu2aDBsSYakpGVI0vOSZMiylJsva7rTksOJCm+yKEgRw5EeWVIQLS9L3lAzJcWyMQ0a4WrsnkQA

florian-lefebvre avatar Aug 01 '23 12:08 florian-lefebvre

~~💎 $100 bounty created by @florian-lefebvre~~ ~~👉 To claim this bounty, submit your pull request on Algora~~ ~~📝 Before proceeding, please make sure you can receive payouts in your country~~ ~~💵 Payment arrives in your account 2-5 days after the bounty is rewarded~~ ~~💯 You keep 100% of the bounty award~~ ~~🙏 Thank you for contributing to Thinkmill/keystatic!~~

algora-pbc avatar Aug 08 '23 08:08 algora-pbc

Hi is this issue still available to be worked on? Would love to give it a shot :)

aazam-gh avatar Aug 24 '23 16:08 aazam-gh

cc @JedWatson

florian-lefebvre avatar Aug 25 '23 08:08 florian-lefebvre

@florian-lefebvre any updates?

aazam-gh avatar Aug 30 '23 12:08 aazam-gh

nope, I'm not on the team so waiting for an answer as well

florian-lefebvre avatar Aug 30 '23 13:08 florian-lefebvre

@algora-pbc Can you add a bounty label for issue?

sravanth-space avatar Sep 05 '23 20:09 sravanth-space

That's a bot, I think labelling has to be done by the keystatic team if they wish

florian-lefebvre avatar Sep 06 '23 06:09 florian-lefebvre

@florian-lefebvre

Is this open to work? Would love to crush this.

rishi-raj-jain avatar Nov 07 '23 07:11 rishi-raj-jain

@JedWatson Any updates?

reteps avatar Oct 20 '24 19:10 reteps