[{"data":1,"prerenderedAt":698},["ShallowReactive",2],{"footer-primary":3,"footer-secondary":93,"footer-description":119,"tv-request-review":121,"tv-request-review-seasons":131,"tv-request-review-episodes":150,"sales-reps":446},{"items":4},[5,29,49,69],{"id":6,"title":7,"url":8,"page":8,"children":9},"522e608a-77b0-4333-820d-d4f44be2ade1","Solutions",null,[10,15,20,25],{"id":11,"title":12,"url":8,"page":13},"fcafe85a-a798-4710-9e7a-776fe413aae5","Headless CMS",{"permalink":14},"/solutions/headless-cms",{"id":16,"title":17,"url":8,"page":18},"79972923-93cf-4777-9e32-5c9b0315fc10","Backend-as-a-Service",{"permalink":19},"/solutions/backend-as-a-service",{"id":21,"title":22,"url":8,"page":23},"0fa8d0c1-7b64-4f6f-939d-d7fdb99fc407","Product Information",{"permalink":24},"/solutions/product-information-management",{"id":26,"title":27,"url":28,"page":8},"63946d54-6052-4780-8ff4-91f5a9931dcc","100+ Things to Build","https://directus.io/blog/100-tools-apps-and-platforms-you-can-build-with-directus",{"id":30,"title":31,"url":8,"page":8,"children":32},"8ab4f9b1-f3e2-44d6-919b-011d91fe072f","Resources",[33,37,41,45],{"id":34,"title":35,"url":36,"page":8},"f951fb84-8777-4b84-9e91-996fe9d25483","Documentation","https://docs.directus.io",{"id":38,"title":39,"url":40,"page":8},"366febc7-a538-4c08-a326-e6204957f1e3","Guides","https://docs.directus.io/guides/",{"id":42,"title":43,"url":44,"page":8},"aeb9128e-1c5f-417f-863c-2449416433cd","Community","https://directus.chat",{"id":46,"title":47,"url":48,"page":8},"da1c2ed8-0a77-49b0-a903-49c56cb07de5","Release Notes","https://github.com/directus/directus/releases",{"id":50,"title":51,"url":8,"page":8,"children":52},"d61fae8c-7502-494a-822f-19ecff3d0256","Support",[53,57,61,65],{"id":54,"title":55,"url":56,"page":8},"8c43c781-7ebd-475f-a931-747e293c0a88","Issue Tracker","https://github.com/directus/directus/issues",{"id":58,"title":59,"url":60,"page":8},"d77bb78e-cf7b-4e01-932a-514414ba49d3","Feature Requests","https://github.com/directus/directus/discussions?discussions_q=is:open+sort:top",{"id":62,"title":63,"url":64,"page":8},"4346be2b-2c53-476e-b53b-becacec626a6","Community Chat","https://discord.com/channels/725371605378924594/741317677397704757",{"id":66,"title":67,"url":68,"page":8},"26c115d2-49f7-4edc-935e-d37d427fb89d","Cloud Dashboard","https://directus.cloud",{"id":70,"title":71,"url":8,"page":8,"children":72},"49141403-4f20-44ac-8453-25ace1265812","Organization",[73,78,84,88],{"id":74,"title":75,"url":76,"page":77},"1f36ea92-8a5e-47c8-914c-9822a8b9538a","About","/about",{"permalink":76},{"id":79,"title":80,"url":81,"page":82},"b84bf525-5471-4b14-a93c-225f6c386005","Careers","#",{"permalink":83},"/careers",{"id":85,"title":86,"url":87,"page":8},"86aabc3a-433d-434b-9efa-ad1d34be0a34","Brand Assets","https://drive.google.com/drive/folders/1lBOTba4RaA5ikqOn8Ewo4RYzD0XcymG9?usp=sharing",{"id":89,"title":90,"url":8,"page":91},"8d2fa1e3-198e-4405-81e1-2ceb858bc237","Contact",{"permalink":92},"/contact",{"items":94},[95,101,107,113],{"id":96,"title":97,"url":8,"page":98,"children":100},"8a1b7bfa-429d-4ffc-a650-2a5fdcf356da","Cloud Policies",{"permalink":99},"/cloud-policies",[],{"id":102,"title":103,"url":81,"page":104,"children":106},"bea848ef-828f-4306-8017-6b00ec5d4a0c","License",{"permalink":105},"/bsl",[],{"id":108,"title":109,"url":81,"page":110,"children":112},"4e914f47-4bee-42b7-b445-3119ee4196ef","Terms",{"permalink":111},"/terms",[],{"id":114,"title":115,"url":81,"page":116,"children":118},"ea69eda6-d317-4981-8421-fcabb1826bfd","Privacy",{"permalink":117},"/privacy",[],{"description":120},"\u003Cp>A composable backend to build your Headless CMS, BaaS, and more.&nbsp;\u003C/p>",{"id":122,"title":123,"logo":124,"cover":125,"tile":126,"announcement_text":8,"description":127,"slug":128,"one_liner":129,"card_text":8,"status":130,"sort":8},"8cf6395d-10fb-4df9-9e47-67d1ee4549eb","Request Review","4b62303e-8f45-4e0f-a6f1-6655eda22768","57daf252-741d-411e-af51-9cfd54d5eb48","73687d01-3734-4c28-aef7-e6fa8db4cf1e","In Request Review, we open the floor to discuss complex feature requests with you - our community - to better understand what implementation would make most sense.","request-review","Join our team discuss complex feature requests and figure out what's next.","published",[132],{"id":133,"number":134,"show":122,"year":135,"episodes":136},"6aa046f1-bd53-4510-9af0-c0f3daaf4415",1,"2024",[137,138,139,140,141,142,143,144,145,146,147,148,149],"daed2c08-703a-43d6-ac97-aacac61be4c0","86fa152b-6a8b-477e-94b5-bd91e1202d21","0b5f4343-1494-455b-b41a-25811c151242","b2b01569-d8c6-49a7-adaa-429fe84f204f","b63afbe1-6418-4e9e-b1da-4890979789f0","69ad81e8-5e1d-4b85-9fa9-3b767a3a3478","5c9c888c-f527-4608-a2f7-56f156d00980","243daa59-3772-4ebe-b212-c2a09a4a0b71","d66c1e46-cc57-49fe-a914-2e440bbc1576","12c8f72d-22fa-4ffa-a9d1-57047216fd1a","8896c934-aa2c-43b6-9342-8275682ab8b2","84c7b3ac-fd85-4539-8f39-3247118bcbf2","044b7c89-aaec-43b2-9d6d-6743a0fb5afd",[151,182,207,232,256,274,296,319,341,362,383,404,425],{"id":137,"slug":152,"vimeo_id":153,"description":154,"tile":155,"length":156,"resources":157,"people":161,"episode_number":134,"published":171,"title":172,"video_transcript_html":173,"video_transcript_text":174,"content":8,"seo":8,"status":130,"episode_people":175,"recommendations":179,"season":180},"json-filtering","903011547","In this recording of our live event on January 11 2024, Rijk, Jonathan, and Daniel discuss filtering inside of stored JSON objects. ","b2035eee-e7c0-44b0-80f6-ba0f7d5fbe37",52,[158],{"name":159,"url":160},"GitHub Discussion","https://github.com/directus/directus/discussions/7277",[162,165,168],{"name":163,"url":164},"Rijk van Zanten","https://directus.io/team/rijk-van-zanten",{"name":166,"url":167},"Jonathan Wagner","https://directus.io/team/jonathan-wagner",{"name":169,"url":170},"Daniel Biegler","https://directus.io/team/daniel-biegler","2024-01-18","Filtering of JSON Objects","\u003Cp>Speaker 0: Welcome, everyone. Happy 2024. We're excited for a new year. We're gonna try out a new well, we've been we've been playing around with this request for views format for a little while, but we're gonna we're gonna try out just covering a specific feature, talking through some details, making sure that we have a full specification on it, and getting additional community feedback, as needed. Today's topic will be JSON object filtering.\u003C/p>\u003Cp>It's been a it's a very, very popular request that we see quite frequently, and we would love to ensure that we solve this problem correctly and get it working for the databases that support it. I think one of the key issues that we've run into we've done a lot of development work on this, but what we run into is various database vendors support this differently. You fix it to support that thing. It breaks something else. We spent a lot of time kind of iterating back and forth on this feature, and I'll let Rai talk about some of that.\u003C/p>\u003Cp>But I mean, fundamentally, we we know that this is important. We consider it kind of a critical road map item, and that's the reason we're gonna talk in detail about it today.\u003C/p>\u003Cp>Speaker 1: Absolutely. Well, thank you for that. Yeah. And as you can see, I was the one who opened this feature request conveniently with no details whatsoever. I basically just say, hey, man.\u003C/p>\u003Cp>I wanna be able to filter in JSON objects. Good luck. And then everybody was like, yep. Me too. However, you know, the this this was done way before we had that RFC format, so the the the details are lacking.\u003C/p>\u003Cp>Let's let's call it that. So before we dive in too deeply, you know, Daniel, I'm just gonna throw you under the bus here. You wanna walk us through what what even is JSON filtering in the first place?\u003C/p>\u003Cp>Speaker 2: JSON filtering can be quite useful if you store JSON inside of your database, and you need to check some field inside of that JSON in your database. Like, we said in the beginning, right, not every database supports this as of right now, which forces us or will force us to, you know, do some little Directus magic as usual. But more and more databases kinda jump on the train, which is pretty neat. I think as what was it? SQLite very recently also announced that they have JSON b support, I think.\u003C/p>\u003Cp>I hope I'm not miss remembering. But, yeah, can be quite useful. If you have stored JSON, then you can filter on fields inside of that JSON. That's very useful.\u003C/p>\u003Cp>Speaker 0: And I think as as Kevin points out, actually, a couple of our default interface configuration our field configurations actually store in JSON by default. You can change them in most cases, but and, currently, that's the recommendation. So off the support side of things currently, for those of you listening, if you use the CSV format instead, on the database field setting side, you can then filter through the application in the API on those fields. But JSON is a little bit nicer structured format, so the reason for the request.\u003C/p>\u003Cp>Speaker 1: Yeah. And then the other the other big sort of elephant in the room there, of course, is that a lot of systems are utilizing and or could be utilizing more of a document style structure rather than, you know, a tabular style data structure. Especially, you know, when you have flexible schemas or unknown, you know, data structures ahead of time or semi semi structured data. Think about, you know, blocks on a page or something. You know, you're talking about sort of rich data that may or may not be structured like a table.\u003C/p>\u003Cp>So, therefore, you know, storing JSON in a Postgres database or another SQL database can give you some of that document magic without having to switch over completely to a document database. So there's a lot of a lot of benefits to having this. Now that being said, it also comes with a ton of complexities. So in my original feature request I was really thinking about it sort of as a filter against the data. Right?\u003C/p>\u003Cp>So similar to how we have, some functions to run against date values. I don't know if you've seen those before, but we have things like extract the year from a timestamp as a function. I was thinking about it the same way in my original feature request. Right? So I was thinking maybe we can have just like you would be able to do, like, year time stamps equals 2024, you could do something like, I don't know, Jason, name of the field, and then some sort of identifier string to select something from that field and then run filters against it, against that value that you've now selected.\u003C/p>\u003Cp>Right? Similarly you'd be able to use that in fields or in sort or other pieces like that And we actually put a lot of work in that already, and by we, I mean Tim who's in the chat, and I'm definitely gonna put him on stage and put him in the spotlight. Jonathan, if you wanna pull that up real quick, it might actually be fun to take a quick scroll through. Also, as a way to answer that, do all DBs even support it? Because there's a wonderful table at the top of that pool request.\u003C/p>\u003Cp>If you wanna pull up the, don't bring him up. We're recording. He's he's a little camera shy, but we can we can figure it out.\u003C/p>\u003Cp>Speaker 0: You know the PR off the top of your head, or do I just need to go find it?\u003C/p>\u003Cp>Speaker 1: Oh, just just open up pull requests, and if you search for Jason, it should be the only one that's there.\u003C/p>\u003Cp>Speaker 2: GitHub\u003C/p>\u003Cp>Speaker 0: pull requests.\u003C/p>\u003Cp>Speaker 1: We've left it open intentionally. We'll we'll circle back to that later how we're handling now. But if you just probably all the way at the bottom is is a little older. Yep. There it is.\u003C/p>\u003Cp>Speaker 2: Alright.\u003C/p>\u003Cp>Speaker 0: There's your matrix.\u003C/p>\u003Cp>Speaker 1: Right. So in this PR, we basically took a swing at implementing that, you know, JSON filtering the way it was described in that discussion. And by described, I mean, vaguely hinted at, because the description was a little poor. But we did implement it in that way, and it does actually work. So we do have, you know, queries for a little different databases.\u003C/p>\u003Cp>But as you can see in this table to the Chet's point earlier, not everything is supported everywhere, which becomes tricky immediately. Right? Because how do you then document it? Now it's gonna be database different. So there has been, you know, implemented some fallback support so you can see the difference in that green check versus the, that sort of Unicode check I guess.\u003C/p>\u003Cp>You you can see that for a lot of these things we're actually you know having to do some direct us magic to to make that work against the database which is not necessarily gonna be the most performant or the what's the right word? The the the quote, unquote right way to do it. Right? It's a blue check mark. Oh, if you're on Windows, just pretend.\u003C/p>\u003Cp>If you're on Linux or Linux, just Linux, just pretend. The check marks are green. Anyways, while building this, if you might wanna pull up the file section of this PR, Jonathan, I think it's a fun fun scroll through. This if we go all the way to the top, there's a tab. Files changed.\u003C/p>\u003Cp>Speaker 2: 2000 editions. Oh my god.\u003C/p>\u003Cp>Speaker 1: Yeah. There's there's only a 1,000 lines across 50 files. The long the long story short is that in the database helpers, if you see in that left hand sidebar, you know, we have to add all of the additional queries for JSON filtering ourselves for a little different database types. Sort of hard coded in, You see them here in the dialects if you just click one of those. It doesn't really matter which one.\u003C/p>\u003Cp>So all of those sort of you can see them here. You know, we have a JSON extract for MariaDB that may or may not exist across the other database vendors. Right? So it's not a SQL standard, which makes this a heck of a lot more complicated than you'd think. It's because every database does it differently.\u003C/p>\u003Cp>I believe it was Postgres that doesn't rely on functions even. It has like a special syntax with like, builders and arrows and whatnot. Which is pretty interesting. I don't\u003C/p>\u003Cp>Speaker 2: know if the\u003C/p>\u003Cp>Speaker 1: voice first 12 one has that in there. But anyways, there's there's, like oh, maybe this that's the one with the question marks there. I don't know. There's there's all sorts of different syntaxes is what I'm trying to say. Oh, here they are drawing with the arrow the the dash arrow arrow.\u003C/p>\u003Cp>That kind of stuff. So what we realized with this sort of initial work that we did on the JSON filtering is that, well, 8, super complicated as you can tell. There's a lot of additional work and a lot of additional logic, which means in turn you're gonna maintain. As always, because the more stuff you add, the harder it becomes to maintain. Right?\u003C/p>\u003Cp>But, the third thing is we're also starting to we also start to wonder like, okay. Instead of, having it as a function style thing in the query parameter, what if we do it more like the fields parameter itself? Right? Where you can just say, like in GraphQL, for example, you could just provide a nested tree that you wanna select instead of having to do it through a filter attribute. And at the same time, we've been working on a new data abstraction engine in the first place that already sort of, like it doesn't necessarily fix the fact that we have to do a lot of stuff ourselves for every database because it's just database specific, but it does it in a way that is designed to have database specific drivers rather than dialect specific overwrites.\u003C/p>\u003Cp>Right? So this is gonna be a bit of a more of a deep dive, but the way the API is set up right now is that everything effectively goes through connects, right? The SQL, what do you call it? SQL query builder that basically everybody and their mom is using. And what that means is that first it just becomes a sort of generic SQL, and then at the very end it's translated for the individual vendors.\u003C/p>\u003Cp>Right? So it's effectively this is a very crude explanation, but it's effectively just doing a find and replace for the quotes, making sure it's, like, the right quote for the right database. And then for some of the databases there's a little bit of additional magic, like for SQLite, you know, for an ALTER TABLE statement there's some magic included there. But the long story short is to add stuff like JSON filtering, it becomes tricky because now it's database specific. Right?\u003C/p>\u003Cp>So we don't really have a way and it was the same with the timestamp, helpers that we did earlier. We don't really have a way to make that agnostic across all of the different database vendors. Right? The second part there is that we know that we wanna support more database vendors over time, not less. So trying to do it in this sort of like make it generic first, add 1 by 1 overwrites to the dialects.\u003C/p>\u003Cp>It doesn't really scale anymore. Right? But end of the versions. A very good point, Tim. Because I think if we go back into the table, we already saw it.\u003C/p>\u003Cp>There's, like, differences between MySQL 5 and MySQL 8 plus, although 5 is now end of life. So that's a whole different discussion. But, we're the same for, you know, Postgres 10 versus 13 and up. So the way we're sort of re architecting that piece is by saying, you know, there is a singular, there's still a singular data entry point, but rather than relying on SQL, it relies on an abstract syntax tree, you know, Veron Design. Just a proprietary data format that explains to the engine what the data looks like that we wanna fetch.\u003C/p>\u003Cp>Right? And then for each of the different vendors, we're gonna have a driver that interprets that command and then just executes it in whatever way is appropriate for that driver. Right? So for a lot of the SQL drivers, we can still share a lot of that SQL magic like we're doing now. But it also means that we can start opening up the doors to other, you know, other data sources and other, JSON specific data sources.\u003C/p>\u003Cp>Right? So one of the reasons there, to keep going on that train of thought, is also because once we started getting super deep into JSON filtering, we also started to realize, like, well, if we implement the JSON filtering like field selection rather than, filtering specific functions, you end up with effectively just drivers for a document data store. Right? Which is very interesting. So with that in mind, we could also start thinking about what does it look like to use something like a DynamoDB or MongoDB or some other sort of key value slash unstructured document style store with the sort of direct to the API.\u003C/p>\u003Cp>Importantly, not treating them as a relational database, but treating them as a document data store, like leaning into the flexibility of a document database rather than trying to force them into a relational structure, right, like we've seen seen in the past and have explicitly avoided. That was a very long train of thought. But what I'm trying to say is, what we're getting at with that is that we've effectively not shelved, but we've sort of put the pause on this particular PR. And instead, focusing now on implementing this sort of JSON selection support directly into this driver based approach. Right?\u003C/p>\u003Cp>Because the one thing we didn't wanna do is add a lot of complexity add more complexity now only to then replace it, you know, in a couple of months with another breaking chain with completely different structure. But we've left open the PR because we definitely don't wanna lose any of work in any of the code because it is being, you know, repurposed repurposed into the new structure. In the chat, there would all be called features, not bugs. That's very true. Any bug in SQL is a feature.\u003C/p>\u003Cp>Speaker 0: Got a question about the specs for the drivers. I believe we do plan to fully spec and document those the driver interfaces, right, for the new architecture?\u003C/p>\u003Cp>Speaker 1: Absolutely. Absolutely. Yes. Yep. I mean, as of right now, it's still very much, you know, in in r and d, so we're not opening the doors quite yet on on building your own, but it is built basically as an extension in mind.\u003C/p>\u003Cp>Right? So we wanna make sure that those things are just do whatever you want as long as you adhere to the spec, you can you can, you know, save and read data from wherever the f you want. But, you know, we're definitely focusing on just feature parity with what we have first, and then expanding the scope there with JSON filtering and some other, you know, additional relationship types. And then, you know,\u003C/p>\u003Cp>Speaker 0: Yeah. Yeah. I love the I love the idea that we're moving towards a an extension driven driver approach. Right? The same way we've done with so many other components of the platform, making it so that it's extensible.\u003C/p>\u003Cp>And it also means that you've got a custom data source. You've got an API. You've got other things. You'd have a spec and be able to build your own driver against some custom data source that you have, and be able to leverage the API and power of the Directus application on top of that. So very exciting very exciting 2024.\u003C/p>\u003Cp>Speaker 2: Absolutely. Wait for the first person, implementing the, Excel sheet data store. I think this will be a a smash hit in Germany. All of the all of the companies love Excel so much. Oh, Maybe maybe The whole finance world rejoices.\u003C/p>\u003Cp>Oh.\u003C/p>\u003Cp>Speaker 1: We should start that as a little competition. Whoever builds the Excel data store first gets a shout out on the website.\u003C/p>\u003Cp>Speaker 2: Oh, you bet. Oh, you bet.\u003C/p>\u003Cp>Speaker 1: A signed certificate of insanity by by me. Love that.\u003C/p>\u003Cp>Speaker 2: The the worst thing is the the very worst thing is that people will actually, like, honestly use it, I'm afraid.\u003C/p>\u003Cp>Speaker 1: It's it's not the using it part that that worries me. It's the relying on part that me. Anyhoo, circling back to, more of the the specifics of JSON filtering as a whole. Right? So just to circle circle back to to a requirements list because we we don't have, you know an RFC for JSON filtering proper we don't really have an RFC for what it could look like in new formats.\u003C/p>\u003Cp>Right? We do know that we want to support it from field selection perspective with that sort of nonstructured data store in mind. We do know that we have to support it as part of filters and sorting and querying and and all of that goods. That being said there is a very interesting difference between JSON objects which is sort of the assumed default that we've been talking about here, and arrays, which is where it gets real complicated real quick. Because one of the main questions or use cases where this is coming from is for fields like tags, right, where you just have a JSON list of individual strings for tags and then how do you search through those.\u003C/p>\u003Cp>Right? But now you're not so much talking about you need to make a nested selection of an adjacent path and then filter against that. Now you have to now search through each item of the the array. Right? So we do have some specific magic going on for one to many's right now like some and none for example to say I want all of the values in my related table to match x y z But we should probably add something along those lines for Jason when it comes to filtering specifically.\u003C/p>\u003Cp>Speaker 2: I think.\u003C/p>\u003Cp>Speaker 1: This is mostly again, for for those who've who've joined us in the past on these live sessions, for Rich, welcome back, the the goal is oftentimes, you know, to really, really diverge to find what are the boundaries of what we can or eventually maybe want to do with this, you know, and then converge back into what is realistic and what does that first MVP look like. This is really that diversion thinking stage. Right? It's like, how how far do we need to go when it comes to filtering on stored values? For example, do you need to be able to say things like, I want all of the JSON objects into an array to have a nest of property author dot agent.\u003C/p>\u003Cp>They all need to be bigger than than 12. Right?\u003C/p>\u003Cp>Speaker 2: I've actually never used, like, field type currying like in Postgres or in the others. So I'm curious. Is there a function of the database that tells you whether or not the stored value is an array or not? Like, is there, like, some database layer check that tells you that? Is that possible?\u003C/p>\u003Cp>Speaker 1: I I think the the realistic answer is we can't assume that there is because we're talking about, you know,\u003C/p>\u003Cp>Speaker 2: good plan. Good plan.\u003C/p>\u003Cp>Speaker 1: We're we're talking about various different database vendors, and we're talking about various different SQL like vendors that, you know, are are sort of SQL inspired, but not fully compliant. Think of, you know, the the I wanna say plan and scale, but they recently added foreign keys. So I think they might not be more compliant than they used to be. But those types of vendors, right, where it's like they they use the SQL syntax for basic querying, but they don't have a full SQL engine behind it because they just implemented the data store differently. So the answer is we don't know nor can know.\u003C/p>\u003Cp>Because we need to build this and design the the specs for this in a way that is sort of agnostic to a data store. Right? Tim was mentioning, you know, we have 3 different pieces of functionality extracting the data in fields, extracting the data from a field, and then using it to filter. And then with the deep filtering against stuff within that JSON blob, filtering inside the j oh, yeah. Yeah.\u003C/p>\u003Cp>Filtering inside of an area with a deep. Yeah. Yeah. Yeah.\u003C/p>\u003Cp>Speaker 2: So\u003C/p>\u003Cp>Speaker 1: So I think, ideally and this is a bit of a a different way of thinking in how we treat the API because it used to be very, you know, tabular data forward first is I think what we're leaning towards now is really treating JSON values f it as if it's just any other table effectively. Right? So we just treat an object as if it's any other item in the database. We treat an array as if it's any other table in database. And therefore, just allow you to use any of the regular query parameters as if it's a table.\u003C/p>\u003Cp>But you get some very interesting usage patterns at that point. Right? Could you consider using JSON schema to type and validate field? Absolutely. There's a very interesting thing, though, when it comes to to JSON and and typing slash validating, is that a lot of people sort of accidentally will start using a document database as a relational database, therefore, completely defeating the point of using a document database.\u003C/p>\u003Cp>Right? And this has been the the main, if not the only argument, that we've had against supporting MongoDB in the past because it has come up before. You know, there have been a couple of feature requests every now and again. But it was always the question of, oh, let's just use MongoDB instead of Postgres. But that really makes no sense if you did pardon my French.\u003C/p>\u003Cp>It makes no sense if you just if you just think about it real. Right? Because the a document data store has a lot of perks. There's, like, a lot of good things about it. But using it as a relational database is just not what it was designed to do best.\u003C/p>\u003Cp>So you're kinda just forcing it to do something it wasn't made for. At which point, it's like just use a SQL database. Right? If you wanna have relational data in a tabular format, use the SQL database. That's what they excel at.\u003C/p>\u003Cp>That's what they're best at. That being said, it's the overlap of the 2. You know? And so overlap of the 2 where it gets really interesting where you know, if you're talking about, things with rich content, like, you have views in an app or pages on the website or something, right, where you have fixed data points, fixed metadata points that you have for everything. You know, you have a title, you have an author, you have a published date, you have some of those pieces, like a status.\u003C/p>\u003Cp>But then you also have rich content which is gonna be, you know, a semi, semi flexible schema. Right? It's when you mix the 2 where I think it gets really, really interesting. But that does also mean that you need to be able to manage and search through and extract the nonstructured part with a semi known schema. That's where it gets tricky.\u003C/p>\u003Cp>Right? So, what made me think about that is the question, you know, consider using a JSON schema to validate the fields. If you're strictly validating against one schema of JSON objects, at that point, are you better off with using JSON or should you just make a couple of columns? Right? Because a many to one, field with a related table with structured columns will most likely perform better than trying to do it with nested objects.\u003C/p>\u003Cp>If, you know, assuming that there's gonna be searching and filtering and and organizing involved. Another question from the chat here was, Postgres allows for date ranges, which is effectively a JSON array. Somebody built a custom date range interface for this but cannot filter against it. That's the question is that something that will be supported by this pr or would that be something else? Yep.\u003C/p>\u003Cp>That's basically exactly it. You know, you have any sort of arbitrary JSON value you need to be able to manage and search through it. It is a table document for the record, though. Each record in a collection have significantly different content structure. Yes.\u003C/p>\u003Cp>That is a very good point, which is why the JSON schema again becomes interesting. Right? Because if you have a column that you want to be the same schema for every single row in your database, in your table, then relying on, you know, adjacent schema for validation makes a lot of sense because you want every one of those to be the same. At that point, you know, what becomes the benefit of using JSON over just columns? Right?\u003C/p>\u003Cp>That those those are sort of the questions that we need to, ask ourselves. Because the other one is like, if you have the because because the nice thing about the JSON thing is that anything could go in there. That's kind of the point. Right? It's like an unstructured data type.\u003C/p>\u003Cp>So what if you want everything to be different? Or maybe you want it to be one of 5 known different schemas, right, instead of just the same fixed object. I guess with an adjacent schema, you have union types, if I'm not mistaken. But food for thought. It's an interesting one.\u003C/p>\u003Cp>But it it does, you know, it does raise a different question that we need to write. What about validation? Right? Because, like, we have validation rules for, for regular columns now where you can say, you know, a number needs to be up and greater than something. For JSON fields specifically, we need to come up with something.\u003C/p>\u003Cp>Right? Using a JSON schema could be very interesting. Maybe a JSON schema for the whole record instead of just the JSON thing field could be interesting. Maybe both. Maybe it's a nested.\u003C/p>\u003Cp>Here's another another thing. Let's see what was the other chat related things on the same click. Somebody else, asked, I'd have missed this, but the idea is to integrate directives as existing filters at dynamic variables, etcetera, or would there be a new JSON specific functions? So that is a great question and kind of the the, instigator of rehashing this chat because we had this feature request. We sort of we're looking at it through the lens of let's make a specific JSON function like we have the others, and just implement that.\u003C/p>\u003Cp>Right? And then Tim went ahead and did it. Kudos. A tremendous amount of effort. But we also really started to, then, you know, it's it's kinda what we talked about with the the data abstraction piece just now.\u003C/p>\u003Cp>We started to realize that it might be way more powerful to try to treat it as an item rather than treat it as a value. So you unlock all of the other query parameters against the value. That answers. It gets it gets a little bit theoretical quick here.\u003C/p>\u003Cp>Speaker 0: Soon as you use\u003C/p>\u003Cp>Speaker 1: it relationally, it becomes even harder to maintain. Good point. Good point. Just started using as a MongoDB as a replacement for Redis for for a project that doesn't use Directis they are crypto so their relational is based on wallets. Makes sense You know, if you think about that use case, you have a semi structured data.\u003C/p>\u003Cp>You know roughly what goes into a wallet, but there's a lot of optional, fields oftentimes. Depends on the implementation, of course. But one thing you do know is that you have a fixed primary key that you can use for some relationships. Big sport of Jason's schema. Everywhere.\u003C/p>\u003Cp>Just for the spec Simpler, Tidebox for the win. I that used to be my go to and then a lot of others in in my team sort of using Zod, and I kind of have been converted to the\u003C/p>\u003Cp>Speaker 2: The inference is pretty\u003C/p>\u003Cp>Speaker 1: is not true here.\u003C/p>\u003Cp>Speaker 0: Let's see what\u003C/p>\u003Cp>Speaker 1: You kinda want to know that oh, it disappeared. Where it is? Oh, you kinda wanna know that a list of tags is always a list of strings or that an object matches a specific schema. Depends. I'd I'd say, generally, yes, but also really depends.\u003C/p>\u003Cp>For example, in to give a system thing as an exam right? For interface options, we don't know ahead of time what's going in there. Right? It's up to the interface to figure out. It's just anything.\u003C/p>\u003Cp>It's basically just a blank store for an interface to do some sort of options, but it really doesn't matter what the format is, what's in it, etcetera. Somebody shared p g adjacent schema, schema validation for postgres specifically. It's where it gets real tricky. Solution relied on the different filter syntax. JSON pass number to XPath.\u003C/p>\u003Cp>Yeah. Yep. Exactly. I think the, the the JSON schema example is is a good example of the the added sort of complexity that we're putting ourselves in here on purpose, which is that we're really really aggressively want this to be a standard in the API that you can use no matter what the data source is. And then it just depends on the data source how performant it becomes.\u003C/p>\u003Cp>Right? But I'd really, really would like to prevent ending up with, you know, a long table in the docs that says, can you use JSON filter? Yes. No. No.\u003C/p>\u003Cp>No. Yes. Yes. Yes. No.\u003C/p>\u003Cp>Yes. Yes. Yes. No. For for the different drivers, especially if those drivers are are third party maintained.\u003C/p>\u003Cp>You know, there's it's gonna be incredibly annoying. It does mean that for some of the data source, we'll definitely have to, we'll definitely have to, what's the right word, add add fallback logic and do a lot of that magic on the director side of things rather than on the data store but so be it You know? I I think that is a a trade off worth having, as long as these drivers can handle it themselves. Because Yeah. Right.\u003C/p>\u003Cp>Speaker 2: We're fine. Scenario. Go ahead. Sorry. The the delay.\u003C/p>\u003Cp>No. It was, just for Brian's message, which was, the discussion point, my mind towards use cases like page builders, where I wouldn't need to create a ton of separate tables. That's true. And this is exactly the use case where I, in the past have used. You know, just sometimes if you very quickly want to throw together a component, but you don't really don't wanna create, like, different relationships and whatever.\u003C/p>\u003Cp>So you just quickly make, like, an h ref with the label and slap it together as adjacent, for example, very quickly, you know. That's that's a very nice use case for that. Yeah. Very quickly, very easy.\u003C/p>\u003Cp>Speaker 1: Mhmm. For sure. And I\u003C/p>\u003Cp>Speaker 2: I agree.\u003C/p>\u003Cp>Speaker 1: Another interesting thing that he's mentioning there is saying that it would be better served by a NoSQL database. Right? That's where the interesting discussion really starts. Because if you're talking about, you know, a page builder for a website, then the pages themselves, just like what is the route? What is the title?\u003C/p>\u003Cp>What is some of the metadata? I'd argue that's probably better for a SQL database. Right? Because you're talking about structured data that you wanna query through on a column by column basis. You wanna say get all articles from, you know, January 2024, for example.\u003C/p>\u003Cp>That is gonna be faster in, you know, a relational database because it has, you know, structured data with known types and you could search through them efficiently. But the content part of a page, absolutely, it makes a lot of sense to have that as a page builder. Right? Because you have semi structured data. You have an array with 1 or more or 0 or more, I guess, you know, blocks of a known type.\u003C/p>\u003Cp>So that's where that JSON validation with schema comes in potentially. You know? And then that's the data is semi structured. So you have objects of, like, x different types, and then that has an array of those things. Yeah.\u003C/p>\u003Cp>So that makes a ton of sense. But I think the real power is the combination of the 2. Because if you were to try to do all of those pages in MongoDB, now you have to trade off of the sort of filtering performance and sort of the searchability aspect of it. But on the SQL side right now, you have the penalty of not having that unstructuredness of the data. Right?\u003C/p>\u003Cp>So right now, we would rely on any to any's for that type of use case, which has its own benefits around, you know, the searchability and the joinability. But, you know, if you're on pages where you don't really have to reuse, sections, for example, then, yeah, I agree. You're doing it as a JSON object for for a page builder makes a lot of sense. Right? But implementing it in a way where you get both is really the\u003C/p>\u003Cp>Speaker 2: Oh, this this is why Brian, the father of, agent c OS, He he felt that pain probably, so he came up with this. Yeah. Yeah. But I agree wholeheartedly. Like, this came up exactly when I wanted to do then.\u003C/p>\u003Cp>If you have, like, one off components that you don't really, you know, they don't have something to do with other stuff or you want to get some data in, it's very, very, very neat. The repeater interface is very useful for that.\u003C/p>\u003Cp>Speaker 1: Now there's one additional topic that we haven't touched on that I think we can easily spend 15 minutes on. And Brian is hinting at it right now, actually. Relationships. Relationships is where it gets real tricky. Right?\u003C/p>\u003Cp>Because right now, we know that's, article dot author is a foreign key to author's table. Right? So that that metadata is known. We know that ahead of time. So therefore, we can do things like give me everything, nest everything, nest everything, you know, start up start dot star whatever.\u003C/p>\u003Cp>And it knows what to nest because it knows what the relationships are. Right? When you're in within a JSON document or an area of JSON documents, there's really no guarantee that something is an ID or there's no real knowledge of what that path is and where it points. Right? So once you want to start nesting, data like that, it becomes tricky, tricky, tricky.\u003C/p>\u003Cp>Right? So within a a MongoDB context, if I'm not mistaken, it's like a MongoDB ID is always globally unique. Right? Right? So as soon as you have a nested data of that, I what what did they call it again?\u003C/p>\u003Cp>There was, like, a Mongo ID special type. I forgot what it's what it's called. Object ID is I think what they call the type. Anyways, when it encounters a value of type object ID, it it can assume that it's a globally unique ID and therefore knows what the what document to fetch. But in a sort of hybrid model, you don't necessarily have that luxury.\u003C/p>\u003Cp>Right? Because you can have a nested, categories array in your adjacent object that just says 123 with the assumption that you're talking about rows 123 in your categories table. Right? Because you're mixing concepts, because there's no such thing as globally unique IDs in a relational database.\u003C/p>\u003Cp>Speaker 2: Kind of a design. I'm already imagining some type of custom format with, like, a dollar sign, direct to dot one or something, and then we have to translate it. And oh, no. It's a whole repertoire. We could do this.\u003C/p>\u003Cp>Speaker 1: The same way as the chat, apparently. Somebody is saying direct us could prefix it.\u003C/p>\u003Cp>Speaker 2: That's what I meant. Oh, yeah.\u003C/p>\u003Cp>Speaker 1: We could. We could. But it does mean that we would have to make the data in your tables proprietary, which is something that I'm personally not a fan of. Right? It's like the system tables are one thing, because, of course, you need to have some metadata saved somewhere and we need, you know, a place to store that.\u003C/p>\u003Cp>But I really, really badly, desperately do not want to introduce any sort of direct to specific proprietary nonsense into your own database, in the user tables rather. So that's a tricky one.\u003C/p>\u003Cp>Speaker 2: Right? So If we would do that, then we would probably also have to provide a way to extract the data, and it's it's more and more patches on top of patches. I don't think we wanna go down that road.\u003C/p>\u003Cp>Speaker 1: The question really becomes like, how do you pull together a join? Right? And it's the same the same reason we haven't really, because Brian said relational repeater. Right? The reason why our repeater interface currently is not relational is because of this exact reason.\u003C/p>\u003Cp>It's like, how do we store the information of, you know, what field is relational to what? And the other tricky thing is, you know, without some real clever engineering from John and Nicklaus, most likely, There's no guaranteed way you can really do a join, based on the nested JSON value. Like some databases would, some databases don't. You know, it's the same sort of story. Right?\u003C/p>\u003Cp>So it becomes a performance nightmare. But what are some of our options there? Right? Just thinking out loud. One would be that we have some sort of, kinda like direct directors relations.\u003C/p>\u003Cp>Right? Where we're saying, well, if your JSON object has a path called, I don't know, article dot author, it we're assuming it's a foreign key, but that is always gonna be, you know, you can't really guarantee that. Right? An additional option would be to allow, you know, the end user to sort of pass the join information, right, manually through the API, where instead of saying author dot name where we know that author is a relationship, maybe there's some sort of syntax where you can just say author joins on table dot column, dot name. I don't know.\u003C/p>\u003Cp>Right? So you can pass it yourself. Can we just say we don't allow relations in JSON? I've I've tried that in the past and I think the answer is no. No.\u003C/p>\u003Cp>I I'm I'm afraid the answer is no for that. Because because that is that's kind of what, you know, that's the situation we're in now. Or, like, we have a relate we have a repeater, and people continuously ask, can we make it relational? And I continuously answer, how is that any different from a one to many? And then oftentimes, you know, we're just sort of in a sort of stalemate, which is, well, it's not JSON, but it does do what it needed to do.\u003C/p>\u003Cp>So we're good enough. Right? But I think it's fair to say that one of the design requirements of the system would be that we need to have some sort of way where you can relate data from a key that is inside of a JSON document.\u003C/p>\u003Cp>Speaker 2: Yeah. I assume we would have\u003C/p>\u003Cp>Speaker 0: to keep\u003C/p>\u003Cp>Speaker 2: track of it. We've\u003C/p>\u003Cp>Speaker 0: talked about this for the editor JS. Right? And or WYSIWYG being able to have great relational data structure that's stored inside there. There's actually a relationship to another\u003C/p>\u003Cp>Speaker 2: Right.\u003C/p>\u003Cp>Speaker 0: This object. Right? Another direct to side of them. So we we've we are thinking about this. We have some ideas around this.\u003C/p>\u003Cp>I think it's separate from this particular request. I think right now, this request is primarily around filtering and searching and finding\u003C/p>\u003Cp>Speaker 1: It's true. Yeah. Yeah. Because because for the record, this really quickly turned into how to just properly do JSON indirect this rather than how to filter through an object. All all very much, you can see to that.\u003C/p>\u003Cp>Speaker 0: Still important. It's it's part of the the divergence, the comeback to convergence. But, I just as as you guys have continued to talk about this, I think there there is a separate kind of feature function likely for relationals versus the ability to filter and just find stuff inside these objects and do it really and performantly.\u003C/p>\u003Cp>Speaker 1: Yeah. The the WYSIWYG one is an interesting example. That's that's a good point because this everything that we've been discussing so far is basically gonna be the underlying engine slash foundational stuff for that type of use case. Right? Where in a in an editor JS type of environment, the line of text kinda like in like a notion docket, for for those unaware of editor JS.\u003C/p>\u003Cp>Each line of text is its own, you know, block effectively, and you have blocks of different types. But then a block could be a relationship elsewhere. Right? Which is a great example of this. Like, how do you know what that relationship is?\u003C/p>\u003Cp>In I'm pretty sure in in, you know, a Notion like environment or an Energy. Js type environment where you have, you know, a semi structured data, part of the solution there is that that joint information could be in the block, right, where you say you have an image block. And because you have an image block, you now know to look at images for looking up the related value. Right? But, again, that depends on the schema that is in your JSON field.\u003C/p>\u003Cp>And if we were to make that a requirement where we're saying, well, there's a there's a a god. Way to go, Brian. If we if we're saying that there that has to be in the JSON field and now we're making the form of proprietary again. Right? Because now we're requiring your JSON object to adhere to a certain spec.\u003C/p>\u003Cp>We designed just to be able to do relationships. Tricky. For a second, I was I thought you were gonna write down, this will be tricky. Rest rest assured. This will be very difficult.\u003C/p>\u003Cp>Is there not a normal standard for that already? Yeah. You'd hope so, but the answer is no.\u003C/p>\u003Cp>Speaker 0: We gotta You know, there are some other CMS vendors that do this, but, again, they've got more, I think, generally well defined kind of hearts hardened structures. The ability to be agnostic is where this becomes very difficult.\u003C/p>\u003Cp>Speaker 1: Yeah. No. That's a great point because we\u003C/p>\u003Cp>Speaker 0: to say, this is the data model you must use. Therefore, this is I I can therefore rely on the fact that my structures are gonna match. But I think, potentially, with some of the discussion we had on the schema piece, you know, as part of this entire discussion here, if you were able to say, I am predefining schema. I know what that is, and then I wanna have enforcement validation and understanding that that's there. I think you we could ag you know, the agnosticity is you define the schema or we define a schema, but it's generic in the sense of you're not required to have it.\u003C/p>\u003Cp>You have a JSON field that's unstructured and doesn't have schema. But if you choose to implement that, then you are actually then getting the benefits of now I can I can kind of quote guarantee as much as you can guarantee in a JSON world? And I know what my data structure is, and I know how to how to interact with that event.\u003C/p>\u003Cp>Speaker 2: Yeah. To be frank with this, it's just very, you know, very, very difficult. I mean, we we could, you know, like, just, willy nilly, we could keep track of, some keys in a new table that says, hey. This relates to that, like, similar to, like, relations, like we do it right now. And, well, try to keep that instinct.\u003C/p>\u003Cp>It's well,\u003C/p>\u003Cp>Speaker 1: So when you're talking about the under, other vendor use case, right, I think for the majority there, it's basically around the idea that you have a globally unique ID. Right? So it's very document database first approach. If you've ever created a so we we use Notion a lot. Right?\u003C/p>\u003Cp>So if you ever create a Notion page that links to another Notion page, that is just a globally unique ID. So therefore, you can nest it however you want and it knows because everything is a page at all times and every page has a globally unique ID. So therefore, that sort of relationship lookup kind of solves itself. Right? Because you don't need to know what collection or what table to look at to find the item because it's all globally unique.\u003C/p>\u003Cp>Right? The difficulty here lies in the that hybrid model where you want to nest a relational record inside of a document, which itself might be, you know, related from a relational record relational row. Oh, do we like to make things difficult? But that's why it's cool. Let's see.\u003C/p>\u003Cp>There is a portable text spec. Absolutely. Which, again, I think it would be great to have a some sort of, you know, portable text interface or, an extension that handles that specific format. But I I it would be a shame if if this everything that we're talking about only works if you're in a specific format. Right?\u003C/p>\u003Cp>Because who are we to say what the right format is?\u003C/p>\u003Cp>Speaker 2: I agree. I just looked at the, audible text one. Yeah. It look looks very, very similar to how everybody else does it. You know?\u003C/p>\u003Cp>You have some things. You define your type, and then you have some keys depending on that type. Great.\u003C/p>\u003Cp>Speaker 1: Cool. Alright. We're quickly reaching the top of the hour here. It was it was a good idea to only focus on one topic for these sessions. Just based on prior experience, it always turns into this should be quick and then you you talk about it for an hour.\u003C/p>\u003Cp>Just to give a chance to chat, any other thoughts, questions, concerns, ideas, shout outs. I wanna say hi to the family at home. This is the time.\u003C/p>\u003Cp>Speaker 2: Or when they start typing.\u003C/p>\u003Cp>Speaker 1: Everyone is typing. Config is code. Uh-oh. I'm pretty sure we have a separate one of these dedicated to that again coming up. Ship it.\u003C/p>\u003Cp>Speaker 2: Ship it? I'm not gonna I'm not gonna say it right now.\u003C/p>\u003Cp>Speaker 1: Let's go. So for 20 minutes for brings everyone here. Same. Yeah. The next one's gonna be Comic It's Code.\u003C/p>\u003Cp>Speaker 2: Cool. Cool. Cool. Cool.\u003C/p>\u003Cp>Speaker 1: Cool. So make sure to come back for that one, saucy, saucy. Cool. Well, if there's no other questions, thoughts, feelings, or concerns, let's wrap this one up. It's Brian just said the conversation about config as code is is in 2 weeks, not the release.\u003C/p>\u003Cp>I think this is a very, very, very important\u003C/p>\u003Cp>Speaker 0: Thank you, Brian.\u003C/p>\u003Cp>Speaker 1: Thank you, Brian.\u003C/p>\u003Cp>Speaker 2: It's Android. So it's it's imported immediately. Go now. What have we done?\u003C/p>\u003Cp>Speaker 1: Cool. Well, all that being said, everybody. Thank you so much for joining us here live. Thank you so much for watching this at home. If you're seeing it on Directus TV, for the people live here, if you don't know what that is, check it out.\u003C/p>\u003Cp>Directus dot a 0/ tv. I think I got that right. Right? It'll be up in about a week's time. But for now, I wanna say thank you all.\u003C/p>\u003Cp>Good luck in Godspeed. And we'll see you in 2 weeks.\u003C/p>","Welcome, everyone. Happy 2024. We're excited for a new year. We're gonna try out a new well, we've been we've been playing around with this request for views format for a little while, but we're gonna we're gonna try out just covering a specific feature, talking through some details, making sure that we have a full specification on it, and getting additional community feedback, as needed. Today's topic will be JSON object filtering. It's been a it's a very, very popular request that we see quite frequently, and we would love to ensure that we solve this problem correctly and get it working for the databases that support it. I think one of the key issues that we've run into we've done a lot of development work on this, but what we run into is various database vendors support this differently. You fix it to support that thing. It breaks something else. We spent a lot of time kind of iterating back and forth on this feature, and I'll let Rai talk about some of that. But I mean, fundamentally, we we know that this is important. We consider it kind of a critical road map item, and that's the reason we're gonna talk in detail about it today. Absolutely. Well, thank you for that. Yeah. And as you can see, I was the one who opened this feature request conveniently with no details whatsoever. I basically just say, hey, man. I wanna be able to filter in JSON objects. Good luck. And then everybody was like, yep. Me too. However, you know, the this this was done way before we had that RFC format, so the the the details are lacking. Let's let's call it that. So before we dive in too deeply, you know, Daniel, I'm just gonna throw you under the bus here. You wanna walk us through what what even is JSON filtering in the first place? JSON filtering can be quite useful if you store JSON inside of your database, and you need to check some field inside of that JSON in your database. Like, we said in the beginning, right, not every database supports this as of right now, which forces us or will force us to, you know, do some little Directus magic as usual. But more and more databases kinda jump on the train, which is pretty neat. I think as what was it? SQLite very recently also announced that they have JSON b support, I think. I hope I'm not miss remembering. But, yeah, can be quite useful. If you have stored JSON, then you can filter on fields inside of that JSON. That's very useful. And I think as as Kevin points out, actually, a couple of our default interface configuration our field configurations actually store in JSON by default. You can change them in most cases, but and, currently, that's the recommendation. So off the support side of things currently, for those of you listening, if you use the CSV format instead, on the database field setting side, you can then filter through the application in the API on those fields. But JSON is a little bit nicer structured format, so the reason for the request. Yeah. And then the other the other big sort of elephant in the room there, of course, is that a lot of systems are utilizing and or could be utilizing more of a document style structure rather than, you know, a tabular style data structure. Especially, you know, when you have flexible schemas or unknown, you know, data structures ahead of time or semi semi structured data. Think about, you know, blocks on a page or something. You know, you're talking about sort of rich data that may or may not be structured like a table. So, therefore, you know, storing JSON in a Postgres database or another SQL database can give you some of that document magic without having to switch over completely to a document database. So there's a lot of a lot of benefits to having this. Now that being said, it also comes with a ton of complexities. So in my original feature request I was really thinking about it sort of as a filter against the data. Right? So similar to how we have, some functions to run against date values. I don't know if you've seen those before, but we have things like extract the year from a timestamp as a function. I was thinking about it the same way in my original feature request. Right? So I was thinking maybe we can have just like you would be able to do, like, year time stamps equals 2024, you could do something like, I don't know, Jason, name of the field, and then some sort of identifier string to select something from that field and then run filters against it, against that value that you've now selected. Right? Similarly you'd be able to use that in fields or in sort or other pieces like that And we actually put a lot of work in that already, and by we, I mean Tim who's in the chat, and I'm definitely gonna put him on stage and put him in the spotlight. Jonathan, if you wanna pull that up real quick, it might actually be fun to take a quick scroll through. Also, as a way to answer that, do all DBs even support it? Because there's a wonderful table at the top of that pool request. If you wanna pull up the, don't bring him up. We're recording. He's he's a little camera shy, but we can we can figure it out. You know the PR off the top of your head, or do I just need to go find it? Oh, just just open up pull requests, and if you search for Jason, it should be the only one that's there. GitHub pull requests. We've left it open intentionally. We'll we'll circle back to that later how we're handling now. But if you just probably all the way at the bottom is is a little older. Yep. There it is. Alright. There's your matrix. Right. So in this PR, we basically took a swing at implementing that, you know, JSON filtering the way it was described in that discussion. And by described, I mean, vaguely hinted at, because the description was a little poor. But we did implement it in that way, and it does actually work. So we do have, you know, queries for a little different databases. But as you can see in this table to the Chet's point earlier, not everything is supported everywhere, which becomes tricky immediately. Right? Because how do you then document it? Now it's gonna be database different. So there has been, you know, implemented some fallback support so you can see the difference in that green check versus the, that sort of Unicode check I guess. You you can see that for a lot of these things we're actually you know having to do some direct us magic to to make that work against the database which is not necessarily gonna be the most performant or the what's the right word? The the the quote, unquote right way to do it. Right? It's a blue check mark. Oh, if you're on Windows, just pretend. If you're on Linux or Linux, just Linux, just pretend. The check marks are green. Anyways, while building this, if you might wanna pull up the file section of this PR, Jonathan, I think it's a fun fun scroll through. This if we go all the way to the top, there's a tab. Files changed. 2000 editions. Oh my god. Yeah. There's there's only a 1,000 lines across 50 files. The long the long story short is that in the database helpers, if you see in that left hand sidebar, you know, we have to add all of the additional queries for JSON filtering ourselves for a little different database types. Sort of hard coded in, You see them here in the dialects if you just click one of those. It doesn't really matter which one. So all of those sort of you can see them here. You know, we have a JSON extract for MariaDB that may or may not exist across the other database vendors. Right? So it's not a SQL standard, which makes this a heck of a lot more complicated than you'd think. It's because every database does it differently. I believe it was Postgres that doesn't rely on functions even. It has like a special syntax with like, builders and arrows and whatnot. Which is pretty interesting. I don't know if the voice first 12 one has that in there. But anyways, there's there's, like oh, maybe this that's the one with the question marks there. I don't know. There's there's all sorts of different syntaxes is what I'm trying to say. Oh, here they are drawing with the arrow the the dash arrow arrow. That kind of stuff. So what we realized with this sort of initial work that we did on the JSON filtering is that, well, 8, super complicated as you can tell. There's a lot of additional work and a lot of additional logic, which means in turn you're gonna maintain. As always, because the more stuff you add, the harder it becomes to maintain. Right? But, the third thing is we're also starting to we also start to wonder like, okay. Instead of, having it as a function style thing in the query parameter, what if we do it more like the fields parameter itself? Right? Where you can just say, like in GraphQL, for example, you could just provide a nested tree that you wanna select instead of having to do it through a filter attribute. And at the same time, we've been working on a new data abstraction engine in the first place that already sort of, like it doesn't necessarily fix the fact that we have to do a lot of stuff ourselves for every database because it's just database specific, but it does it in a way that is designed to have database specific drivers rather than dialect specific overwrites. Right? So this is gonna be a bit of a more of a deep dive, but the way the API is set up right now is that everything effectively goes through connects, right? The SQL, what do you call it? SQL query builder that basically everybody and their mom is using. And what that means is that first it just becomes a sort of generic SQL, and then at the very end it's translated for the individual vendors. Right? So it's effectively this is a very crude explanation, but it's effectively just doing a find and replace for the quotes, making sure it's, like, the right quote for the right database. And then for some of the databases there's a little bit of additional magic, like for SQLite, you know, for an ALTER TABLE statement there's some magic included there. But the long story short is to add stuff like JSON filtering, it becomes tricky because now it's database specific. Right? So we don't really have a way and it was the same with the timestamp, helpers that we did earlier. We don't really have a way to make that agnostic across all of the different database vendors. Right? The second part there is that we know that we wanna support more database vendors over time, not less. So trying to do it in this sort of like make it generic first, add 1 by 1 overwrites to the dialects. It doesn't really scale anymore. Right? But end of the versions. A very good point, Tim. Because I think if we go back into the table, we already saw it. There's, like, differences between MySQL 5 and MySQL 8 plus, although 5 is now end of life. So that's a whole different discussion. But, we're the same for, you know, Postgres 10 versus 13 and up. So the way we're sort of re architecting that piece is by saying, you know, there is a singular, there's still a singular data entry point, but rather than relying on SQL, it relies on an abstract syntax tree, you know, Veron Design. Just a proprietary data format that explains to the engine what the data looks like that we wanna fetch. Right? And then for each of the different vendors, we're gonna have a driver that interprets that command and then just executes it in whatever way is appropriate for that driver. Right? So for a lot of the SQL drivers, we can still share a lot of that SQL magic like we're doing now. But it also means that we can start opening up the doors to other, you know, other data sources and other, JSON specific data sources. Right? So one of the reasons there, to keep going on that train of thought, is also because once we started getting super deep into JSON filtering, we also started to realize, like, well, if we implement the JSON filtering like field selection rather than, filtering specific functions, you end up with effectively just drivers for a document data store. Right? Which is very interesting. So with that in mind, we could also start thinking about what does it look like to use something like a DynamoDB or MongoDB or some other sort of key value slash unstructured document style store with the sort of direct to the API. Importantly, not treating them as a relational database, but treating them as a document data store, like leaning into the flexibility of a document database rather than trying to force them into a relational structure, right, like we've seen seen in the past and have explicitly avoided. That was a very long train of thought. But what I'm trying to say is, what we're getting at with that is that we've effectively not shelved, but we've sort of put the pause on this particular PR. And instead, focusing now on implementing this sort of JSON selection support directly into this driver based approach. Right? Because the one thing we didn't wanna do is add a lot of complexity add more complexity now only to then replace it, you know, in a couple of months with another breaking chain with completely different structure. But we've left open the PR because we definitely don't wanna lose any of work in any of the code because it is being, you know, repurposed repurposed into the new structure. In the chat, there would all be called features, not bugs. That's very true. Any bug in SQL is a feature. Got a question about the specs for the drivers. I believe we do plan to fully spec and document those the driver interfaces, right, for the new architecture? Absolutely. Absolutely. Yes. Yep. I mean, as of right now, it's still very much, you know, in in r and d, so we're not opening the doors quite yet on on building your own, but it is built basically as an extension in mind. Right? So we wanna make sure that those things are just do whatever you want as long as you adhere to the spec, you can you can, you know, save and read data from wherever the f you want. But, you know, we're definitely focusing on just feature parity with what we have first, and then expanding the scope there with JSON filtering and some other, you know, additional relationship types. And then, you know, Yeah. Yeah. I love the I love the idea that we're moving towards a an extension driven driver approach. Right? The same way we've done with so many other components of the platform, making it so that it's extensible. And it also means that you've got a custom data source. You've got an API. You've got other things. You'd have a spec and be able to build your own driver against some custom data source that you have, and be able to leverage the API and power of the Directus application on top of that. So very exciting very exciting 2024. Absolutely. Wait for the first person, implementing the, Excel sheet data store. I think this will be a a smash hit in Germany. All of the all of the companies love Excel so much. Oh, Maybe maybe The whole finance world rejoices. Oh. We should start that as a little competition. Whoever builds the Excel data store first gets a shout out on the website. Oh, you bet. Oh, you bet. A signed certificate of insanity by by me. Love that. The the worst thing is the the very worst thing is that people will actually, like, honestly use it, I'm afraid. It's it's not the using it part that that worries me. It's the relying on part that me. Anyhoo, circling back to, more of the the specifics of JSON filtering as a whole. Right? So just to circle circle back to to a requirements list because we we don't have, you know an RFC for JSON filtering proper we don't really have an RFC for what it could look like in new formats. Right? We do know that we want to support it from field selection perspective with that sort of nonstructured data store in mind. We do know that we have to support it as part of filters and sorting and querying and and all of that goods. That being said there is a very interesting difference between JSON objects which is sort of the assumed default that we've been talking about here, and arrays, which is where it gets real complicated real quick. Because one of the main questions or use cases where this is coming from is for fields like tags, right, where you just have a JSON list of individual strings for tags and then how do you search through those. Right? But now you're not so much talking about you need to make a nested selection of an adjacent path and then filter against that. Now you have to now search through each item of the the array. Right? So we do have some specific magic going on for one to many's right now like some and none for example to say I want all of the values in my related table to match x y z But we should probably add something along those lines for Jason when it comes to filtering specifically. I think. This is mostly again, for for those who've who've joined us in the past on these live sessions, for Rich, welcome back, the the goal is oftentimes, you know, to really, really diverge to find what are the boundaries of what we can or eventually maybe want to do with this, you know, and then converge back into what is realistic and what does that first MVP look like. This is really that diversion thinking stage. Right? It's like, how how far do we need to go when it comes to filtering on stored values? For example, do you need to be able to say things like, I want all of the JSON objects into an array to have a nest of property author dot agent. They all need to be bigger than than 12. Right? I've actually never used, like, field type currying like in Postgres or in the others. So I'm curious. Is there a function of the database that tells you whether or not the stored value is an array or not? Like, is there, like, some database layer check that tells you that? Is that possible? I I think the the realistic answer is we can't assume that there is because we're talking about, you know, good plan. Good plan. We're we're talking about various different database vendors, and we're talking about various different SQL like vendors that, you know, are are sort of SQL inspired, but not fully compliant. Think of, you know, the the I wanna say plan and scale, but they recently added foreign keys. So I think they might not be more compliant than they used to be. But those types of vendors, right, where it's like they they use the SQL syntax for basic querying, but they don't have a full SQL engine behind it because they just implemented the data store differently. So the answer is we don't know nor can know. Because we need to build this and design the the specs for this in a way that is sort of agnostic to a data store. Right? Tim was mentioning, you know, we have 3 different pieces of functionality extracting the data in fields, extracting the data from a field, and then using it to filter. And then with the deep filtering against stuff within that JSON blob, filtering inside the j oh, yeah. Yeah. Filtering inside of an area with a deep. Yeah. Yeah. Yeah. So So I think, ideally and this is a bit of a a different way of thinking in how we treat the API because it used to be very, you know, tabular data forward first is I think what we're leaning towards now is really treating JSON values f it as if it's just any other table effectively. Right? So we just treat an object as if it's any other item in the database. We treat an array as if it's any other table in database. And therefore, just allow you to use any of the regular query parameters as if it's a table. But you get some very interesting usage patterns at that point. Right? Could you consider using JSON schema to type and validate field? Absolutely. There's a very interesting thing, though, when it comes to to JSON and and typing slash validating, is that a lot of people sort of accidentally will start using a document database as a relational database, therefore, completely defeating the point of using a document database. Right? And this has been the the main, if not the only argument, that we've had against supporting MongoDB in the past because it has come up before. You know, there have been a couple of feature requests every now and again. But it was always the question of, oh, let's just use MongoDB instead of Postgres. But that really makes no sense if you did pardon my French. It makes no sense if you just if you just think about it real. Right? Because the a document data store has a lot of perks. There's, like, a lot of good things about it. But using it as a relational database is just not what it was designed to do best. So you're kinda just forcing it to do something it wasn't made for. At which point, it's like just use a SQL database. Right? If you wanna have relational data in a tabular format, use the SQL database. That's what they excel at. That's what they're best at. That being said, it's the overlap of the 2. You know? And so overlap of the 2 where it gets really interesting where you know, if you're talking about, things with rich content, like, you have views in an app or pages on the website or something, right, where you have fixed data points, fixed metadata points that you have for everything. You know, you have a title, you have an author, you have a published date, you have some of those pieces, like a status. But then you also have rich content which is gonna be, you know, a semi, semi flexible schema. Right? It's when you mix the 2 where I think it gets really, really interesting. But that does also mean that you need to be able to manage and search through and extract the nonstructured part with a semi known schema. That's where it gets tricky. Right? So, what made me think about that is the question, you know, consider using a JSON schema to validate the fields. If you're strictly validating against one schema of JSON objects, at that point, are you better off with using JSON or should you just make a couple of columns? Right? Because a many to one, field with a related table with structured columns will most likely perform better than trying to do it with nested objects. If, you know, assuming that there's gonna be searching and filtering and and organizing involved. Another question from the chat here was, Postgres allows for date ranges, which is effectively a JSON array. Somebody built a custom date range interface for this but cannot filter against it. That's the question is that something that will be supported by this pr or would that be something else? Yep. That's basically exactly it. You know, you have any sort of arbitrary JSON value you need to be able to manage and search through it. It is a table document for the record, though. Each record in a collection have significantly different content structure. Yes. That is a very good point, which is why the JSON schema again becomes interesting. Right? Because if you have a column that you want to be the same schema for every single row in your database, in your table, then relying on, you know, adjacent schema for validation makes a lot of sense because you want every one of those to be the same. At that point, you know, what becomes the benefit of using JSON over just columns? Right? That those those are sort of the questions that we need to, ask ourselves. Because the other one is like, if you have the because because the nice thing about the JSON thing is that anything could go in there. That's kind of the point. Right? It's like an unstructured data type. So what if you want everything to be different? Or maybe you want it to be one of 5 known different schemas, right, instead of just the same fixed object. I guess with an adjacent schema, you have union types, if I'm not mistaken. But food for thought. It's an interesting one. But it it does, you know, it does raise a different question that we need to write. What about validation? Right? Because, like, we have validation rules for, for regular columns now where you can say, you know, a number needs to be up and greater than something. For JSON fields specifically, we need to come up with something. Right? Using a JSON schema could be very interesting. Maybe a JSON schema for the whole record instead of just the JSON thing field could be interesting. Maybe both. Maybe it's a nested. Here's another another thing. Let's see what was the other chat related things on the same click. Somebody else, asked, I'd have missed this, but the idea is to integrate directives as existing filters at dynamic variables, etcetera, or would there be a new JSON specific functions? So that is a great question and kind of the the, instigator of rehashing this chat because we had this feature request. We sort of we're looking at it through the lens of let's make a specific JSON function like we have the others, and just implement that. Right? And then Tim went ahead and did it. Kudos. A tremendous amount of effort. But we also really started to, then, you know, it's it's kinda what we talked about with the the data abstraction piece just now. We started to realize that it might be way more powerful to try to treat it as an item rather than treat it as a value. So you unlock all of the other query parameters against the value. That answers. It gets it gets a little bit theoretical quick here. Soon as you use it relationally, it becomes even harder to maintain. Good point. Good point. Just started using as a MongoDB as a replacement for Redis for for a project that doesn't use Directis they are crypto so their relational is based on wallets. Makes sense You know, if you think about that use case, you have a semi structured data. You know roughly what goes into a wallet, but there's a lot of optional, fields oftentimes. Depends on the implementation, of course. But one thing you do know is that you have a fixed primary key that you can use for some relationships. Big sport of Jason's schema. Everywhere. Just for the spec Simpler, Tidebox for the win. I that used to be my go to and then a lot of others in in my team sort of using Zod, and I kind of have been converted to the The inference is pretty is not true here. Let's see what You kinda want to know that oh, it disappeared. Where it is? Oh, you kinda wanna know that a list of tags is always a list of strings or that an object matches a specific schema. Depends. I'd I'd say, generally, yes, but also really depends. For example, in to give a system thing as an exam right? For interface options, we don't know ahead of time what's going in there. Right? It's up to the interface to figure out. It's just anything. It's basically just a blank store for an interface to do some sort of options, but it really doesn't matter what the format is, what's in it, etcetera. Somebody shared p g adjacent schema, schema validation for postgres specifically. It's where it gets real tricky. Solution relied on the different filter syntax. JSON pass number to XPath. Yeah. Yep. Exactly. I think the, the the JSON schema example is is a good example of the the added sort of complexity that we're putting ourselves in here on purpose, which is that we're really really aggressively want this to be a standard in the API that you can use no matter what the data source is. And then it just depends on the data source how performant it becomes. Right? But I'd really, really would like to prevent ending up with, you know, a long table in the docs that says, can you use JSON filter? Yes. No. No. No. Yes. Yes. Yes. No. Yes. Yes. Yes. No. For for the different drivers, especially if those drivers are are third party maintained. You know, there's it's gonna be incredibly annoying. It does mean that for some of the data source, we'll definitely have to, we'll definitely have to, what's the right word, add add fallback logic and do a lot of that magic on the director side of things rather than on the data store but so be it You know? I I think that is a a trade off worth having, as long as these drivers can handle it themselves. Because Yeah. Right. We're fine. Scenario. Go ahead. Sorry. The the delay. No. It was, just for Brian's message, which was, the discussion point, my mind towards use cases like page builders, where I wouldn't need to create a ton of separate tables. That's true. And this is exactly the use case where I, in the past have used. You know, just sometimes if you very quickly want to throw together a component, but you don't really don't wanna create, like, different relationships and whatever. So you just quickly make, like, an h ref with the label and slap it together as adjacent, for example, very quickly, you know. That's that's a very nice use case for that. Yeah. Very quickly, very easy. Mhmm. For sure. And I I agree. Another interesting thing that he's mentioning there is saying that it would be better served by a NoSQL database. Right? That's where the interesting discussion really starts. Because if you're talking about, you know, a page builder for a website, then the pages themselves, just like what is the route? What is the title? What is some of the metadata? I'd argue that's probably better for a SQL database. Right? Because you're talking about structured data that you wanna query through on a column by column basis. You wanna say get all articles from, you know, January 2024, for example. That is gonna be faster in, you know, a relational database because it has, you know, structured data with known types and you could search through them efficiently. But the content part of a page, absolutely, it makes a lot of sense to have that as a page builder. Right? Because you have semi structured data. You have an array with 1 or more or 0 or more, I guess, you know, blocks of a known type. So that's where that JSON validation with schema comes in potentially. You know? And then that's the data is semi structured. So you have objects of, like, x different types, and then that has an array of those things. Yeah. So that makes a ton of sense. But I think the real power is the combination of the 2. Because if you were to try to do all of those pages in MongoDB, now you have to trade off of the sort of filtering performance and sort of the searchability aspect of it. But on the SQL side right now, you have the penalty of not having that unstructuredness of the data. Right? So right now, we would rely on any to any's for that type of use case, which has its own benefits around, you know, the searchability and the joinability. But, you know, if you're on pages where you don't really have to reuse, sections, for example, then, yeah, I agree. You're doing it as a JSON object for for a page builder makes a lot of sense. Right? But implementing it in a way where you get both is really the Oh, this this is why Brian, the father of, agent c OS, He he felt that pain probably, so he came up with this. Yeah. Yeah. But I agree wholeheartedly. Like, this came up exactly when I wanted to do then. If you have, like, one off components that you don't really, you know, they don't have something to do with other stuff or you want to get some data in, it's very, very, very neat. The repeater interface is very useful for that. Now there's one additional topic that we haven't touched on that I think we can easily spend 15 minutes on. And Brian is hinting at it right now, actually. Relationships. Relationships is where it gets real tricky. Right? Because right now, we know that's, article dot author is a foreign key to author's table. Right? So that that metadata is known. We know that ahead of time. So therefore, we can do things like give me everything, nest everything, nest everything, you know, start up start dot star whatever. And it knows what to nest because it knows what the relationships are. Right? When you're in within a JSON document or an area of JSON documents, there's really no guarantee that something is an ID or there's no real knowledge of what that path is and where it points. Right? So once you want to start nesting, data like that, it becomes tricky, tricky, tricky. Right? So within a a MongoDB context, if I'm not mistaken, it's like a MongoDB ID is always globally unique. Right? Right? So as soon as you have a nested data of that, I what what did they call it again? There was, like, a Mongo ID special type. I forgot what it's what it's called. Object ID is I think what they call the type. Anyways, when it encounters a value of type object ID, it it can assume that it's a globally unique ID and therefore knows what the what document to fetch. But in a sort of hybrid model, you don't necessarily have that luxury. Right? Because you can have a nested, categories array in your adjacent object that just says 123 with the assumption that you're talking about rows 123 in your categories table. Right? Because you're mixing concepts, because there's no such thing as globally unique IDs in a relational database. Kind of a design. I'm already imagining some type of custom format with, like, a dollar sign, direct to dot one or something, and then we have to translate it. And oh, no. It's a whole repertoire. We could do this. The same way as the chat, apparently. Somebody is saying direct us could prefix it. That's what I meant. Oh, yeah. We could. We could. But it does mean that we would have to make the data in your tables proprietary, which is something that I'm personally not a fan of. Right? It's like the system tables are one thing, because, of course, you need to have some metadata saved somewhere and we need, you know, a place to store that. But I really, really badly, desperately do not want to introduce any sort of direct to specific proprietary nonsense into your own database, in the user tables rather. So that's a tricky one. Right? So If we would do that, then we would probably also have to provide a way to extract the data, and it's it's more and more patches on top of patches. I don't think we wanna go down that road. The question really becomes like, how do you pull together a join? Right? And it's the same the same reason we haven't really, because Brian said relational repeater. Right? The reason why our repeater interface currently is not relational is because of this exact reason. It's like, how do we store the information of, you know, what field is relational to what? And the other tricky thing is, you know, without some real clever engineering from John and Nicklaus, most likely, There's no guaranteed way you can really do a join, based on the nested JSON value. Like some databases would, some databases don't. You know, it's the same sort of story. Right? So it becomes a performance nightmare. But what are some of our options there? Right? Just thinking out loud. One would be that we have some sort of, kinda like direct directors relations. Right? Where we're saying, well, if your JSON object has a path called, I don't know, article dot author, it we're assuming it's a foreign key, but that is always gonna be, you know, you can't really guarantee that. Right? An additional option would be to allow, you know, the end user to sort of pass the join information, right, manually through the API, where instead of saying author dot name where we know that author is a relationship, maybe there's some sort of syntax where you can just say author joins on table dot column, dot name. I don't know. Right? So you can pass it yourself. Can we just say we don't allow relations in JSON? I've I've tried that in the past and I think the answer is no. No. I I'm I'm afraid the answer is no for that. Because because that is that's kind of what, you know, that's the situation we're in now. Or, like, we have a relate we have a repeater, and people continuously ask, can we make it relational? And I continuously answer, how is that any different from a one to many? And then oftentimes, you know, we're just sort of in a sort of stalemate, which is, well, it's not JSON, but it does do what it needed to do. So we're good enough. Right? But I think it's fair to say that one of the design requirements of the system would be that we need to have some sort of way where you can relate data from a key that is inside of a JSON document. Yeah. I assume we would have to keep track of it. We've talked about this for the editor JS. Right? And or WYSIWYG being able to have great relational data structure that's stored inside there. There's actually a relationship to another Right. This object. Right? Another direct to side of them. So we we've we are thinking about this. We have some ideas around this. I think it's separate from this particular request. I think right now, this request is primarily around filtering and searching and finding It's true. Yeah. Yeah. Because because for the record, this really quickly turned into how to just properly do JSON indirect this rather than how to filter through an object. All all very much, you can see to that. Still important. It's it's part of the the divergence, the comeback to convergence. But, I just as as you guys have continued to talk about this, I think there there is a separate kind of feature function likely for relationals versus the ability to filter and just find stuff inside these objects and do it really and performantly. Yeah. The the WYSIWYG one is an interesting example. That's that's a good point because this everything that we've been discussing so far is basically gonna be the underlying engine slash foundational stuff for that type of use case. Right? Where in a in an editor JS type of environment, the line of text kinda like in like a notion docket, for for those unaware of editor JS. Each line of text is its own, you know, block effectively, and you have blocks of different types. But then a block could be a relationship elsewhere. Right? Which is a great example of this. Like, how do you know what that relationship is? In I'm pretty sure in in, you know, a Notion like environment or an Energy. Js type environment where you have, you know, a semi structured data, part of the solution there is that that joint information could be in the block, right, where you say you have an image block. And because you have an image block, you now know to look at images for looking up the related value. Right? But, again, that depends on the schema that is in your JSON field. And if we were to make that a requirement where we're saying, well, there's a there's a a god. Way to go, Brian. If we if we're saying that there that has to be in the JSON field and now we're making the form of proprietary again. Right? Because now we're requiring your JSON object to adhere to a certain spec. We designed just to be able to do relationships. Tricky. For a second, I was I thought you were gonna write down, this will be tricky. Rest rest assured. This will be very difficult. Is there not a normal standard for that already? Yeah. You'd hope so, but the answer is no. We gotta You know, there are some other CMS vendors that do this, but, again, they've got more, I think, generally well defined kind of hearts hardened structures. The ability to be agnostic is where this becomes very difficult. Yeah. No. That's a great point because we to say, this is the data model you must use. Therefore, this is I I can therefore rely on the fact that my structures are gonna match. But I think, potentially, with some of the discussion we had on the schema piece, you know, as part of this entire discussion here, if you were able to say, I am predefining schema. I know what that is, and then I wanna have enforcement validation and understanding that that's there. I think you we could ag you know, the agnosticity is you define the schema or we define a schema, but it's generic in the sense of you're not required to have it. You have a JSON field that's unstructured and doesn't have schema. But if you choose to implement that, then you are actually then getting the benefits of now I can I can kind of quote guarantee as much as you can guarantee in a JSON world? And I know what my data structure is, and I know how to how to interact with that event. Yeah. To be frank with this, it's just very, you know, very, very difficult. I mean, we we could, you know, like, just, willy nilly, we could keep track of, some keys in a new table that says, hey. This relates to that, like, similar to, like, relations, like we do it right now. And, well, try to keep that instinct. It's well, So when you're talking about the under, other vendor use case, right, I think for the majority there, it's basically around the idea that you have a globally unique ID. Right? So it's very document database first approach. If you've ever created a so we we use Notion a lot. Right? So if you ever create a Notion page that links to another Notion page, that is just a globally unique ID. So therefore, you can nest it however you want and it knows because everything is a page at all times and every page has a globally unique ID. So therefore, that sort of relationship lookup kind of solves itself. Right? Because you don't need to know what collection or what table to look at to find the item because it's all globally unique. Right? The difficulty here lies in the that hybrid model where you want to nest a relational record inside of a document, which itself might be, you know, related from a relational record relational row. Oh, do we like to make things difficult? But that's why it's cool. Let's see. There is a portable text spec. Absolutely. Which, again, I think it would be great to have a some sort of, you know, portable text interface or, an extension that handles that specific format. But I I it would be a shame if if this everything that we're talking about only works if you're in a specific format. Right? Because who are we to say what the right format is? I agree. I just looked at the, audible text one. Yeah. It look looks very, very similar to how everybody else does it. You know? You have some things. You define your type, and then you have some keys depending on that type. Great. Cool. Alright. We're quickly reaching the top of the hour here. It was it was a good idea to only focus on one topic for these sessions. Just based on prior experience, it always turns into this should be quick and then you you talk about it for an hour. Just to give a chance to chat, any other thoughts, questions, concerns, ideas, shout outs. I wanna say hi to the family at home. This is the time. Or when they start typing. Everyone is typing. Config is code. Uh-oh. I'm pretty sure we have a separate one of these dedicated to that again coming up. Ship it. Ship it? I'm not gonna I'm not gonna say it right now. Let's go. So for 20 minutes for brings everyone here. Same. Yeah. The next one's gonna be Comic It's Code. Cool. Cool. Cool. Cool. Cool. So make sure to come back for that one, saucy, saucy. Cool. Well, if there's no other questions, thoughts, feelings, or concerns, let's wrap this one up. It's Brian just said the conversation about config as code is is in 2 weeks, not the release. I think this is a very, very, very important Thank you, Brian. Thank you, Brian. It's Android. So it's it's imported immediately. Go now. What have we done? Cool. Well, all that being said, everybody. Thank you so much for joining us here live. Thank you so much for watching this at home. If you're seeing it on Directus TV, for the people live here, if you don't know what that is, check it out. Directus dot a 0/ tv. I think I got that right. Right? It'll be up in about a week's time. But for now, I wanna say thank you all. Good luck in Godspeed. And we'll see you in 2 weeks.",[176,177,178],"21d00b4f-2a61-4cff-b024-cde2a0640a2b","dc94af4a-d84f-440c-bd93-7734aa6aede7","3d6f534d-6fd7-436e-b2ce-eb4b743eeb0c",[],{"id":133,"number":134,"show":122,"year":135,"episodes":181},[137,138,139,140,141,142,143,144,145,146,147,148,149],{"id":138,"slug":183,"vimeo_id":184,"description":185,"tile":186,"length":187,"resources":188,"people":191,"episode_number":195,"published":196,"title":197,"video_transcript_html":198,"video_transcript_text":199,"content":8,"seo":8,"status":130,"episode_people":200,"recommendations":204,"season":205},"config-as-code","906788449","In this recording of our live event on January 25 2024, Rijk, Jonathan, and Daniel discuss configuration as code.","bd5024fb-4ef7-455a-8ff6-8631da26b5d2",56,[189],{"name":159,"url":190},"https://github.com/directus/directus/discussions/13041",[192,193,194],{"name":163,"url":164},{"name":166,"url":167},{"name":169,"url":170},2,"2024-02-01","Configuration as Code","\u003Cp>Speaker 0: Welcome everybody once more to a wonderful request review session here where we go over feature requests and figure it out. Now what do we do? I'm afraid we ramble on for about an hour about the technical complexities. Remember, the goal here is to basically divergently discuss, you know, what is the feature request, what are we trying to do, what is it trying to achieve, And how do we think we can make it happen in a very sort of direct to see way? What are we talking about this week?\u003C/p>\u003Cp>Speaker 1: Yes. We're talking about configuration.\u003C/p>\u003Cp>Speaker 0: Configuration as code. Let's let's figure out how to take schema endpoints to the max and actually Schema endpoints to the max. Manage the entire project as code. So this is really with a focus on GitOps. Right?\u003C/p>\u003Cp>Where you have a sort of centralized repository of static files that is the single source of truth for all configuration of the running project. Which as you might guess, they get complicated fairly quick. Hello. And as per usual, we'll be eyeing the chat. So if you have any questions in between or any suggestions or any good thoughts, please do please do put it in the chat.\u003C/p>\u003Cp>I already saw his name fly by. Well, most likely I have a very special guest for you today, because our very own Connor has been researching, you know, some of this for a little while now. But before we dive into the research results there, let's discuss a little bit of the requirements that are presented here in the current feature requests. Right? Because the one thing we know now, you know, the current state of affairs, we have that schema snapshot and apply endpoint, that we use and sort of recommend for, you know, moving bits of schema, to and from dev to prod, that sort of thing.\u003C/p>\u003Cp>But as people have pointed out, you know, that is still for schema only. Right? So we know one of the big requirements for this is gonna be you need to figure out additional configuration, additional additional, data points maybe from your own tables, you know, environment migrations, like you mentioned there, which includes, you know, what about roles? What about flows? What about presets?\u003C/p>\u003Cp>What about translation strings, etcetera? This well, one of the complexities for this is figuring out, you know, what is configuration within the context of directives in the first place. Right? Which is a discussion topic that I have had some trouble with just going through myself already, which is what is configuration? You know, are your roles and the way you configured permission configured, you know, permissions configuration, probably.\u003C/p>\u003Cp>But the users within those roles, probably not. But then users with static tokens, maybe. Right? If you have your own tables, maybe you have a single, you know, app settings, singleton collection that you use for configuration is that now configuration that is part of code first configuration. Right?\u003C/p>\u003Cp>Even though it's not a system table and you're not configuring directives, you might still be configuring other things. Although, that's where the fun starts. So maybe we could scroll down a little bit, Jonathan, just take a quick peek through, the other the motivation and the requirements here. So, you know, as we kinda touched on already, the same here from, Erif van Oort. Pretty sure that would be a Dutch user.\u003C/p>\u003Cp>It's it's about things like permission logic, you know, keep the local dev environment in sync, source control is the source of truth. Right? You wanna make sure that you can spin up new Directus instances not completely empty, but start it from, you know, a template that is in your repo. If there's an issue, you can easily, you know, share, the configuration of your platform. Daniel, if you would kindly mute, you're being very annoying.\u003C/p>\u003Cp>From the replying system, this is immediately where where it gets complicated. Right? It's like, what is configuration? Right? What is configuration?\u003C/p>\u003Cp>When it comes to import export, how to define what gets imported, what gets exported? Basically, the same question to me. Right? How does it get imported? You know, are you merging stuff?\u003C/p>\u003Cp>Are you overwriting stuff? What happens if you try to insert something that already exists? You know? How do you deal with conflicts? Very good question.\u003C/p>\u003Cp>So if you wanna scroll down a little bit further to see what else is in here.\u003C/p>\u003Cp>Speaker 1: Yeah. No. I don't know about that point. That's a good question, but a very, very long one to answer properly. But the gist is, you know, if you work with multiple people with different setups and if somebody changes your database schema, for example, how do you synchronize the state between your instance and another instance?\u003C/p>\u003Cp>You can do that with our schema endpoint. You can we already have that, capability. But, technically, you would want to or ideally let's say ideally, you would want to set up your configuration as code, because then you have a single source of truth. If you're developing a new feature, for example, you need a new table, you need new fields, you want to test something, you wanna try something, but then you, you know, delete some fields, How do you get the changes synchronized between different setups? And even the problem gets even larger if you have an organization, for example, with, let's say, I don't know, one dev department of, like, 8 people, for example.\u003C/p>\u003Cp>Stuff gets really gnarly really quick. How do you synchronize then between 8 people, for example, between different branches, different features, different collections, different fields? You know.\u003C/p>\u003Cp>Speaker 0: Let alone a test team of 200. Right?\u003C/p>\u003Cp>Speaker 1: Yeah. And this this is, you know, for a very small team, it can get quite gnarly pretty quickly. But, you know Yeah.\u003C/p>\u003Cp>Speaker 0: There's a couple other things there too. Right? When it comes to the git repo flow specifically is that any change to the schema of the project is now sort of, like, version controlled, so you know what happened when and you can roll back. And you have accountability because you know who made the change, through that sort of git first approach. Right?\u003C/p>\u003Cp>The other main thing there too, I think, is from a database template, you don't have files, which is one thing we'll touch on in a and the second thing is it's database vendor specific. That's another thing. Right? Like, you could plop the whole SQLite file in a repo, but, you know, if you wanna move if you have a local dev instance that uses SQLite and you wanna go push your change into production in Postgres, now you have a workflow trouble. Right?\u003C/p>\u003Cp>Even if you have local Postgres, the server Postgres, you might go, you know, I don't know, Postgres 10 to 13 or something. If there's a version mismatch, you know, there's there's things to to consider there. Of course, there's third party tools. I see Ansible mentioned here that you can use to sort of move databases across, sort of thing. This would really be sort of direct as native way to move configuration around.\u003C/p>\u003Cp>Right? Which I personally see it as an improvement or an upgrade to the schema snapshot system that we have rather than a completely new thing. Just the real question just becomes, you know, how do we add more stuff into that so you can use it for this? That's that's really the, to me, the the underlying discussion. Right.\u003C/p>\u003Cp>Jonathan, if you wanna scroll down a little bit further, you can see if there's any other points. Wanna make sure we don't forget. Export considerations, multiple files. I think that's a very important requirement because we've already seen some of the schema snapshots just get bonkers large. Right?\u003C/p>\u003Cp>Because if you have a 1,000 collections, a total of 25 100 fields sounds insane, but it happens in the wild. The one export file, you know, is is megabytes and megabytes and megabytes worth of of JSON. Tens if not 100, which gets unwieldy pretty quick. It also makes it more difficult to import, by the way, because we're not really able to stream it all that well and then it becomes a very large file. So you have to read it into memory and then and then use it.\u003C/p>\u003Cp>Let's see. Selective export. That, I think, is a tricky one. Right? How do you know what you're exporting if you, consider your roles and permissions part of this, but you have one admin dev role that you don't care about for your production instance, How do you pick and choose?\u003C/p>\u003Cp>Right? Pick and choose what to what to include, what what not to include, and handling, you know, sensitive data. Very good point. You know, is this gonna be plain text in a static file? Tricky.\u003C/p>\u003Cp>Right? Tricky in a repo. If you scroll down a little bit further, The modular files of extensions, single file per collection, you know, we kinda test.\u003C/p>\u003Cp>Speaker 2: Does\u003C/p>\u003Cp>Speaker 0: does it actually make more sense to have selective import versus export? Great question. Great great question. Maybe. Maybe.\u003C/p>\u003Cp>Yeah. It's it's like if you have Go.\u003C/p>\u003Cp>Speaker 2: I'm sorry. Go ahead.\u003C/p>\u003Cp>Speaker 1: I I don't have to remember to mute and unmute myself between every sentence. That's fine. Yeah. I can see both being very useful. Right?\u003C/p>\u003Cp>For example, if if you have a very, very large, instance with, like, Greg mentioned, right, like, a 1,000 collections, And on your dev instance, you only want to add one thing, do you really need to export, like, this whole thing that's, like, I don't know, 10 megabytes or whatever? Maybe, you know, maybe, it would be enough to just export that table with its fields, and you'd be good to go, because then you could import that partial instance, maybe. But, yeah, for for import or for export, both could be useful. But, yeah, like we said, it's just lots lots and lots of stuff to talk about there. Yeah.\u003C/p>\u003Cp>Speaker 0: TBD is is the honest answer. I I also feel like both is probably where we need to end up with that. Because to your point, if you have a large project and you only care about a small subset of that as a sort of templatable piece, you know, you don't want to export everything and have a bunch of unneeded data in your repo muddying up, you know, the workflow and the reviews. Because then also imagine that you make an export and then now you have a PR of, like, 16,000 lines of stuff that you don't really need. Right?\u003C/p>\u003Cp>But, yeah, let's see. Extend, you know, existing schema files. That's an interesting one. Merging multiple together, importing snippets from other files, maybe, you know, from nested collections. So that's all about, you know, the the file structure for the project.\u003C/p>\u003Cp>Saving the non defaults, I think that is more of a technical requirement to me. Right? It's like we don't have to save default values from Directus in the schema snapshot because they're the default values. Dynamic configuration sync, it's just whenever you make a change in the studio, it auto exports basically, which feels heavy, personally. Feels a bit heavy, but could could potentially work depending on the file format.\u003C/p>\u003Cp>But then again, how do you choose what to export on the automated one? Right? So TBD. That's also why it's a could have. I mean, they've they've thought about it luckily.\u003C/p>\u003Cp>Automatic real time sync, sort of similar idea. Right? But an option in the Data Studio API triggered chrono periodically high. So the one thing I do notice in the requirements list here is that there's a lot of talk about how to get it out of Directus and in what file format, but not so much the other way around. Right?\u003C/p>\u003Cp>How do you get it back in? So if you have something in your repo, whatever that something is, what does that code look like and how do you get that back into the Directus instance? Right? This might be a good point actually, a nice little segue. Like I hinted at at the beginning, our very own Connor has been doing quite a lot of homework on this just to figure out, you know, the, the format and some of the ideas around this and how it could work.\u003C/p>\u003Cp>So if let me see if I can find him. Where is this little so many here. Look at that. Hello, Connor. What have\u003C/p>\u003Cp>Speaker 2: you been what have\u003C/p>\u003Cp>Speaker 0: you been up to recently?\u003C/p>\u003Cp>Speaker 2: I have been up to quite a bit involving this config as code and how it plays into all the other different parts of direct disc that we wanna do. Let me get my notes up. Here we go. So you said you wanted me to talk about the structure of the exports?\u003C/p>\u003Cp>Speaker 0: I think it'd be cool if you wanna give a quick overview of sort of the the research process itself. Like, what are the things that you've been looking into? What have been the considerations or requirements? And sort of the things that you found. And then dive into some initial conclusions.\u003C/p>\u003Cp>Speaker 2: Sure. So what I have been going through and researching is basically we have a couple of different feature requests from config as code to templates to migrating between instances to migrating between different databases. And all of it sort of involves, you know, moving configuration between instances, moving data between instances, and moving files and assets between instances. And that is a very big task when you're trying to be database agnostic and you're trying to be efficient. You're trying to have you're trying to support multiple different use cases where sometimes you wanna overwrite everything, sometimes you just wanna bring in some stuff, sometimes you only wanna take out some stuff.\u003C/p>\u003Cp>Sometimes you wanna stream it all. Sometimes you wanna have the file small. So there's a lot of very different considerations that go into it, and then making it all happen with one sort of directest way of making it all magical. It becomes a very big rabbit hole that you start diving down into. And so one of the stuff one of the things that we've that I have been looking at is, you know, what are all the different use cases for it, and what are the requirements for all those different use cases?\u003C/p>\u003Cp>And so configuration as code is one of the use cases on there. It's not completely fleshed out yet because that was not on it's one of the later goals of what I've been working on. But with it brings, you know, how do you integrate it with CICD, you know, GitHub, GitLab. You know, do you have your own hosted GitHub, You know, self hosted GitHub. You know?\u003C/p>\u003Cp>Where do all your stuff is stored? And so there's a whole bunch of different parts of it. Right now with the schema service, we go and we give you you export a schema of your stuff. It exports everything. You diff it against your instance, and then you apply that diff, and it gives you, like, the changes if you can do it or not.\u003C/p>\u003Cp>And right now, that's really it. There's not really too much to the schema service outside of that right now, and adding in all these different layers and features. The schema service is definitely gonna have to take a new look to it. And so one of the things that we've been looking at is, you know, that initial export of a schema, you know, making it more of a distributable type of folder structure file structure, whether it's a compressed zip file or some type of other special file. But basically redefining how that schema export looks to be able to hold all these different configuration items, to be able to hold data, to be able to hold assets, and defining that structure and, you know, you know, as Ryke mentioned earlier, you know, do you want that stuff stored in plain text or do you want it to be stored in, you know, some type of encrypted format or do you want it to be compressed?\u003C/p>\u003Cp>So there's a lot of different variables there. And then once you take that distributable that gets made, it can be I mean, for some instances, if you've pulled out data and assets and configuration, you know, that thing could be huge. And so we wanna go we wanna bring that into the this new instance of the target instance. Right? And so we need to different and change it.\u003C/p>\u003Cp>And so bringing all that in and processing in is a whole another thing. You know, do you wanna bring in all of it? You know, you have all the export controls. Do you wanna have import controls to how it gets implied and, you know, how it gets imported? And so I've been going through and documenting all those different ways that we can do stuff, you know, what is dependent, you know, if we wanna do this, then, you know, we have to do that, you know.\u003C/p>\u003Cp>And so we've been looking at one of the things this week, you know, is what type of file format for all of this type of stuff, for how it gets really big. You know, if it gets a lot of data, if somebody has a 1,000 collections and 4,000 fields, you know, is a CSV file, a JSON file really the right file structure to store all of that data? And so we've been looking at, you know, different options and different file formats for storing, you know, structured data like that in an efficient compressed way that also lets you keep the schema of the schema export defined and structured in a way. And then also making sure that we keep that same right now, we hash the schemas and stuff so that they all stay. You know?\u003C/p>\u003Cp>You could only use the schema to apply to this instance because you just did it with it and yada yada. So having that in there too, you know, do we have a metadata file inside of that export that, you know, talks about what the export is? You know, do we have it? Do these become an extension type, you know, that can be used throughout the instance in different places? You know, there's a whole bunch of different options there.\u003C/p>\u003Cp>Speaker 0: Yeah. Yeah. Absolutely. It\u003C/p>\u003Cp>Speaker 1: was a great intro. Yeah. It was a very good yeah.\u003C/p>\u003Cp>Speaker 0: Exactly. Exactly. Yeah. So the first order of business to your point, you know, figuring out what does that file format look like. We know some of the requirements now based on this discussion that we just looked at.\u003C/p>\u003Cp>We know some of the the downsides of the current format. So that's a great step. Then, of course, the second big step will be figuring out, you know, how do you go from that sort of source of truth overview into applying it for realsies. Right? So we have that sort of diff step in between.\u003C/p>\u003Cp>So for those unaware right now, if you upload a schema snapshot into the Directus API, it will compare it to the current state of the database and then return, you you know, the the the list of differences, basically. So it's a diff, not a list of changes. As in a step step by step list, it's just a diff, like an a a versus b. And then that diff is then uploaded to an apply endpoint, which will basically, you know, apply the changes required to get rid of the diff, right, to make sure that the that the 2 are in sync, that the instance is in sync with your file export. So based on that, Connor, we've done some research on what needs to happen on that diff endpoint itself too.\u003C/p>\u003Cp>You wanna you wanna share some insights on what we know now, at least, are some of the requirements to make that work properly with all of these new new additional features that we're trying to add in.\u003C/p>\u003Cp>Speaker 2: Yeah. So with that dipping endpoint, some of the things that we are looking at is, number 1, if you wanna bring in data. Right? You know, how do you diff large amounts of data? Are you able to diff large amounts of data?\u003C/p>\u003Cp>That's one of the research things that's on the list. You know? Right now, we have an import and export service to import and export data. Looking at Attica drive run options. You know?\u003C/p>\u003Cp>Can you import this data? Can you export this data, for that diffing stuff? You know, if you have a really big file, so you do have 300,000 collections and fields, you know, that's gonna take a long time to make changes to the database and to go through and find that diff. And so having some type of long task runner on the instance that's able to sit there and work through that to that, diff or making that diff or distributable or whatever it is. You know, having such a long running service of the background of your instance, I can handle that.\u003C/p>\u003Cp>And then also if you're going through and you're applying all these big changes or diffing it or whatever, you don't want people in your instance changing the stuff as you're trying to change stuff. So implementing some sort of maintenance mode on your instance that basically locks it down and puts it, hey. We're making changes right now. You know, you can't it doesn't let anyone else change the schema or anything or the data or whatever you want it to do. We also, have been looking at, you know, for asset data, you know, pulling in you know, do you pull it in from the distributable file, or do you pull it in from the data the asset source?\u003C/p>\u003Cp>You know, do you pull it in from the s three bucket directly? You know, do you use it like that, or do you package it into the distributable? Or, but, basically, for the diffing part, the other part is that if you have a really, really big distributable or schema thing, whatever it ends up being called, you also upload downloading it from one instance, uploading it to another instance just to download another big thing, just to upload the other big thing back again is a lot of moving back and forth of all this different stuff. And so the other thing is when you upload that schema, whatever, it diffs it. Instead of it downloading the diff back to you, then you having to send it back up, it being able to just keep the diff on the instance and you just being able to tell it to apply the storage diff that it already has.\u003C/p>\u003Cp>And so you don't have to have that all that network changing back and forth, and then, you know, Internet goes out, then you're screwed. You know? But that's one of the things that we've also been looking at for the diffing. And then another thing is, you know, different types of strategies of diffing and importing. So that, you know, do you just wanna up cert stuff?\u003C/p>\u003Cp>Do you just wanna add new things and you wanna ignore everything else that has conflicts? Or do you want it to only apply if there are no conflicts, you know, or do you want it to overwrite everything, you know, so it doesn't matter if there's conflict. We're gonna rewrite over it with everything, you know. And then instead of just returning a singular diff that just compares the 2 different schemas and it just says, hey this is what's different. You know putting in more migration like making it more of a step type thing.\u003C/p>\u003Cp>So it works through migration steps. And, you know, oh, you need to do this. You need to do this. You need to do this. You need to do this.\u003C/p>\u003Cp>And basically a workflow that the thing can work through and and guide those long running task runners on what to do and how to configure your instance. And I\u003C/p>\u003Cp>Speaker 0: think last but not least, the having some sort of format to expose potential conflicts for manual resolution. Right? So if one of the strategies has to be that it's up to the end user to pick and choose what to do. So imagine if you go, you know, from a dev to prod, life cycle, right, where you're not so much delete everything and insert everything, you wouldn't wanna do that in a prod obviously, And if you have an absurd strategy, but there is a conflict, right, you you have, like, a foreign key that doesn't work anymore or something like that. There needs to be some sort of format in whatever this diff looks like or this migration step format looks like that just has, a list of Here's the steps with the known conflict What do you wanna do?\u003C/p>\u003Cp>Right? How do you wanna modify that that step, those steps to get around the conflict? Right? Do you wanna upload, you wanna upload new data, or do you wanna, ignore that particular step, or do you wanna ignore those records? You know?\u003C/p>\u003Cp>So to your point, if we need some sort of driver and to check if you can import all of the data, it's sort of a requirement in order to be able to extract, you know, potential conflicts. So we need to have some sort of way to search through the data you're trying to apply, in order to know how to deal with conflicts. Right? So now that we're talking about all of this, what we're what we started to notice is that we're not so much talking about, you know, configuration as code specifically or templating specifically. What we're basically shaping here is a system that works for multiple things, right?\u003C/p>\u003Cp>Depending on how you use it. So if you were to make, a snapshot of everything, just full stop everything, and you import it as as apply everything, what you're talking about now is basically backup restore. Right? If you're exporting a small fragment and you're importing that into another project, you're basically talking about templating. Right?\u003C/p>\u003Cp>If you're exporting just the schema part and no data and you apply that to a new project, you're you're talking about seeding or something. You know what I mean? Like preparing preparing, a database basically, a a new project for what you wanted to do. And the question now is, how does that how does that all tie together how does that tie back into the configuration as code parts specifically, Connor? Because what we're talking about now is, you know, a new sort of format, generated by Directus that you can save somewhere, you know, which is fairly still, it's still fairly proprietary because it will have to be heavily compressed and, you know, directors needs to know what the format is.\u003C/p>\u003Cp>So what is the current thinking on tying it back into the code side of this question? Right?\u003C/p>\u003Cp>Speaker 2: Yeah. So if we went the route of having some sort of distributable file structure folder structure that is some proprietary format or is encrypted or compressed or whatever, you know, you're not gonna be able to sit there and write code that is a compressed file. You know, you're gonna have to have write something that generates that file. So one thought that we've been having is following the lead of some other types of, you know, companies like AWS and their SDKs. So, basically, having some type of SDK that you can write and configure your instance with, and then you tell the CLI or whatever to execute that, read those different set the code that you've written, and then it will make a direct distributable file, diff file, whatever it is, from the code that you've read.\u003C/p>\u003Cp>So if you wanna go through and you wanna define all of your collections and your fields or whatever, and you can go in and define that in all your files and your code and then execute that code, it comes up. It generates that file that you can then use to apply those changes, import those changes, diff those changes to any of your target instances that you want to.\u003C/p>\u003Cp>Speaker 0: Jonathan, if you might be wanna pull up, I think one one piece of inspiration that we were looking at for that part specifically was AWS's, what do we call it? CDK, I think, code development kit. If you wanna quickly Google that, it could be it could prove like, it could put some flavor to that to that point. So the way AWS has that, they basically made a JavaScript library that you can use to code, like, configuration. And then what it does under the hood is it effectively converts it into, a CloudFormation template, I wanna say, and then applies it immediately.\u003C/p>\u003Cp>Right? So under the hoot, you don't really notice the difference, but it's effectively a 1, 2 jump. Right? So it converts it into their proprietary thing in the middle first and then just applies that as is. What am I searching for?\u003C/p>\u003Cp>Sorry. CDK, the cloud development kit. If you wanna pull up the GitHub repo for that, maybe I have a link somewhere. I'm just curious if they have some some examples somewhere. It's been a minute since I've played with this, but it's an interesting, idea.\u003C/p>\u003Cp>There was a Directus community library, a little while back that that tried doing a similar thing, but it would run it against the API endpoints. It wasn't as flexible yet because we didn't have we don't have, you know, GreenStep. Is this branch? You know. If you wanna do AWS before that, because I think CD case is all different.\u003C/p>\u003Cp>Yeah. There we go. There's a link in the chat as Open it up. Here we go. Here we go.\u003C/p>\u003Cp>Here we go. Is it gonna go? There it\u003C/p>\u003Cp>Speaker 1: goes.\u003C/p>\u003Cp>Speaker 0: So this is an interesting reference for people that wanna look it up. At home, it's basically, you know what was that? Distracted by the chat immediately. Using something like CDK would mean that changes would need to be replicated from the UI to the generation scripts. Changes would need to be replicated.\u003C/p>\u003Cp>That's a great point. Yeah. How does that go both ways? Right? Because if you have that one format in the middle, directors can recreate that format in the middle.\u003C/p>\u003Cp>The directors wouldn't be able to recreate arbitrary JavaScript, basically. Right? So when you opt into something like that, I think it becomes a one way street by definition because we cannot figure out what parts of your JS file are, or your code because they also have some other languages, but you get the idea. And we don't know what parts of that file are auto generatable and what parts are, human created. Right?\u003C/p>\u003Cp>There's so there's no way to auto generate that back into a manually created file. So at that point, that's a great point, but it's the it really becomes, you know, it becomes a a one way street at that point. Some of the data community did a sort of proof of concept library to do this for, which is very interesting. So if you wanna pull up the direct to community schema builder kit repo, I just sent a link in the chat there. It was very much inspired by a similar idea where you have a JavaScript file that you use to sort of define.\u003C/p>\u003Cp>It's almost, you know, a declaration file rather than, you know, JavaScript, but it is still just JavaScript that runs from top to bottom. But you could define your schema and how it's applied as, you know, individual build steps, in a JavaScript. So this is where it gets real heavy on the code part of the codeless configuration. Right? And not so much just the, moving stuff around.\u003C/p>\u003Cp>So in in terms of big picture stuff, I really see this as the final step of whatever these changes are that we're discussing. We'll have to start with what is that new format in the middle, how is it generated, how is it used, and then see this as a way to sort of generate it into that format and then apply it automatically. Right? But, yeah, that that JavaScript syntax is an interesting interesting idea. So, yeah, I see some folk typing.\u003C/p>\u003Cp>This is one of those very typical director's projects where there is about 600,000 different opinions on the ideal way of doing this. And I think we we saw it in the chat immediately. Right? Shout out to a person that was like, isn't it not just the database template? Why why bother?\u003C/p>\u003Cp>Right? Which I can totally get behind that, but then there's a 180 or so of votes or something like that on the on the discussion. So apparently, you know, that is not an opinion that's shared.\u003C/p>\u003Cp>Speaker 1: Yeah. What what's interesting is, right, because, technically, the most basic example would be something like a database migration, generally, in the beginning, you know, for the configuration as code, for example. So there's another, a similar project director, the CMS like project that I've checked out and see how they did it. And, so they handled this a little bit differently. They don't have, like, a DSL type, you know, language that defines your infrastructure or whatever.\u003C/p>\u003Cp>But, they went the route of as soon as a person or user, via the UI creates some type of change in the tables or the collections or however you want to call it, the instance automatically generates a migration file locally for that specific change. And, there's then a mode in the instance where you can disable any, any ability for other users to change the actual instance. So you can actually just rely on the migration files, which is an approach that you could take, you know, because a migration file then could technically do anything you'd like, you know, with with regards to, you know, the collections, the fields, whatever, even inserting, items. But, then, you know, because we're a directors, we want to that's a little too easy for us because we would like to include some type of things like, alright. How about you, locally, you develop some type of new feature, new new table, new collection, new fields.\u003C/p>\u003Cp>And then in order for that to work in the way that you want it to work, you need an item. You know? You need to include a new new row, data row, or an asset. This is the thing now. Because, you know, assets are not inside of the database.\u003C/p>\u003Cp>So we want to include assets, for example, or maybe this, of course. Nothing is, you know, set in stone, but, you know, including assets, for example. So you want to make some changes, and you need to include some assets for your changes to be even, you know, useful. So you would then have to, you know, do your changes, test it locally, include everything with the correct file name, with the correct row, whatever, or other metadata of an asset, for example. But then on production, you would have to replicate that again.\u003C/p>\u003Cp>So you get this back to back to step 1. Right? So this is kinda it kinda sucks, with a migration part. So even then, if we want to include this, then we get back to the issue at hand that we were talking about. Right?\u003C/p>\u003Cp>We want to have a process that could export something, and you can recreate that between instances and so forth and so forth. I would, I just wanted to mention that for the others in the chat because, it's not just about, you know, just adding a field because that's basically, you know, that's a basic thing, which we could solve. And I think the Director Schema Builder kit is basically that. Right? You you generate some type of syntax, which generates some type of migration.\u003C/p>\u003Cp>But you have to keep in mind then, of course, right, different database vendors, we have to abstract that. Because, for example, you know, in SQLite, if I remember correctly please correct me. If I remember correctly, like, you can't alter a table and introduce, like, a foreign key. You're forced to drop the table, actually, and recreate it in order to add a foreign key, for example. Other databases can do that as CLI can.\u003C/p>\u003Cp>So there's lots of different\u003C/p>\u003Cp>Speaker 0: honest there, I'm pretty too sure that the last minor release of SQLite didn't come out too long ago. They finally do have that alter table sort of baked in. Although then, you, of course, you have the you have the side effects that it depends on your native build of SQLite on your machine, which may or may not have had. So generally speaking, historically, you've been absolutely right. It's been a nightmare and a half to to do that.\u003C/p>\u003Cp>Speaker 1: Lots of fun. So I just wanted to make sure that, people in chat, you know, it's it's not about just adding a thing. It's it's a little more involved than then. And, you know, including assets and, like, the other sent. Right?\u003C/p>\u003Cp>Maybe there's proprietary information or whatever, and you're not allowed to leave it on your hard drive. Maybe you want to zip it, encrypt it, compress it. There's lots and lots and lots of different steps that we have to, kick off there. So alright. Oh, we got some in the chat interaction.\u003C/p>\u003Cp>Cool. Cool. Cool.\u003C/p>\u003Cp>Speaker 0: So alright. Top to bottom. First question. What speaks against using JSON or YAML files? Instead of JavaScript, this way the changes in the webpack could also be synced back to the files easily.\u003C/p>\u003Cp>So for what it's worth, the the, formats that we're talking about being generated from directives would most likely be, you know, in some sort of structured format. Not quite sure if that's JSON or YAML yet or if we have to find some sort of optimized, file format to do that. Because the the the risk of JSON and YAML exports, once you start including data, you know, we no longer know how much data you wanna include. Like if we're treating this as you could use this for backup restore we could talk about a large large amount of data right at which point we need to have a very optimized structural format that may or may not be usable in that point. Right?\u003C/p>\u003Cp>Connor, remind me, we found like an Apache file format that could be interesting for this. I think what was it called? Parquet or something. Right?\u003C/p>\u003Cp>Speaker 2: It was called Parquet.\u003C/p>\u003Cp>Speaker 0: Parquet. Yeah. That would be an interesting file format for something like that. Or potentially using a SQLite database as as the exported file. Like, that's a completely different, direction.\u003C/p>\u003Cp>But But you get the idea. We need to have some sort of optimized compressed file format because the export file could get really large. Now, it might be an option for the way, you know, you save one of those to just save it in a sort of raw mode. Right? Where it doesn't save it compressed, at which point it's just it could be human readable YAML or or JSON, including, you know, the ability to properly, source control it.\u003C/p>\u003Cp>On the migration note, I think you answered that before, Daniel, like, exactly right. If you're doing auto generated migrations, it's really only for the database schema part. Like, we can't really know on your behalf if you consider, insights dashboards part of configuration or flows or something. Right? So it's it's gonna be it's gonna be tricky because people different people have different export requirements.\u003C/p>\u003Cp>And if you go from dev to prod, all bets are off. Right? You you never quite know what the the idea is. Creating internal libraries fiber to schema works with native access to directives rather than the API using integrations and help creating a lot of complex repetitive action. I can imagine.\u003C/p>\u003Cp>Yeah. Because you can write a little JavaScript for loop and just block. You have 10,000 collections. Right? But, you know, the lack of two way integration between the UI does cause issues which is the unfortunate side effect of using, you know, a programming language rather than a declarative language like yaml or JSON, for doing schema modifications like that.\u003C/p>\u003Cp>You're gonna lose that two way integration. That being said, you know, if Directus has a don't allow me to change the schema environment variable flag, whatever, you could make that, you could do that on purpose. Right? For a production instance, for example, I can totally imagine that you disable any sort of schema modifications just for security reasons, and and availability reasons and only allow those changes to happen through whatever system we're we're cooking up here. Right?\u003C/p>\u003Cp>I think default value filtering could help make the YAML auth more manageable. Fully agree. You know, we should only store the stuff that we need to know, and storing default values feels like a waste of waste of space. Then Azure is working on some sort of YAML based metadata authoring, announcing Azure data delivery net auth sales. What marketing email?\u003C/p>\u003Cp>Very curious. Haven't I haven't heard of that one before. If you wanna keep the GitOps thing, it should really be a text format. Good point from Tim. Which may or may not be answered from by Dominic here.\u003C/p>\u003Cp>If you split up between schema and content in different formats. Right? Maybe the configuration piece is all human readable file formats. But if you have a data export that is maybe there's a file size threshold. Right?\u003C/p>\u003Cp>If you have a very large CSV export maybe there's just a smart point where it's like, oh, you're trying to save 10,000 rows We're gonna flip it automatically into a compressed, non readable format so you get the best of both worlds. Right? Potentially. Cool. Alright.\u003C/p>\u003Cp>Cool. We tried.\u003C/p>\u003Cp>Speaker 1: I it's something similar. Yeah. Just to, you know, chime in to regards to what you just said. So with the, like, yeah, like, yeah, we have to split that up preferably, you know, or at least, you know, required to have this as text based so you can, you know, use it in version control, whatever. And, for, like, including items, for example, you know, a ZIP is is a nice thing that you could use, but then, of course, you know, maybe this includes then items that are not, like like an old version, for example, and, you want to insert something in in where a field doesn't exist anymore, and and lots and lots and lots of other, you know, stuff.\u003C/p>\u003Cp>And, you can then, of course, if we then have all of the different points that we want to persist, right, like flows, permissions, the general config as it is, you could include this then also in the export with the items, so you can do both at the same time or see if it differs and then cancel the thing. But, yeah, it's, it's a fun thing. You know? There's lots and lots of things that could go wrong. There's so many.\u003C/p>\u003Cp>Speaker 0: No no matter what, we wanna make sure that the output file is a single distributable. Right? We do wanna make sure because we on the one hand, we're saying we have to split it up into multiple files in order to make it efficient and easy to work with, But, at the same time, we also wanna make sure that you have a singular thing, singular file that you can send over, to somebody else. Right? Either through the API, so you just have a single download or a single upload, or as a file, maybe packaged through, you know, the marketplace.\u003C/p>\u003Cp>Shout out. Wink wink. Notch notch. Or as, just to email it to somebody for a like air. Right?\u003C/p>\u003Cp>Put it in a GitHub issue as a zip. So there needs to be some sort of both. Right? But I could also imagine that, you know, the API, lets you download it as just a zip, right, that you can just double click to open if you're on macOS or do whatever else it takes on other platforms, to unzip it. Looking at you, Daniel, I'm sure there's a 2 step process.\u003C/p>\u003Cp>For those who, out out of the loop, he's, this is the year of Linux on the desktop, evangelist within the team.\u003C/p>\u003Cp>Speaker 1: Yes. This year. Here it is. This is the year. Mark my words.\u003C/p>\u003Cp>And this year is the year of the Linux desktop. This year. Yes.\u003C/p>\u003Cp>Speaker 0: But long story short, we it's it's we're we're in that weird in between that we need both. Right? We need both the single file and multiple files. So we'll most likely have to come out with some sort of zip, gzip, something like that in between. Cool.\u003C/p>\u003Cp>Prisma migrations are an interesting way of doing things. They have a custom format, which is more concise than directed YAML, and then some CLI tools that create actual SQL migrations in the syncs the environment. Yeah. Great example. Right.\u003C/p>\u003Cp>Good example. They have they basically do with that shadow shadow database, if I'm not mistaken, that's how they keep track of those migrations step by step by step. Yep. Right? And then with the the CLI tool, it can compare your custom migration format with what they already have tracked so far.\u003C/p>\u003Cp>And then, you know, apply apply the diff based on that. Still has the similar I think a similar one way issue, though. Right? Because the Prisma migrations that you write manually, I don't think they can sort of update those from the others from the other side, so to speak, that a two way binding. Good point, though.\u003C/p>\u003Cp>Good point. Alright.\u003C/p>\u003Cp>Speaker 1: Could remember. I had a problem with in the past. So, sadly, I can't remember it right now, but it was very painful. So, it's not a 100%. Yeah.\u003C/p>\u003Cp>It's not a 100 perfect thing. Nice. I've seen people you know, there's there's lots of other, what is it called? Drizzle drizzle right now?\u003C/p>\u003Cp>Speaker 0: Oh, there's a couple of RMS like that. Yeah. Yeah.\u003C/p>\u003Cp>Speaker 1: So there's there's lots of sauces that we could, you know, yoink some code from, but be inspired. Let's say be inspired.\u003C/p>\u003Cp>Speaker 0: Yeah. I don't think we've been yoinked. I don't think we've legitimately ever yoinked code before.\u003C/p>\u003Cp>Speaker 1: Borrow. Borrow. See.\u003C/p>\u003Cp>Speaker 0: Strategies is interesting there. But the the the main difference and then you you touched on it perfectly before. The main difference there is the just keeping track of the database schema versus having that ability to just sort of manual template in between moving stuff between dev and prod that is not just schema, but also data and how to deal with that, which at any point needs to be, something you can do manually. Right? It doesn't have to be manual all the time, but it needs to be something you can do manually Right?\u003C/p>\u003Cp>Cool. Well, with all that being said, looking at the clock here Connor, back to you. We've discussed quite a lot of the research up until this point, some of the requirements. You and I have also sort of been daydreaming about potential ways to implement this moving forwards. You wanna quickly touch on sort of the different, different phases and different sort of parts that we wanna touch as part of this bigger bigger effort?\u003C/p>\u003Cp>Speaker 2: Yeah. So the first thing we wanna do is we wanna figure out how this is gonna look, the distributable, the diffing. What is that file structure? What's the file format? You know, what are the requirements for that?\u003C/p>\u003Cp>Do we have encryption? Do we have multiple files? Do we have one file? Do we have whatever? Like, we've already discussed here.\u003C/p>\u003Cp>First thing is defining what that'll look like in totality, covering all use cases so that as we progress through the the phases of this project and making it happen, we can keep that spec that we have for those files in mind, and we can make sure that we cover everything whenever we could work through the different phases. But the that is phase 0 to finding out that spec, figuring it out what it looks like. Phase 2 or phase 1 would be upgrading the schema service foundationally right now. So making sure we have all the bug fixes with the schema service taken care of, you know, adding the new different, you know, different strategies that to it that might be needed. You know?\u003C/p>\u003Cp>Do we have, you know, add in those exports, export filters, you know, only export this stuff, you know, that stuff. So getting that schema service, adding some more features to it. And then the next phase is working on data importing. And so adding in the different features that would be needed to make the data importing work, You know, dry running, imported data, importing strategies. You know, do we have a import strategy where right now everything just gets up sorted?\u003C/p>\u003Cp>Do we wanna have an import strategy where if you import the data, it drops all the current date data in the table and re imports everything fresh? You know, adding those different options. Some other just things, ideas that have been thrown in the mix is, you know, if you're moving between one instance to another instance and you don't wanna bring any of your IDs, your primary keys, your foreign keys, you know, adding some type of way to anonymize that as it goes from one instance to another. So the new instance makes new IDs for everything. Or adding, you know, the ability to for, like, templates, you know, if I wanna bring in a template for project management and have a due date in one of the items, but I made the template a year ago, then the due date's gonna be from a year ago.\u003C/p>\u003Cp>So, you know, being able to have dynamic data that gets brought in on import. And so, you know, oh, I want you to import this as a date, but make it for in 2 hours after the import is when it's set. And then the next phase after that, working on data importing is getting into putting it all together. So we've worked on the spec for the thing. We worked on the schema service.\u003C/p>\u003Cp>We worked on data importing. Now we need to bring it all together into this this new overhaul configuration, multimodal thing, and have it work on bring all those pieces together and make it work, basically. And then after that, once we've gotten the specs spec'd out, the schema service upgraded, the data importing upgraded, we brought it all together, and it now works foundationally. Now we need to figure out how do we use this to implement these different use cases? So for templating, you know, what do we build inside of the data studio admin app from a user interface and API perspective to make templating work?\u003C/p>\u003Cp>What do we do from the configuration as code to use the stuff that we've already built? So how do we implement the feature set that we want in the configuration as code use case. You know, are there any other use cases? You know, back up being and restoring an instance. Do we have the feature set that we wanna use for that?\u003C/p>\u003Cp>And then that should, in theory, wrap up the project after that, after we figure out and implement those use cases. So there's quite a few steps here. Quite a lot of different items and it's going to take a long time. But at the end, we should have something pretty cool.\u003C/p>\u003Cp>Speaker 1: Ideally. Yeah.\u003C/p>\u003Cp>Speaker 0: And I think I think Daniel's facial expressions told told the whole story. No. But that'll I mean, it'll make sense to me. It sounds it sounds like a large overwhelming amount of stuff as it usually does. But by breaking it up, you know, step by step like this, we actually have a pretty solid idea, you know, start to finish of of what is involved to getting that across the finish line.\u003C/p>\u003Cp>And, yeah, as per usual, you know, there's a lot of, what's the word? Direct this magic going on under the hood to to tie it all together. But I'm always just very excited and glad that we're able to sort of re envision this as we have one underlying core foundational engine that can power all of those different use cases. Right? Rather than trying to tack on a new sort of templating piece and a new sort of code first configuration piece and a new sort of other piece.\u003C/p>\u003Cp>Right? That just increases the tech that makes it hard to maintain. It makes it those different flavors incompatible. You know, somebody will ask, how do we do a template as code? And we're like, well, you can't because code is not for templating.\u003C/p>\u003Cp>You know, that kind of stuff. It really reminds me of how we built flows. Right? That we had the hook extension first. And if you configure a new flow, you're effectively just building together a hook extension, and it's all the exact same underlying, underlying logic and event based system, which is also why, you know, flows you can do it say the same stuff as you can in a hook.\u003C/p>\u003Cp>Right? Well, same events. I mean, you can, of course, in a hook, you can code it yourself. So I'm very glad that we're making this, you know, a foundational upgrade to the schema snapshotting engine rather than trying to make it yet a new thing cool cool cool well that all being said I see we're at time here. Let me just quickly briefly peek at the chat.\u003C/p>\u003Cp>Do we missed anything? Pascal mentioned dynamic collection of field names will be cool. EG importing third party templates so you can choose your own target names. Good point. I think a similar goes for the conflict resolution piece that we talked about.\u003C/p>\u003Cp>Right? If you're trying to import won't be complex. Very, very, very true. But rest assured, it will be complex, I'm sure. Cool.\u003C/p>\u003Cp>With all that being said, this will be, life on Drax. Io/tv/requestreview in about a week week's time. Also, last episode, you can find there too. Should be if you're watching this on DirectTV, it's probably somewhere over there, there, there, or down there. Is this the point where we say, like, and subscribe?\u003C/p>\u003Cp>No. We don't have that yet. It's exactly we thank you all for joining.\u003C/p>","Welcome everybody once more to a wonderful request review session here where we go over feature requests and figure it out. Now what do we do? I'm afraid we ramble on for about an hour about the technical complexities. Remember, the goal here is to basically divergently discuss, you know, what is the feature request, what are we trying to do, what is it trying to achieve, And how do we think we can make it happen in a very sort of direct to see way? What are we talking about this week? Yes. We're talking about configuration. Configuration as code. Let's let's figure out how to take schema endpoints to the max and actually Schema endpoints to the max. Manage the entire project as code. So this is really with a focus on GitOps. Right? Where you have a sort of centralized repository of static files that is the single source of truth for all configuration of the running project. Which as you might guess, they get complicated fairly quick. Hello. And as per usual, we'll be eyeing the chat. So if you have any questions in between or any suggestions or any good thoughts, please do please do put it in the chat. I already saw his name fly by. Well, most likely I have a very special guest for you today, because our very own Connor has been researching, you know, some of this for a little while now. But before we dive into the research results there, let's discuss a little bit of the requirements that are presented here in the current feature requests. Right? Because the one thing we know now, you know, the current state of affairs, we have that schema snapshot and apply endpoint, that we use and sort of recommend for, you know, moving bits of schema, to and from dev to prod, that sort of thing. But as people have pointed out, you know, that is still for schema only. Right? So we know one of the big requirements for this is gonna be you need to figure out additional configuration, additional additional, data points maybe from your own tables, you know, environment migrations, like you mentioned there, which includes, you know, what about roles? What about flows? What about presets? What about translation strings, etcetera? This well, one of the complexities for this is figuring out, you know, what is configuration within the context of directives in the first place. Right? Which is a discussion topic that I have had some trouble with just going through myself already, which is what is configuration? You know, are your roles and the way you configured permission configured, you know, permissions configuration, probably. But the users within those roles, probably not. But then users with static tokens, maybe. Right? If you have your own tables, maybe you have a single, you know, app settings, singleton collection that you use for configuration is that now configuration that is part of code first configuration. Right? Even though it's not a system table and you're not configuring directives, you might still be configuring other things. Although, that's where the fun starts. So maybe we could scroll down a little bit, Jonathan, just take a quick peek through, the other the motivation and the requirements here. So, you know, as we kinda touched on already, the same here from, Erif van Oort. Pretty sure that would be a Dutch user. It's it's about things like permission logic, you know, keep the local dev environment in sync, source control is the source of truth. Right? You wanna make sure that you can spin up new Directus instances not completely empty, but start it from, you know, a template that is in your repo. If there's an issue, you can easily, you know, share, the configuration of your platform. Daniel, if you would kindly mute, you're being very annoying. From the replying system, this is immediately where where it gets complicated. Right? It's like, what is configuration? Right? What is configuration? When it comes to import export, how to define what gets imported, what gets exported? Basically, the same question to me. Right? How does it get imported? You know, are you merging stuff? Are you overwriting stuff? What happens if you try to insert something that already exists? You know? How do you deal with conflicts? Very good question. So if you wanna scroll down a little bit further to see what else is in here. Yeah. No. I don't know about that point. That's a good question, but a very, very long one to answer properly. But the gist is, you know, if you work with multiple people with different setups and if somebody changes your database schema, for example, how do you synchronize the state between your instance and another instance? You can do that with our schema endpoint. You can we already have that, capability. But, technically, you would want to or ideally let's say ideally, you would want to set up your configuration as code, because then you have a single source of truth. If you're developing a new feature, for example, you need a new table, you need new fields, you want to test something, you wanna try something, but then you, you know, delete some fields, How do you get the changes synchronized between different setups? And even the problem gets even larger if you have an organization, for example, with, let's say, I don't know, one dev department of, like, 8 people, for example. Stuff gets really gnarly really quick. How do you synchronize then between 8 people, for example, between different branches, different features, different collections, different fields? You know. Let alone a test team of 200. Right? Yeah. And this this is, you know, for a very small team, it can get quite gnarly pretty quickly. But, you know Yeah. There's a couple other things there too. Right? When it comes to the git repo flow specifically is that any change to the schema of the project is now sort of, like, version controlled, so you know what happened when and you can roll back. And you have accountability because you know who made the change, through that sort of git first approach. Right? The other main thing there too, I think, is from a database template, you don't have files, which is one thing we'll touch on in a and the second thing is it's database vendor specific. That's another thing. Right? Like, you could plop the whole SQLite file in a repo, but, you know, if you wanna move if you have a local dev instance that uses SQLite and you wanna go push your change into production in Postgres, now you have a workflow trouble. Right? Even if you have local Postgres, the server Postgres, you might go, you know, I don't know, Postgres 10 to 13 or something. If there's a version mismatch, you know, there's there's things to to consider there. Of course, there's third party tools. I see Ansible mentioned here that you can use to sort of move databases across, sort of thing. This would really be sort of direct as native way to move configuration around. Right? Which I personally see it as an improvement or an upgrade to the schema snapshot system that we have rather than a completely new thing. Just the real question just becomes, you know, how do we add more stuff into that so you can use it for this? That's that's really the, to me, the the underlying discussion. Right. Jonathan, if you wanna scroll down a little bit further, you can see if there's any other points. Wanna make sure we don't forget. Export considerations, multiple files. I think that's a very important requirement because we've already seen some of the schema snapshots just get bonkers large. Right? Because if you have a 1,000 collections, a total of 25 100 fields sounds insane, but it happens in the wild. The one export file, you know, is is megabytes and megabytes and megabytes worth of of JSON. Tens if not 100, which gets unwieldy pretty quick. It also makes it more difficult to import, by the way, because we're not really able to stream it all that well and then it becomes a very large file. So you have to read it into memory and then and then use it. Let's see. Selective export. That, I think, is a tricky one. Right? How do you know what you're exporting if you, consider your roles and permissions part of this, but you have one admin dev role that you don't care about for your production instance, How do you pick and choose? Right? Pick and choose what to what to include, what what not to include, and handling, you know, sensitive data. Very good point. You know, is this gonna be plain text in a static file? Tricky. Right? Tricky in a repo. If you scroll down a little bit further, The modular files of extensions, single file per collection, you know, we kinda test. Does does it actually make more sense to have selective import versus export? Great question. Great great question. Maybe. Maybe. Yeah. It's it's like if you have Go. I'm sorry. Go ahead. I I don't have to remember to mute and unmute myself between every sentence. That's fine. Yeah. I can see both being very useful. Right? For example, if if you have a very, very large, instance with, like, Greg mentioned, right, like, a 1,000 collections, And on your dev instance, you only want to add one thing, do you really need to export, like, this whole thing that's, like, I don't know, 10 megabytes or whatever? Maybe, you know, maybe, it would be enough to just export that table with its fields, and you'd be good to go, because then you could import that partial instance, maybe. But, yeah, for for import or for export, both could be useful. But, yeah, like we said, it's just lots lots and lots of stuff to talk about there. Yeah. TBD is is the honest answer. I I also feel like both is probably where we need to end up with that. Because to your point, if you have a large project and you only care about a small subset of that as a sort of templatable piece, you know, you don't want to export everything and have a bunch of unneeded data in your repo muddying up, you know, the workflow and the reviews. Because then also imagine that you make an export and then now you have a PR of, like, 16,000 lines of stuff that you don't really need. Right? But, yeah, let's see. Extend, you know, existing schema files. That's an interesting one. Merging multiple together, importing snippets from other files, maybe, you know, from nested collections. So that's all about, you know, the the file structure for the project. Saving the non defaults, I think that is more of a technical requirement to me. Right? It's like we don't have to save default values from Directus in the schema snapshot because they're the default values. Dynamic configuration sync, it's just whenever you make a change in the studio, it auto exports basically, which feels heavy, personally. Feels a bit heavy, but could could potentially work depending on the file format. But then again, how do you choose what to export on the automated one? Right? So TBD. That's also why it's a could have. I mean, they've they've thought about it luckily. Automatic real time sync, sort of similar idea. Right? But an option in the Data Studio API triggered chrono periodically high. So the one thing I do notice in the requirements list here is that there's a lot of talk about how to get it out of Directus and in what file format, but not so much the other way around. Right? How do you get it back in? So if you have something in your repo, whatever that something is, what does that code look like and how do you get that back into the Directus instance? Right? This might be a good point actually, a nice little segue. Like I hinted at at the beginning, our very own Connor has been doing quite a lot of homework on this just to figure out, you know, the, the format and some of the ideas around this and how it could work. So if let me see if I can find him. Where is this little so many here. Look at that. Hello, Connor. What have you been what have you been up to recently? I have been up to quite a bit involving this config as code and how it plays into all the other different parts of direct disc that we wanna do. Let me get my notes up. Here we go. So you said you wanted me to talk about the structure of the exports? I think it'd be cool if you wanna give a quick overview of sort of the the research process itself. Like, what are the things that you've been looking into? What have been the considerations or requirements? And sort of the things that you found. And then dive into some initial conclusions. Sure. So what I have been going through and researching is basically we have a couple of different feature requests from config as code to templates to migrating between instances to migrating between different databases. And all of it sort of involves, you know, moving configuration between instances, moving data between instances, and moving files and assets between instances. And that is a very big task when you're trying to be database agnostic and you're trying to be efficient. You're trying to have you're trying to support multiple different use cases where sometimes you wanna overwrite everything, sometimes you just wanna bring in some stuff, sometimes you only wanna take out some stuff. Sometimes you wanna stream it all. Sometimes you wanna have the file small. So there's a lot of very different considerations that go into it, and then making it all happen with one sort of directest way of making it all magical. It becomes a very big rabbit hole that you start diving down into. And so one of the stuff one of the things that we've that I have been looking at is, you know, what are all the different use cases for it, and what are the requirements for all those different use cases? And so configuration as code is one of the use cases on there. It's not completely fleshed out yet because that was not on it's one of the later goals of what I've been working on. But with it brings, you know, how do you integrate it with CICD, you know, GitHub, GitLab. You know, do you have your own hosted GitHub, You know, self hosted GitHub. You know? Where do all your stuff is stored? And so there's a whole bunch of different parts of it. Right now with the schema service, we go and we give you you export a schema of your stuff. It exports everything. You diff it against your instance, and then you apply that diff, and it gives you, like, the changes if you can do it or not. And right now, that's really it. There's not really too much to the schema service outside of that right now, and adding in all these different layers and features. The schema service is definitely gonna have to take a new look to it. And so one of the things that we've been looking at is, you know, that initial export of a schema, you know, making it more of a distributable type of folder structure file structure, whether it's a compressed zip file or some type of other special file. But basically redefining how that schema export looks to be able to hold all these different configuration items, to be able to hold data, to be able to hold assets, and defining that structure and, you know, you know, as Ryke mentioned earlier, you know, do you want that stuff stored in plain text or do you want it to be stored in, you know, some type of encrypted format or do you want it to be compressed? So there's a lot of different variables there. And then once you take that distributable that gets made, it can be I mean, for some instances, if you've pulled out data and assets and configuration, you know, that thing could be huge. And so we wanna go we wanna bring that into the this new instance of the target instance. Right? And so we need to different and change it. And so bringing all that in and processing in is a whole another thing. You know, do you wanna bring in all of it? You know, you have all the export controls. Do you wanna have import controls to how it gets implied and, you know, how it gets imported? And so I've been going through and documenting all those different ways that we can do stuff, you know, what is dependent, you know, if we wanna do this, then, you know, we have to do that, you know. And so we've been looking at one of the things this week, you know, is what type of file format for all of this type of stuff, for how it gets really big. You know, if it gets a lot of data, if somebody has a 1,000 collections and 4,000 fields, you know, is a CSV file, a JSON file really the right file structure to store all of that data? And so we've been looking at, you know, different options and different file formats for storing, you know, structured data like that in an efficient compressed way that also lets you keep the schema of the schema export defined and structured in a way. And then also making sure that we keep that same right now, we hash the schemas and stuff so that they all stay. You know? You could only use the schema to apply to this instance because you just did it with it and yada yada. So having that in there too, you know, do we have a metadata file inside of that export that, you know, talks about what the export is? You know, do we have it? Do these become an extension type, you know, that can be used throughout the instance in different places? You know, there's a whole bunch of different options there. Yeah. Yeah. Absolutely. It was a great intro. Yeah. It was a very good yeah. Exactly. Exactly. Yeah. So the first order of business to your point, you know, figuring out what does that file format look like. We know some of the requirements now based on this discussion that we just looked at. We know some of the the downsides of the current format. So that's a great step. Then, of course, the second big step will be figuring out, you know, how do you go from that sort of source of truth overview into applying it for realsies. Right? So we have that sort of diff step in between. So for those unaware right now, if you upload a schema snapshot into the Directus API, it will compare it to the current state of the database and then return, you you know, the the the list of differences, basically. So it's a diff, not a list of changes. As in a step step by step list, it's just a diff, like an a a versus b. And then that diff is then uploaded to an apply endpoint, which will basically, you know, apply the changes required to get rid of the diff, right, to make sure that the that the 2 are in sync, that the instance is in sync with your file export. So based on that, Connor, we've done some research on what needs to happen on that diff endpoint itself too. You wanna you wanna share some insights on what we know now, at least, are some of the requirements to make that work properly with all of these new new additional features that we're trying to add in. Yeah. So with that dipping endpoint, some of the things that we are looking at is, number 1, if you wanna bring in data. Right? You know, how do you diff large amounts of data? Are you able to diff large amounts of data? That's one of the research things that's on the list. You know? Right now, we have an import and export service to import and export data. Looking at Attica drive run options. You know? Can you import this data? Can you export this data, for that diffing stuff? You know, if you have a really big file, so you do have 300,000 collections and fields, you know, that's gonna take a long time to make changes to the database and to go through and find that diff. And so having some type of long task runner on the instance that's able to sit there and work through that to that, diff or making that diff or distributable or whatever it is. You know, having such a long running service of the background of your instance, I can handle that. And then also if you're going through and you're applying all these big changes or diffing it or whatever, you don't want people in your instance changing the stuff as you're trying to change stuff. So implementing some sort of maintenance mode on your instance that basically locks it down and puts it, hey. We're making changes right now. You know, you can't it doesn't let anyone else change the schema or anything or the data or whatever you want it to do. We also, have been looking at, you know, for asset data, you know, pulling in you know, do you pull it in from the distributable file, or do you pull it in from the data the asset source? You know, do you pull it in from the s three bucket directly? You know, do you use it like that, or do you package it into the distributable? Or, but, basically, for the diffing part, the other part is that if you have a really, really big distributable or schema thing, whatever it ends up being called, you also upload downloading it from one instance, uploading it to another instance just to download another big thing, just to upload the other big thing back again is a lot of moving back and forth of all this different stuff. And so the other thing is when you upload that schema, whatever, it diffs it. Instead of it downloading the diff back to you, then you having to send it back up, it being able to just keep the diff on the instance and you just being able to tell it to apply the storage diff that it already has. And so you don't have to have that all that network changing back and forth, and then, you know, Internet goes out, then you're screwed. You know? But that's one of the things that we've also been looking at for the diffing. And then another thing is, you know, different types of strategies of diffing and importing. So that, you know, do you just wanna up cert stuff? Do you just wanna add new things and you wanna ignore everything else that has conflicts? Or do you want it to only apply if there are no conflicts, you know, or do you want it to overwrite everything, you know, so it doesn't matter if there's conflict. We're gonna rewrite over it with everything, you know. And then instead of just returning a singular diff that just compares the 2 different schemas and it just says, hey this is what's different. You know putting in more migration like making it more of a step type thing. So it works through migration steps. And, you know, oh, you need to do this. You need to do this. You need to do this. You need to do this. And basically a workflow that the thing can work through and and guide those long running task runners on what to do and how to configure your instance. And I think last but not least, the having some sort of format to expose potential conflicts for manual resolution. Right? So if one of the strategies has to be that it's up to the end user to pick and choose what to do. So imagine if you go, you know, from a dev to prod, life cycle, right, where you're not so much delete everything and insert everything, you wouldn't wanna do that in a prod obviously, And if you have an absurd strategy, but there is a conflict, right, you you have, like, a foreign key that doesn't work anymore or something like that. There needs to be some sort of format in whatever this diff looks like or this migration step format looks like that just has, a list of Here's the steps with the known conflict What do you wanna do? Right? How do you wanna modify that that step, those steps to get around the conflict? Right? Do you wanna upload, you wanna upload new data, or do you wanna, ignore that particular step, or do you wanna ignore those records? You know? So to your point, if we need some sort of driver and to check if you can import all of the data, it's sort of a requirement in order to be able to extract, you know, potential conflicts. So we need to have some sort of way to search through the data you're trying to apply, in order to know how to deal with conflicts. Right? So now that we're talking about all of this, what we're what we started to notice is that we're not so much talking about, you know, configuration as code specifically or templating specifically. What we're basically shaping here is a system that works for multiple things, right? Depending on how you use it. So if you were to make, a snapshot of everything, just full stop everything, and you import it as as apply everything, what you're talking about now is basically backup restore. Right? If you're exporting a small fragment and you're importing that into another project, you're basically talking about templating. Right? If you're exporting just the schema part and no data and you apply that to a new project, you're you're talking about seeding or something. You know what I mean? Like preparing preparing, a database basically, a a new project for what you wanted to do. And the question now is, how does that how does that all tie together how does that tie back into the configuration as code parts specifically, Connor? Because what we're talking about now is, you know, a new sort of format, generated by Directus that you can save somewhere, you know, which is fairly still, it's still fairly proprietary because it will have to be heavily compressed and, you know, directors needs to know what the format is. So what is the current thinking on tying it back into the code side of this question? Right? Yeah. So if we went the route of having some sort of distributable file structure folder structure that is some proprietary format or is encrypted or compressed or whatever, you know, you're not gonna be able to sit there and write code that is a compressed file. You know, you're gonna have to have write something that generates that file. So one thought that we've been having is following the lead of some other types of, you know, companies like AWS and their SDKs. So, basically, having some type of SDK that you can write and configure your instance with, and then you tell the CLI or whatever to execute that, read those different set the code that you've written, and then it will make a direct distributable file, diff file, whatever it is, from the code that you've read. So if you wanna go through and you wanna define all of your collections and your fields or whatever, and you can go in and define that in all your files and your code and then execute that code, it comes up. It generates that file that you can then use to apply those changes, import those changes, diff those changes to any of your target instances that you want to. Jonathan, if you might be wanna pull up, I think one one piece of inspiration that we were looking at for that part specifically was AWS's, what do we call it? CDK, I think, code development kit. If you wanna quickly Google that, it could be it could prove like, it could put some flavor to that to that point. So the way AWS has that, they basically made a JavaScript library that you can use to code, like, configuration. And then what it does under the hood is it effectively converts it into, a CloudFormation template, I wanna say, and then applies it immediately. Right? So under the hoot, you don't really notice the difference, but it's effectively a 1, 2 jump. Right? So it converts it into their proprietary thing in the middle first and then just applies that as is. What am I searching for? Sorry. CDK, the cloud development kit. If you wanna pull up the GitHub repo for that, maybe I have a link somewhere. I'm just curious if they have some some examples somewhere. It's been a minute since I've played with this, but it's an interesting, idea. There was a Directus community library, a little while back that that tried doing a similar thing, but it would run it against the API endpoints. It wasn't as flexible yet because we didn't have we don't have, you know, GreenStep. Is this branch? You know. If you wanna do AWS before that, because I think CD case is all different. Yeah. There we go. There's a link in the chat as Open it up. Here we go. Here we go. Here we go. Is it gonna go? There it goes. So this is an interesting reference for people that wanna look it up. At home, it's basically, you know what was that? Distracted by the chat immediately. Using something like CDK would mean that changes would need to be replicated from the UI to the generation scripts. Changes would need to be replicated. That's a great point. Yeah. How does that go both ways? Right? Because if you have that one format in the middle, directors can recreate that format in the middle. The directors wouldn't be able to recreate arbitrary JavaScript, basically. Right? So when you opt into something like that, I think it becomes a one way street by definition because we cannot figure out what parts of your JS file are, or your code because they also have some other languages, but you get the idea. And we don't know what parts of that file are auto generatable and what parts are, human created. Right? There's so there's no way to auto generate that back into a manually created file. So at that point, that's a great point, but it's the it really becomes, you know, it becomes a a one way street at that point. Some of the data community did a sort of proof of concept library to do this for, which is very interesting. So if you wanna pull up the direct to community schema builder kit repo, I just sent a link in the chat there. It was very much inspired by a similar idea where you have a JavaScript file that you use to sort of define. It's almost, you know, a declaration file rather than, you know, JavaScript, but it is still just JavaScript that runs from top to bottom. But you could define your schema and how it's applied as, you know, individual build steps, in a JavaScript. So this is where it gets real heavy on the code part of the codeless configuration. Right? And not so much just the, moving stuff around. So in in terms of big picture stuff, I really see this as the final step of whatever these changes are that we're discussing. We'll have to start with what is that new format in the middle, how is it generated, how is it used, and then see this as a way to sort of generate it into that format and then apply it automatically. Right? But, yeah, that that JavaScript syntax is an interesting interesting idea. So, yeah, I see some folk typing. This is one of those very typical director's projects where there is about 600,000 different opinions on the ideal way of doing this. And I think we we saw it in the chat immediately. Right? Shout out to a person that was like, isn't it not just the database template? Why why bother? Right? Which I can totally get behind that, but then there's a 180 or so of votes or something like that on the on the discussion. So apparently, you know, that is not an opinion that's shared. Yeah. What what's interesting is, right, because, technically, the most basic example would be something like a database migration, generally, in the beginning, you know, for the configuration as code, for example. So there's another, a similar project director, the CMS like project that I've checked out and see how they did it. And, so they handled this a little bit differently. They don't have, like, a DSL type, you know, language that defines your infrastructure or whatever. But, they went the route of as soon as a person or user, via the UI creates some type of change in the tables or the collections or however you want to call it, the instance automatically generates a migration file locally for that specific change. And, there's then a mode in the instance where you can disable any, any ability for other users to change the actual instance. So you can actually just rely on the migration files, which is an approach that you could take, you know, because a migration file then could technically do anything you'd like, you know, with with regards to, you know, the collections, the fields, whatever, even inserting, items. But, then, you know, because we're a directors, we want to that's a little too easy for us because we would like to include some type of things like, alright. How about you, locally, you develop some type of new feature, new new table, new collection, new fields. And then in order for that to work in the way that you want it to work, you need an item. You know? You need to include a new new row, data row, or an asset. This is the thing now. Because, you know, assets are not inside of the database. So we want to include assets, for example, or maybe this, of course. Nothing is, you know, set in stone, but, you know, including assets, for example. So you want to make some changes, and you need to include some assets for your changes to be even, you know, useful. So you would then have to, you know, do your changes, test it locally, include everything with the correct file name, with the correct row, whatever, or other metadata of an asset, for example. But then on production, you would have to replicate that again. So you get this back to back to step 1. Right? So this is kinda it kinda sucks, with a migration part. So even then, if we want to include this, then we get back to the issue at hand that we were talking about. Right? We want to have a process that could export something, and you can recreate that between instances and so forth and so forth. I would, I just wanted to mention that for the others in the chat because, it's not just about, you know, just adding a field because that's basically, you know, that's a basic thing, which we could solve. And I think the Director Schema Builder kit is basically that. Right? You you generate some type of syntax, which generates some type of migration. But you have to keep in mind then, of course, right, different database vendors, we have to abstract that. Because, for example, you know, in SQLite, if I remember correctly please correct me. If I remember correctly, like, you can't alter a table and introduce, like, a foreign key. You're forced to drop the table, actually, and recreate it in order to add a foreign key, for example. Other databases can do that as CLI can. So there's lots of different honest there, I'm pretty too sure that the last minor release of SQLite didn't come out too long ago. They finally do have that alter table sort of baked in. Although then, you, of course, you have the you have the side effects that it depends on your native build of SQLite on your machine, which may or may not have had. So generally speaking, historically, you've been absolutely right. It's been a nightmare and a half to to do that. Lots of fun. So I just wanted to make sure that, people in chat, you know, it's it's not about just adding a thing. It's it's a little more involved than then. And, you know, including assets and, like, the other sent. Right? Maybe there's proprietary information or whatever, and you're not allowed to leave it on your hard drive. Maybe you want to zip it, encrypt it, compress it. There's lots and lots and lots of different steps that we have to, kick off there. So alright. Oh, we got some in the chat interaction. Cool. Cool. Cool. So alright. Top to bottom. First question. What speaks against using JSON or YAML files? Instead of JavaScript, this way the changes in the webpack could also be synced back to the files easily. So for what it's worth, the the, formats that we're talking about being generated from directives would most likely be, you know, in some sort of structured format. Not quite sure if that's JSON or YAML yet or if we have to find some sort of optimized, file format to do that. Because the the the risk of JSON and YAML exports, once you start including data, you know, we no longer know how much data you wanna include. Like if we're treating this as you could use this for backup restore we could talk about a large large amount of data right at which point we need to have a very optimized structural format that may or may not be usable in that point. Right? Connor, remind me, we found like an Apache file format that could be interesting for this. I think what was it called? Parquet or something. Right? It was called Parquet. Parquet. Yeah. That would be an interesting file format for something like that. Or potentially using a SQLite database as as the exported file. Like, that's a completely different, direction. But But you get the idea. We need to have some sort of optimized compressed file format because the export file could get really large. Now, it might be an option for the way, you know, you save one of those to just save it in a sort of raw mode. Right? Where it doesn't save it compressed, at which point it's just it could be human readable YAML or or JSON, including, you know, the ability to properly, source control it. On the migration note, I think you answered that before, Daniel, like, exactly right. If you're doing auto generated migrations, it's really only for the database schema part. Like, we can't really know on your behalf if you consider, insights dashboards part of configuration or flows or something. Right? So it's it's gonna be it's gonna be tricky because people different people have different export requirements. And if you go from dev to prod, all bets are off. Right? You you never quite know what the the idea is. Creating internal libraries fiber to schema works with native access to directives rather than the API using integrations and help creating a lot of complex repetitive action. I can imagine. Yeah. Because you can write a little JavaScript for loop and just block. You have 10,000 collections. Right? But, you know, the lack of two way integration between the UI does cause issues which is the unfortunate side effect of using, you know, a programming language rather than a declarative language like yaml or JSON, for doing schema modifications like that. You're gonna lose that two way integration. That being said, you know, if Directus has a don't allow me to change the schema environment variable flag, whatever, you could make that, you could do that on purpose. Right? For a production instance, for example, I can totally imagine that you disable any sort of schema modifications just for security reasons, and and availability reasons and only allow those changes to happen through whatever system we're we're cooking up here. Right? I think default value filtering could help make the YAML auth more manageable. Fully agree. You know, we should only store the stuff that we need to know, and storing default values feels like a waste of waste of space. Then Azure is working on some sort of YAML based metadata authoring, announcing Azure data delivery net auth sales. What marketing email? Very curious. Haven't I haven't heard of that one before. If you wanna keep the GitOps thing, it should really be a text format. Good point from Tim. Which may or may not be answered from by Dominic here. If you split up between schema and content in different formats. Right? Maybe the configuration piece is all human readable file formats. But if you have a data export that is maybe there's a file size threshold. Right? If you have a very large CSV export maybe there's just a smart point where it's like, oh, you're trying to save 10,000 rows We're gonna flip it automatically into a compressed, non readable format so you get the best of both worlds. Right? Potentially. Cool. Alright. Cool. We tried. I it's something similar. Yeah. Just to, you know, chime in to regards to what you just said. So with the, like, yeah, like, yeah, we have to split that up preferably, you know, or at least, you know, required to have this as text based so you can, you know, use it in version control, whatever. And, for, like, including items, for example, you know, a ZIP is is a nice thing that you could use, but then, of course, you know, maybe this includes then items that are not, like like an old version, for example, and, you want to insert something in in where a field doesn't exist anymore, and and lots and lots and lots of other, you know, stuff. And, you can then, of course, if we then have all of the different points that we want to persist, right, like flows, permissions, the general config as it is, you could include this then also in the export with the items, so you can do both at the same time or see if it differs and then cancel the thing. But, yeah, it's, it's a fun thing. You know? There's lots and lots of things that could go wrong. There's so many. No no matter what, we wanna make sure that the output file is a single distributable. Right? We do wanna make sure because we on the one hand, we're saying we have to split it up into multiple files in order to make it efficient and easy to work with, But, at the same time, we also wanna make sure that you have a singular thing, singular file that you can send over, to somebody else. Right? Either through the API, so you just have a single download or a single upload, or as a file, maybe packaged through, you know, the marketplace. Shout out. Wink wink. Notch notch. Or as, just to email it to somebody for a like air. Right? Put it in a GitHub issue as a zip. So there needs to be some sort of both. Right? But I could also imagine that, you know, the API, lets you download it as just a zip, right, that you can just double click to open if you're on macOS or do whatever else it takes on other platforms, to unzip it. Looking at you, Daniel, I'm sure there's a 2 step process. For those who, out out of the loop, he's, this is the year of Linux on the desktop, evangelist within the team. Yes. This year. Here it is. This is the year. Mark my words. And this year is the year of the Linux desktop. This year. Yes. But long story short, we it's it's we're we're in that weird in between that we need both. Right? We need both the single file and multiple files. So we'll most likely have to come out with some sort of zip, gzip, something like that in between. Cool. Prisma migrations are an interesting way of doing things. They have a custom format, which is more concise than directed YAML, and then some CLI tools that create actual SQL migrations in the syncs the environment. Yeah. Great example. Right. Good example. They have they basically do with that shadow shadow database, if I'm not mistaken, that's how they keep track of those migrations step by step by step. Yep. Right? And then with the the CLI tool, it can compare your custom migration format with what they already have tracked so far. And then, you know, apply apply the diff based on that. Still has the similar I think a similar one way issue, though. Right? Because the Prisma migrations that you write manually, I don't think they can sort of update those from the others from the other side, so to speak, that a two way binding. Good point, though. Good point. Alright. Could remember. I had a problem with in the past. So, sadly, I can't remember it right now, but it was very painful. So, it's not a 100%. Yeah. It's not a 100 perfect thing. Nice. I've seen people you know, there's there's lots of other, what is it called? Drizzle drizzle right now? Oh, there's a couple of RMS like that. Yeah. Yeah. So there's there's lots of sauces that we could, you know, yoink some code from, but be inspired. Let's say be inspired. Yeah. I don't think we've been yoinked. I don't think we've legitimately ever yoinked code before. Borrow. Borrow. See. Strategies is interesting there. But the the the main difference and then you you touched on it perfectly before. The main difference there is the just keeping track of the database schema versus having that ability to just sort of manual template in between moving stuff between dev and prod that is not just schema, but also data and how to deal with that, which at any point needs to be, something you can do manually. Right? It doesn't have to be manual all the time, but it needs to be something you can do manually Right? Cool. Well, with all that being said, looking at the clock here Connor, back to you. We've discussed quite a lot of the research up until this point, some of the requirements. You and I have also sort of been daydreaming about potential ways to implement this moving forwards. You wanna quickly touch on sort of the different, different phases and different sort of parts that we wanna touch as part of this bigger bigger effort? Yeah. So the first thing we wanna do is we wanna figure out how this is gonna look, the distributable, the diffing. What is that file structure? What's the file format? You know, what are the requirements for that? Do we have encryption? Do we have multiple files? Do we have one file? Do we have whatever? Like, we've already discussed here. First thing is defining what that'll look like in totality, covering all use cases so that as we progress through the the phases of this project and making it happen, we can keep that spec that we have for those files in mind, and we can make sure that we cover everything whenever we could work through the different phases. But the that is phase 0 to finding out that spec, figuring it out what it looks like. Phase 2 or phase 1 would be upgrading the schema service foundationally right now. So making sure we have all the bug fixes with the schema service taken care of, you know, adding the new different, you know, different strategies that to it that might be needed. You know? Do we have, you know, add in those exports, export filters, you know, only export this stuff, you know, that stuff. So getting that schema service, adding some more features to it. And then the next phase is working on data importing. And so adding in the different features that would be needed to make the data importing work, You know, dry running, imported data, importing strategies. You know, do we have a import strategy where right now everything just gets up sorted? Do we wanna have an import strategy where if you import the data, it drops all the current date data in the table and re imports everything fresh? You know, adding those different options. Some other just things, ideas that have been thrown in the mix is, you know, if you're moving between one instance to another instance and you don't wanna bring any of your IDs, your primary keys, your foreign keys, you know, adding some type of way to anonymize that as it goes from one instance to another. So the new instance makes new IDs for everything. Or adding, you know, the ability to for, like, templates, you know, if I wanna bring in a template for project management and have a due date in one of the items, but I made the template a year ago, then the due date's gonna be from a year ago. So, you know, being able to have dynamic data that gets brought in on import. And so, you know, oh, I want you to import this as a date, but make it for in 2 hours after the import is when it's set. And then the next phase after that, working on data importing is getting into putting it all together. So we've worked on the spec for the thing. We worked on the schema service. We worked on data importing. Now we need to bring it all together into this this new overhaul configuration, multimodal thing, and have it work on bring all those pieces together and make it work, basically. And then after that, once we've gotten the specs spec'd out, the schema service upgraded, the data importing upgraded, we brought it all together, and it now works foundationally. Now we need to figure out how do we use this to implement these different use cases? So for templating, you know, what do we build inside of the data studio admin app from a user interface and API perspective to make templating work? What do we do from the configuration as code to use the stuff that we've already built? So how do we implement the feature set that we want in the configuration as code use case. You know, are there any other use cases? You know, back up being and restoring an instance. Do we have the feature set that we wanna use for that? And then that should, in theory, wrap up the project after that, after we figure out and implement those use cases. So there's quite a few steps here. Quite a lot of different items and it's going to take a long time. But at the end, we should have something pretty cool. Ideally. Yeah. And I think I think Daniel's facial expressions told told the whole story. No. But that'll I mean, it'll make sense to me. It sounds it sounds like a large overwhelming amount of stuff as it usually does. But by breaking it up, you know, step by step like this, we actually have a pretty solid idea, you know, start to finish of of what is involved to getting that across the finish line. And, yeah, as per usual, you know, there's a lot of, what's the word? Direct this magic going on under the hood to to tie it all together. But I'm always just very excited and glad that we're able to sort of re envision this as we have one underlying core foundational engine that can power all of those different use cases. Right? Rather than trying to tack on a new sort of templating piece and a new sort of code first configuration piece and a new sort of other piece. Right? That just increases the tech that makes it hard to maintain. It makes it those different flavors incompatible. You know, somebody will ask, how do we do a template as code? And we're like, well, you can't because code is not for templating. You know, that kind of stuff. It really reminds me of how we built flows. Right? That we had the hook extension first. And if you configure a new flow, you're effectively just building together a hook extension, and it's all the exact same underlying, underlying logic and event based system, which is also why, you know, flows you can do it say the same stuff as you can in a hook. Right? Well, same events. I mean, you can, of course, in a hook, you can code it yourself. So I'm very glad that we're making this, you know, a foundational upgrade to the schema snapshotting engine rather than trying to make it yet a new thing cool cool cool well that all being said I see we're at time here. Let me just quickly briefly peek at the chat. Do we missed anything? Pascal mentioned dynamic collection of field names will be cool. EG importing third party templates so you can choose your own target names. Good point. I think a similar goes for the conflict resolution piece that we talked about. Right? If you're trying to import won't be complex. Very, very, very true. But rest assured, it will be complex, I'm sure. Cool. With all that being said, this will be, life on Drax. Io/tv/requestreview in about a week week's time. Also, last episode, you can find there too. Should be if you're watching this on DirectTV, it's probably somewhere over there, there, there, or down there. Is this the point where we say, like, and subscribe? No. We don't have that yet. It's exactly we thank you all for joining.",[201,202,203],"a09a4ffe-1990-4313-bf15-fd8840a5036d","72808a44-0e90-42e5-b48d-7298d0ed4294","b60bedda-7ca6-412b-ae38-c664024bcebe",[],{"id":133,"number":134,"show":122,"year":135,"episodes":206},[137,138,139,140,141,142,143,144,145,146,147,148,149],{"id":139,"slug":208,"vimeo_id":209,"description":210,"tile":211,"length":212,"resources":213,"people":216,"episode_number":220,"published":221,"title":222,"video_transcript_html":223,"video_transcript_text":224,"content":8,"seo":8,"status":130,"episode_people":225,"recommendations":229,"season":230},"flows-log","912263898","In this recording of our live event on February 8 2024, Rijk, Jonathan, and Daniel discuss improvements to our no-code automation builder - Flows.","f89ae85c-4df4-4b9e-86db-8ca73f5980ba",55,[214],{"name":159,"url":215},"https://github.com/directus/directus/discussions/15870",[217,218,219],{"name":163,"url":164},{"name":166,"url":167},{"name":169,"url":170},3,"2024-02-15","Improvements to Flows Debugging","\u003Cp>Speaker 0: Alright. Yeah. So, Jonathan, you already, briefly introduced that seeing all the hiccups, I don't know if we're gonna cut that. But just to restart it, we're gonna be talking about flows today. We're really gonna be starting with this 15 8 70 about improving the activity panel.\u003C/p>\u003Cp>But, realistically, as far as I'm concerned, it's sort of a smaller piece of a bigger discussion around upgrades to flows. Right? So for those out of the loop, we introduced that flow system as a way to do event based, actions and operations, kinda like you could with hooks, or custom endpoints, but doing it in a no code type of way. Right? So you configure when you want your flow to trigger and then step by step configure individual operations, individual nodes of sort of this this path, that you wanna execute.\u003C/p>\u003Cp>The original version of that was really much designed as a, start with the basics, see what people wanna use it for, see where what what the best improvements are gonna be. So we shipped it a little bit lightweight, you know, with a handful of operations and have been more and more over time. But it has been becoming increasingly obvious that there's, a lot of improvements that would be really nice to have, especially when it comes to debugging, sort of helping configuring some of these pieces. So with that being said\u003C/p>\u003Cp>Speaker 1: Yes.\u003C/p>\u003Cp>Speaker 0: Discussion. So for Daniel, who's flying blind here, we're looking at the one about the logs first. Right? So if you're currently running a flow, optionally if you have it enabled, it's enabled by default. It will keep track of the data that sort of went through the various operations, and then saves it to, a logs tab that you can see on the right hand side of the flow.\u003C/p>\u003Cp>This is basically the primary way at the moment where you can debug what is happening under the hood, because otherwise, you know, there it's it's the way where you can see what data came actually through the trigger and how you've modified the data points in between. So over the Jonathan, you're you're showing it out what that looks like now on your own instance. What are some of the points in this initial discussion that triggered this this conversation? You've got\u003C/p>\u003Cp>Speaker 2: a lot of the ease and access to that information, as well as the ability to control, like, durations. Some of the problems we run into with flows, especially if someone once they get them into production, if they still have the activity and logging turned on, you can fill up your activity revisions tables really quickly. And there's you know, the mechanisms for cleaning that up are, you know, another flow, or direct database access or other kinds of things where you've gotta manage your activity and revision logs and so forth. Common recommendation that I make is once you've done your testing and you've got your flows functioning is to disable the activity and logging. But there are cases where you may want that and logging just for audit trackability on actions and things that people are doing with flows.\u003C/p>\u003Cp>So, I think some of that is just the general trigger and management of that. Other things that, tend to cause struggle for people in flows is the way that you access this instead of being able to say, look at the data from the log directly in something that I'm working on. There's been a again, there's a number of ways that we can kind of shake and look at this. But the general thing is this kinda lives over here. I can't edit this while I'm looking at this, so the the interactions with logs and the work that you're doing is kind of a it's a bit of a hindrance when you're doing the development phase of flow development.\u003C/p>\u003Cp>So it's just a more a nuisance than anything else. But the the inability to say edit something here, I have to actually come here to check. So if I'm looking for variables or data or what are the things looking like in here, what's my payload? Now I've gotta remember this data structure or copy this data somewhere else because I wanna actually do something with it. I wanna interact with it.\u003C/p>\u003Cp>I wanna use those variables. So it's kind of a it's a weird transition kind of back and forth. Some of the systems that we we got in some inbound activity on some other tickets and feedback that we got from some clients on the enterprise side, was you know, they showed showed us some other systems that have similar no code kinds of flow capabilities. And logs, instead of living in, like, a side panel in a weird way, kind of live with the operations themselves. So there's just some general ideas and thoughts around how that interaction in the UX kind of works.\u003C/p>\u003Cp>Data wise, I don't think anybody's complaining about the information that shows up in here. That tends to be you know, it's fairly easy to work with and deal with. I think it's more the kind of user interactions with data.\u003C/p>\u003Cp>Speaker 1: Yeah. For me, personally, I've ran into this when I tried to set up a flow which triggers another flow, which then leads you to, you know, switching between those 2. And then you have to check that again, but then you forgot on the first flow, forgot something, and you have to switch back. And, you know, so people do run into this, and, I've experienced this myself. So, generally, if I if I experience this, the general user will probably also experience this.\u003C/p>\u003Cp>So this is a very valid point, in my opinion, and, we should we should improve this a little bit. You're muted, Jonathan. Sorry. You're muted.\u003C/p>\u003Cp>Speaker 0: You look very passionate, though. I'll give you that. But\u003C/p>\u003Cp>Speaker 2: Sorry. I'm not gonna mute. So so what that does is, you know and that's why we saw this very same thing as we started doing some internal research on just this ticket. We rapidly diverged into we've got 4 or 5 other kinds of spec, and that's why we it's kinda leading into this call today. We were talking about the fact that there's some general overall flows improvements that I think we'd like to see across the boards.\u003C/p>\u003Cp>But the logging and activity, you know, that's that kinda triggered this action was really about that the way that those logs interact and how you have to it's kind of a separation of what is a common function.\u003C/p>\u003Cp>Speaker 1: Yeah. Definitely. Totally agree. And, like the other comment on the chat said, switching is painful. Yes.\u003C/p>\u003Cp>An auto refresh for logs would go a very long way because I I do think that these two things are very, service the same niche, service the same pain. Because you you want to have up to date logs and see what is different, what do I have to work with, what can I work with, and not being able to have that on auto refresh, for example? Is the same thing as context switching back and forth, and you want to refresh and whatever. So I think these two pieces are very similar and and and try to work on the same pain, basically. So, good point from the chat.\u003C/p>\u003Cp>Thank you very much.\u003C/p>\u003Cp>Speaker 0: So there's a lot of lot of, I saw the word divergent on the screen. Just made me think there's a lot of divergent ideas happening at the same time. Right? We're talking about a lot of smaller optimizations like the auto refresh or some sort of way to make that context switching a little bit less painful. If we take a deeper look at this discussion, though, that sort of triggered everything, are there any particular pain points about the way we describe or show those logs that is currently sort of, something that should be improved?\u003C/p>\u003Cp>Speaker 2: I'm kinda skimming through this guy.\u003C/p>\u003Cp>Speaker 1: See some people typing in the chat. Please let us know if you have experience in using flows and would like to, contribute. We're here for you.\u003C/p>\u003Cp>Speaker 2: I think on the Trigger log\u003C/p>\u003Cp>Speaker 0: is the hardest to understand.\u003C/p>\u003Cp>Speaker 2: I'm still on. So on that log side, the other key thing that's being pointed out here is there are differences in the inbound payloads based on whether you're doing a create, update, or delete operation. You do have some variation in the trigger payload bodies. And, again, I don't know that it's a bad thing, but it is one of the things that's called out as a there's differences in the pathing, say, to the collection or the item, based on what type of event triggered the action. Yep.\u003C/p>\u003Cp>Speaker 0: Yeah. Very good one. That that makes a lot of sense, and it's it's it's explainable from a technical perspective, but also makes sense where it's where where the pain point's coming from. So earlier on, when we just did the hooks initially, the decision was made to differentiate between create a single thing and create multiple things, which in turn means that sometimes you get a single ID as a sort of, string or a number, and sometimes you get an array of ID strings or a number, which is basically just a bigger discussion around what does that hook payload look like. Right?\u003C/p>\u003Cp>Because everything is based on the same internal, event system. So, you know, a flow is triggered based on the same hook that you get from, a hook extension, for example. It's all the same thing. Then, the difference between, you know, trigger dot keys, trigger dot body dot keys, etcetera, sometimes it's payload, sometimes it's not, That really depends on the type of trigger, which, again, you know, doesn't necessarily make it make it better, but it is, you know, explainable where it's coming from, where. If you're having an endpoint, you know, with a a trigger request, now you're dealing with a sort of user payload that was submitted that could be anything.\u003C/p>\u003Cp>Right? If you're dealing with a hook, it's a pre pre known format for what our hooks fire. But, you know, it's there's a difference. There's gonna be a difference, and that is that's definitely tricky. Somebody said, if hooks supported loops, we probably wouldn't need the differentiation for 1 versus multiple.\u003C/p>\u003Cp>Hook supported loops. I'm not entirely sure what you mean by that because a hook is just a bit of JavaScript, so you could loop over whatever you want. Right? Oh, flows. Oh.\u003C/p>\u003Cp>Oh, I see. Gotcha. Gotcha. Gotcha. Gotcha.\u003C/p>\u003Cp>Yeah. So we're basically saying, you know, if you have a way to just say do this flow against every item in the triggered whatever trigger keys, then we can basically just drop the one hook and make everything an array all the time, sort of get rid of some of that confusion, which for the record Yeah. Makes a ton of sense to me. I mean, every every insert into the database could be 1 or multiple things. And if you do one thing, it's just an area of one thing.\u003C/p>\u003Cp>Right? It's basically it's it's easy to explain. So I I do agree with that sort of general sentiment. Even though for the record, that would be a quite a big breaking change and totally wreck everybody's existing flows and extensions. So TBD TBD.\u003C/p>\u003Cp>As mentioned, the extension shed will be very possible to create a repeat operation for all elements in an array extension with exposing a single function from the flows manager. Yeah. Yeah. No. Absolutely.\u003C/p>\u003Cp>Yeah. That's very true. Very true. Cool. There is one more, thing in the chat here from our very own Brian saying remembering the key names for operations is a pretty big headache for me.\u003C/p>\u003Cp>Why are the keys only showing on hover? Where can I not copy them? Which has been a thing all over the app. And just trying to remember what that key name is. That's a very good point.\u003C/p>\u003Cp>And I think, you know, overall in the app, we've sort of on the side of making things sort of, what's the right word? User friendly is such an empty thing, but, like, look pretty for nontechnical users. Right? So a lot of stuff gets, what we call title formatted. Family friendly.\u003C/p>\u003Cp>Yeah. Exactly. We we we title format a lot of that stuff, so it looks prettier in the UI. But totally. Yeah.\u003C/p>\u003Cp>For things like flow logs, you know, which is inherently a very technical thing, flows is only available for admin users, which are generally speaking, a little bit more of the on the technical side. Those should most likely just be the technical keys. Right? Render them in monospace and just lean into it. Because why why show them as a title formatted version and then have it only show on hover that you can then not copy paste because it's a tooltip.\u003C/p>\u003Cp>Right? It that that makes a ton of sense, and that is just a perfect sort of tiny little tiny little tweak that's a huge quality of life improvement. Jonathan, I hope that was in the notes somewhere now.\u003C/p>\u003Cp>Speaker 2: Yep. I'm taking some notes in in a separate section, over in the the actual internal notion doc that we've got running on this guy. So I'm trying to capture pretty much it.\u003C/p>\u003Cp>Speaker 0: Another good point here too is, like, why even have a pretty name if you just have the key? You know? Good point. Good point. I think having some sort of description is a nice, you know, nice to have where at least you can write, like, a mini description, but you wouldn't really use the name for that anyways necessarily.\u003C/p>\u003Cp>Cool. Okay. Just looking at the discussion, though, because I see we're sort of, what, 1 eighths of the way on the scroll on the page. So I'm kinda curious to see if there's any other points in this particular discussion that we haven't really touched on. That's easy to forget.\u003C/p>\u003Cp>So these ones we just looked at.\u003C/p>\u003Cp>Speaker 1: I think, the suggestion by our own\u003C/p>\u003Cp>Speaker 2: Oh, the the JSON object wrapping. Object wrapping was the other big thing. Again, having this in the side panel, data here, you can start to see if you get long things. It it actually goes off screen and ends up, you know, and you I don't even think it enables a scroll. I'm not sure you can even get to long data that's being displayed in the log there.\u003C/p>\u003Cp>So some form of wrap, at least, if we're gonna continue in this panel. I think, ultimately, I think we'd like to maybe move this out of the panel anyway. It'll end up somewhere else in the UX. But something for us to keep in mind is that JSON wrapping, and we have that captured as well in a I\u003C/p>\u003Cp>Speaker 0: was just gonna say that it's there it it's I can already also see there's no way to search or filter through logs. Right? That is another, you know, in. The only thing we show about the log is just a time stamp and then a rel as a time stamp. But I'd I'd say an obvious next step is to sort of move that out of the sidebar into just a proper, you know, layout like we do with other things all over the place.\u003C/p>\u003Cp>So you get the searching, you get the filtering, and we can have a proper detailed view, or draw our although a detail page is probably gonna be nicer for that. Save a little bit more space, for things like that overflowing scroll and just presenting it nicer. Although, then, you know, we create a new problem, which is now the logs live outside of the flow where you configure them. So at that point, you know, we also wanna make sure that we have some sort of way where you can render that maybe as a split view, maybe you can sort of 50 50 between the flow that you're creating and then seeing the logs of that flow with this layout. Because I do believe that keeping them in context or at least having some sort of link back and forth, from, you know, where you're configuring the the law, the flow and configuring the log is gonna be important.\u003C/p>\u003Cp>Speaker 1: From\u003C/p>\u003Cp>Speaker 0: the chat, having logs and operations might be helpful for that. Yes. Yes. Yes and no. It's it's I'm I'm, to me, the logs on operations is an addition, not a replacement.\u003C/p>\u003Cp>I think personally it's very valuable that you can see, you know, the full, execution path in a log. You can see, you know, at 2 pm today we started with this, we started with it, that one failed, and then we did this, and then here's the data that went through it and what we concluded with. I do think it's important to have that sort of consolidated together, but the the logs and operations, I do agree, would have really be a really nice addition to that where you can just look like, okay. In the last couple of runs, here's the day that it came in and went out of this particular box in your flow. Right?\u003C/p>\u003Cp>I don't know if that's gonna be a deep link or maybe just an info.\u003C/p>\u003Cp>Speaker 2: Almost feels like you could have, like, a split panel down here that had the normal, like, search layout capabilities of searching through the logs, could be an interesting use case for this where you'd Mhmm. Similar to Visual Studio and other kinds of console logs where when you're doing this kind of development, you've got logging information you can see down here. Because I also think some of the other nice things with flows would be able to have, like, step through. Right? Being able to step through and see data at certain points, what's going on as you're debugging and working on the flow itself.\u003C/p>\u003Cp>But then as you say, having an actual, you know, log panel or maybe there's a, like, in a sub ten under flows where you can go to the logs and just see logs full screen, be able to search. Because once my flow is operating, I think the the DERF, pointed out that they're they like logs turned on so when users report issues hours later, they can go back and search the logs. And in that case, I'm not looking at the flow. I'm looking at what's the data, what's the flow, what happened, what errors, what things do I see. So\u003C/p>\u003Cp>Speaker 1: cool.\u003C/p>\u003Cp>Speaker 0: Because the nice thing by putting the again, this for for those new to the stream, this is very much a session of divergently thinking. Right? We're just gonna go brainstorm a bunch, like, what will be the ideal state and then take it back towards the end to, like, okay. What is an actual realistic next step? So I can also imagine, you know, closing your eyes thinking about it, if we have a proper detail page, like a full full screen view for the logs for one particular run.\u003C/p>\u003Cp>Right? We could actually render sort of a smaller, graphical representation of your flow as you have configured it, in in here, and then just show you. You can sort of replay it, so to speak. So we can just show you step 1, and then that's the data that came in and out based on the logs that you're looking at. Right?\u003C/p>\u003Cp>So instead of just having a long list top to bottom, you could effectively just get a visual replay, of that particular flow operation. I think that could be an interesting one too. Because then you really get to visualize the the execution of that flow because you're effectively trying to follow a path through your flow with the log. But right now, the log is always gonna be a a sort of,\u003C/p>\u003Cp>Speaker 2: what's the\u003C/p>\u003Cp>Speaker 0: right word, a one dimensional list, top to bottom. Right? Chronological. But, you're thinking about your flow, potentially, in more of a graphical tree. Right?\u003C/p>\u003Cp>Where it's like you have option b, and then you branch off, etcetera, which is not really, represented in the logs in any sort of way right now. From the chat, somebody you could almost use the exact same UI as the flow editing page for that. Yeah. No. Yeah.\u003C/p>\u003Cp>Yeah. Exactly. Maybe a little bit smaller so you have the whole thing, you know, in view at the same time, and we just can highlight whichever box we're currently showing you. Yeah. I think that could be a very interesting visual representation.\u003C/p>\u003Cp>It becomes very interactive at that point. Right? Where it's almost like, you know, the logs will just be represented with some sort of timeline bar where it's like, okay. You read operation 1 out of 16 steps, and then you can just go to the next one. Then the visual representation up top just sort of, like, highlights which box we're on.\u003C/p>\u003Cp>Right? And then just go to the next one, go to the next one, go to the next one. I still think we would have to have some sort of way where it's just, like, show me the whole thing as a JSON blob. Don't make me go through this this pretty thing, but I'm pretty hopeful that that could help, really help debug what's going on here. Speaking of which, why is the flow edit page the default?\u003C/p>\u003Cp>The view page seems kinda pointless. Yeah. Agreed. Done. So easy it can be sometimes.\u003C/p>\u003Cp>I I think the the honest answer is that kinda came from flows being initially designed as using the exact same UI and UX and order of operations as dashboards, where that is, very different, obviously, where dashboard is definitely read read only by default, and then only if you wanna change something to your panels for the order of the dashboard or that kind of stuff that you really go edit it. But in this particular case, I agree because it's like, what is really the difference between read and editing it? The only difference for read is that you can't, you know, click a button, but there's nothing that's really, you know, different between the two states. Right? So just getting rid of that read only view, I mean, it it makes sense to me, honestly.\u003C/p>\u003Cp>Food for thought. It's not not something we're just gonna we'll have to double check if that all makes sense, but just you know?\u003C/p>\u003Cp>Speaker 1: Well, let's say let's play with that thought a little bit. So let's say we make a new page, detailed page, which features everything that we want. Would we like to then be more stringent on how it looks? So maybe take away the ability to point, to to place nodes wherever you want so we can, you know, for example, make it, smaller for the detail page because we probably don't have the same amount of space as of right now. Is that something that we would like to do?\u003C/p>\u003Cp>I don't know. Like, how important is that even?\u003C/p>\u003Cp>Speaker 0: I think for the flow detail page, for the if you're talking about the flow detail page, it's not important. It's it's really more of a visual aid. This is like if you're mentally, you know, visioning what your flow looked like when you created it, you can see it sort of, like, go through the go through the motion. So it's really more meant as a graphical element that is more for, it's kinda like a map. It's kinda what I see it like.\u003C/p>\u003Cp>Right? It's it's a nice to have, not really a requirement. What I was kinda thinking we could potentially get away with though is instead of rendering the full boxes with everything in it, which just be the name or just an empty box for that matter. What we could do, though, it's I don't know if you've ever ever played with this, but if you have a dashboard set up Jonathan, do you happen to have a dashboard in this this demo instance? Plenty.\u003C/p>\u003Cp>You gotta love it. Dashboards and sort of the underlying panels and the the viewport stuff. Yeah. Exactly. It has a button that just sort of zoom out the fit.\u003C/p>\u003Cp>And also a full screen button for those who don't. Pro tip for you. So you can full screen and make it fit on your your, fit on your screen. But we could use that exact same thing for doing just sort of a mini representation of, of your flow at the top of this flow's detail log page. Right?\u003C/p>\u003Cp>Because you don't need to see all the exact details. It's mostly just as a graphical map for going through your flow. This could be a very\u003C/p>\u003Cp>Speaker 2: interesting trick. Similar similar tools I've seen, you can actually zoom in or out. You can actually zoom your view so you can see more of your flow or all of your flow. And then when you double click or click on something, then you get back into the item view or the detailed view. So back in our flows example here.\u003C/p>\u003Cp>Right? You'd be able to, you know, have a zoom option or be able to scroll in or out and zoom your view similar to a map style the way we do with the geospatial kinds of things. So very similar to that would be fun.\u003C/p>\u003Cp>Speaker 1: I wish I could see the screen right now, but, I thought there's something\u003C/p>\u003Cp>Speaker 0: Oh, right. About exhibit. I forgot.\u003C/p>\u003Cp>Speaker 1: For example, yeah, if if we decide to, you know, like, restructure the visuals or want to provide a different type of view, for example, like, we don't have to have boxes. We could also have, like, circles, for example, which could be smaller, take out the space. Maybe they're horizontal or something. I'm not sure if you showed this, right now. I'm sorry for that.\u003C/p>\u003Cp>But\u003C/p>\u003Cp>Speaker 0: Oh, no. No. No. No. It's I just I just love the the very bit of a sidebar.\u003C/p>\u003Cp>I just absolutely love the the artistic way you brought that just now. Maybe instead of rectangles, they could be circles. Yes. But yeah. No.\u003C/p>\u003Cp>You're absolutely right. Because we the nice thing is we know the exact dimensions of each box. Right? So we could theoretically, for a graphical overview, render each box at a half height and offset all of the, x and y positions by, you know, the number of boxes high To sort of recreate the diagram in a more compact view.\u003C/p>\u003Cp>Speaker 1: For sure.\u003C/p>\u003Cp>Speaker 0: Yeah. Good point. So let's let's noodle on this idea for logs on the actual operation box. Right? So would that be a, sort of additional button, I guess?\u003C/p>\u003Cp>Because I'm also sort of operating under this. It's edit mode by default all the time. So I could imagine that maybe next to the edit button, there's just some sort of logs link.\u003C/p>\u003Cp>Speaker 2: And now\u003C/p>\u003Cp>Speaker 0: that I'm thinking about it even more.\u003C/p>\u003Cp>Speaker 2: Pre filter the logs to the particular one you're looking at, all that kind of fun stuff.\u003C/p>\u003Cp>Speaker 0: Yeah. Because now that I'm thinking about it, we save the logs as one row with a bunch of JSON in it for the whole flow execution. Right? That's the, that's the log item that we have. So there's no real way to just say, give me all of the logs for just the update data operation, because you're looking about all of the, you know, all of the, all of the data from the whole flow, and then we have to sort of filter it back down.\u003C/p>\u003Cp>But, you know, we could consider, although the amount of data is gonna get out of control real quick, but we could consider saving, you know, a log row in the database for each operation step instead of for the whole flow. But we gotta make sure that we have some sort of automated retention setting and and a bunch of indexes, indices for that, to not completely wreck your database. Because if we're now creating 5 new records per flow instead of 1, then you're talking about millions and millions of data points, which, you know, depending on your database might not matter.\u003C/p>\u003Cp>Speaker 1: This has been a point in the discussion. The person that started then was already interested in some type of way to for example, similar to the activities, issue that we had, recently where, you know, big or large instances have trouble with, I don't know, I don't know, 2,000,000 activity entries and some type of schedule that clears logs or, for example, you only want to retain those who are at most, I don't know, 30 days old, for example. Some type of rule maybe which could, lighten the load a little bit would be helpful, I think.\u003C/p>\u003Cp>Speaker 0: Oh, a 100%. Yeah. Yeah. The 100%. The the main reason we haven't had that before, I haven't done that yet, is because we didn't have support for this use yet.\u003C/p>\u003Cp>Right? And that's really a requirement. Because if you wanna delete with a filter on a timestamp and you don't have an index on that timestamp, now it might take your database, you know, minutes to just go through a table of that size. So that's that's also where that sort of sprint came through to, like, support indices and now collaborating with the the contributor there to to get that across the finish line. Because then once we have proper support for indices because because I do wanna make sure that, you know, whatever we do for the system stuff needs to be available to the end user.\u003C/p>\u003Cp>Right? So once we have support for indices, we can then enable indices for the system tables for, like, the timestamp in activity and and same for flow logs and stuff. And then the second piece of that is gonna be a setting that says, what do you want your, you know, low log retention to be? And it should be an environment variable, I guess, or maybe it's a per flow option. T b t b d on that.\u003C/p>\u003Cp>Right? Maybe there's an environment variable for the the maximum number you can set, and then in the app, there's a drop down, whatever. We'll have to figure it out. But, yeah, to your point, if you can configure, I only wanna keep 7 days worth of flow logs for this flow. I feel like that's a must have for any sort of upgrade that we're gonna be doing the flows, because it's so easy to just now accidentally end up with a couple of 100.\u003C/p>\u003Cp>Actually, that reminds me, I think, Kevin the other day did a fantastic little flow that he sent over where he was using it for, for beddlesnakes. But I also saw his flow logs in the sidebar already be in the 100, and I was like, how how long have you been running this right now? Right? You're gonna have 1,000 tens of 1,000 of those, so we need to have some sort of retention for that, which I could imagine, you know, if you have a flow that you know you're running a lot and you want it to be lowers, think it has to be per flow.\u003C/p>\u003Cp>Speaker 1: Food for thought. Food for thought for sure.\u003C/p>\u003Cp>Speaker 0: So then when we're thinking about, you know, one other thing I know about the debugging of, flow specifically is that right now to test anything, you have to trigger the actual thing that triggers this. Right? So, as of right now, if, Jonathan wanted to test this ready for review flow in any way, he would have to save this, quit, go to his articles collection, and then manually trigger it. Right? Oh, it's\u003C/p>\u003Cp>Speaker 2: so painful. It is so painful to debug these things, because you have to do just that. Right? I have to go I have to go save, then I have to go to our to my systems over here. I have to go to articles.\u003C/p>\u003Cp>I mean, at this point, normally, I've got an you're already kind of nabbed here, but now I've gotta open an article, and then I've gotta go through the actions of whatever I'm testing. So ready for review case. I have to push the button, then we go back, and then we're gonna go back to flows. We go back to ready for review. Now I have to go to logs, and now I can look at logs and see what's going on, test flow or not.\u003C/p>\u003Cp>So you're in here, you're traveling through, and you're looking at your payloads, and at your options wherever you are in the debug process, then you're closing out. Now you're going back to edit. So many mouse\u003C/p>\u003Cp>Speaker 0: It's a pain is what I'm hearing. It's a pain in the butt. Flow is\u003C/p>\u003Cp>Speaker 2: awesome, but it is it is painful to do the administration.\u003C/p>\u003Cp>Speaker 0: That's why we're here.\u003C/p>\u003Cp>Speaker 2: That's why we're here.\u003C/p>\u003Cp>Speaker 1: Yeah. So one thing I think just wanna add another point from from him. Yeah. Sorry.\u003C/p>\u003Cp>Speaker 0: Go. Go. Go. Go. No.\u003C/p>\u003Cp>Please. Please. Yeah. Yeah.\u003C/p>\u003Cp>Speaker 1: Because, this this then touches the issue of alright, so let's you you want to create a flow. You want to try it out. You have to try it out in order to actually make it work. But then comes the thing, alright, so let's say I have an existing flow, and it's running. It should continue on running, but I want to, I want to edit it without changing the actual running flow, which would technically be something like, alright.\u003C/p>\u003Cp>Let's duplicate this flow so I can play around with it. And then, after I'm done with my modification, then I switch them or, basically, disable the previous one and enable the next one. So some type of let's let's call it, like, very, very lightly versioning. Yes. Oh, the chat.\u003C/p>\u003Cp>The chat is exactly it.\u003C/p>\u003Cp>Speaker 0: Once they\u003C/p>\u003Cp>Speaker 1: have the\u003C/p>\u003Cp>Speaker 0: whole tag.\u003C/p>\u003Cp>Speaker 1: Right. So so if, yeah, if you have a couple of, like, important very important flows running in production systems, you don't want to, you know, edit them willy nilly. So that's the that's the another thing, which is can be can be painful because as of right now, there's technically no duplicate button, which is, not as nice as it could be.\u003C/p>\u003Cp>Speaker 0: And, it's it's a difficult one, isn't it? Because I'm also thinking about some of the triggers. Would that make sense? Because if you make a new version of a an endpoint, right, and an endpoint has a UUID to run it. But then if you create a duplicate, now the endpoint is different.\u003C/p>\u003Cp>So then if you wanna make that your production one, now you have a different endpoint. Right? So it's like the the duplicate and then kill the old one flow pun intended of updating flows might not work for every trigger. Also, if you create a new version of a flow that uses, like, an event hook for, like, an item save on articles or something, like, in this example. Yeah.\u003C/p>\u003Cp>It would have to be some sort of dedicated versioning because if you create a duplicate, then now you're firing both of your flows. Right?\u003C/p>\u003Cp>Speaker 1: You know, a very, like, naive solution to that event problem would be to have the duplicated flow immediately be set to disabled. So if you duplicate duplicate something, the duplicate one is disabled, so it doesn't fire. And then you can play around with it, change something, and then enable it yourself. Yeah.\u003C/p>\u003Cp>Speaker 0: Somebody in the chat that or somebody's plural in the chat, we're also saying, you know, you can obviously have a local dev instance or a dev copy where you could configure a new flow and then sort of import it at once so you don't, you know, mess anything up on production. Very true. Very true. Wanna make sure, you know, we keep we can Yeah. All the use ASM license.\u003C/p>\u003Cp>Speaker 1: This this then goes hand in hand with the next thing that I wanted to bring up with with the same thing. So let's say you have your dev instance, and then you want to sync your synchronize your flow to the production instance. Alright? There's no version control, basically. If you don't use, like, an actual extension, which you can put into your Git, version control, you would have to manually duplicate or use the API or something to to get the flow over or synchronize between your two instances.\u003C/p>\u003Cp>Mhmm.\u003C/p>\u003Cp>Speaker 0: Well, luckily, we talked about that particular problem 2 weeks ago in the last episode.\u003C/p>\u003Cp>Speaker 1: That's exactly right.\u003C/p>\u003Cp>Speaker 0: Like and subscribe. Exactly. The link right below the like button. Is that what they say?\u003C/p>\u003Cp>Speaker 1: Yeah. I'm gonna have the sidebar here.\u003C/p>\u003Cp>Speaker 0: Exactly. Circling back, though, because we we have, I think, 2 or 3 different, UX points with, like, a couple of different solutions. So one thing that I think is a must have for sort of this flows upgrade project that we're putting together here is that there needs to be a button on the trigger where you can manually trigger that trigger. The difficulty will be what data do we trigger it with, and how can we help you make that data realistic? Right?\u003C/p>\u003Cp>That is gonna be the difficulty there, which is kind of what we haven't done before. Because right now, with this manual trigger on an article, you know, the data format for that, like we talked about with the chat a little bit earlier, it's very specific to that particular article and that particular, data model for the article if it's like a filter hook or something. So if you have a manual play button, so to speak, we need to have some sort of way where you can sort of fake what that event looks like. We can pre pre generate a couple of ones based on your instance, I guess. Because, like, we know for the manual trigger that you get the primary key of an article.\u003C/p>\u003Cp>Right? That's what you would trigger with. So when you hit a play button, I imagine that we would have to show some sort of modal or a dialogue that allows you to put in a JSON object, I guess, with what that sort of, fake data looks like. And for some of the triggers, I think we can prepare that cause we can we can pre fill, you know, a fake article manual run cause we know the format, collection, keys, etcetera. For some of them, you don't need to do anything at all.\u003C/p>\u003Cp>Like a cron thing, you can just play because there's no real, you know, trigger data coming in, maybe a timestamp, but I'm not a 100% sure. For an endpoint, though, there there's no way for us to know what that looks like. Right? Because the payload is user edit, so we don't really know do with that.\u003C/p>\u003Cp>Speaker 2: So so some of the things I've seen with other tools, then this goes this even goes back 20 plus years ago using WebLogic's BEA workflow engines. You could actually take data from previous runs, so from the logs essentially. You could actually generate your payloads dynamically from that, or have say, I wanna capture this data, and I wanna actually reuse that as the test mechanism and essentially create your test data from an existing run. And then, ultimately, you could even edit at that point, you could edit the payload. So if you wanted to change some of the data attribution for subsequent runs, you could actually just quickly edit.\u003C/p>\u003Cp>So as part of the you know, that kind of play operation, you would actually get some dialogue capability and say, I wanna use either an existing or, in some way, create or save your payload and then fire that in. And in that way, you know, we don't have to be trying to generate it. We can just say, you can either run it normally, go and trigger the action. You know. Another way that I've done some of it is, like, have an incognito window with log you know, I I don't have to actually do what I just showed you, which is exit my flow.\u003C/p>\u003Cp>I can actually do the testing from another user. You can there there are some ways you can simplify or streamline that just a little bit. And you may be testing that permission set anyway. Then you may have permissions and restrictions, and you may be testing that as part of your application anyway. You'd have a test user with those permission.\u003C/p>\u003Cp>But being able to capture that information from an existing log or flow, run would be super cool and helpful. And that's some of what we've captured some of that already.\u003C/p>\u003Cp>Speaker 0: We have the logs. I mean, we have all of that data to your point.\u003C/p>\u003Cp>Speaker 2: Like,\u003C/p>\u003Cp>Speaker 0: if if there was a previous run, we'd know exactly, you know, what what information was there anyway. So we could definitely use that to to prefill it. Is this sort of manual trigger for well, manual trigger is a bad bad name because we already have a thing called manual trigger. But it's this sort of play button. Let's call it that.\u003C/p>\u003Cp>Is that something you'd wanna do for the whole flow, like, on the trigger level, or is that something you'd also wanna be able to do per operation itself? Because somebody before was like, you know, I used the run script operation a lot. I can also imagine that it would be really useful then to just just be able to say, okay. Just replay my run script a couple of times. But what I was just about to say showed up in the chat.\u003C/p>\u003Cp>Shout out to the Dev once more. Operations depend on a lot of context from what happened before. Right? Yep.\u003C/p>\u003Cp>Speaker 2: That would be more like that step through capability, right, where you you can step through and, you know, in debug mode, essentially pause. Right? The you know, you have your your break point. And at that point, you stop. You can actually analyze and look at the data.\u003C/p>\u003Cp>So, I mean, this does become very much ID style kind because that's what this really is. We're we're doing ID development. The idea is you would have these kinds of breakpoint capabilities to be able to stop, look at what data and parameters, be able to look back through the current context, what does it look like. Am I getting what I expect? Okay.\u003C/p>\u003Cp>Okay. Then step through debug. And it gets complex because we've got this mix of operations, and then you got run script that has, you know, code. Right? You know?\u003C/p>\u003Cp>Now do I have another debug capability with stop points and break points inside the job? You know?\u003C/p>\u003Cp>Speaker 0: Yeah.\u003C/p>\u003Cp>Speaker 2: Debugging that the TypeScript JavaScript in there directly. It gets very complex in that sense. But I think just the ability to be able to have a I wanna be able break point at the run script, be able to step to the next operation, then check the data and see I'll be able to multiple breakpoint options. We could get more creative down the line. I think if we can just put it at the operation level, that could it would be kinda cool if you could, you know, essentially step back, edit the data, or do something to the input, and then feed it back through, step back, step forward in in the operations themselves.\u003C/p>\u003Cp>Like, it's more complex\u003C/p>\u003Cp>Speaker 0: than And another thing with all of this, of course, is that, these operations may very well have side of on purpose because you might ping a different endpoint. You might save something's database, whatever. Right? So if you're manually playing, you know, with Flow or even individual operations for debugging purposes or whatever else, those side effects will still be in effect. Right?\u003C/p>\u003Cp>And if you're trying to debug a whole flow, you know, operation 2 might be dependent on a successful response from operation number 1. Like, number 1, save something to the database. Number 2, reads it, you know, now that it has been saved or something. I'm just trying to come up with an example. Because I was thinking, you know, it it be important to think through some sort of dry run as well where you can just like, okay.\u003C/p>\u003Cp>This would have now saved to the database. Right? And then, oh, this would have now made a request to the API, but we didn't actually do that. We didn't want to make a Stripe subscription as part of our little testing thing right now, right, to just test if everything works. So that'll be interest interesting.\u003C/p>\u003Cp>Some sort of dry running, thing behind it. I I do think it's important to think through at least because of the side effects. But to again, shout out to the derp. Can't really do a universal drive run because you never know what, you know, arbitrary stuff is being used.\u003C/p>\u003Cp>Speaker 2: Yeah. You'd almost have to have, like, a successful run or at least a set of data and payload options that you could edit up to say, you know, this is what I'm kind of expecting as I process through my input outputs.\u003C/p>\u003Cp>Speaker 1: Mhmm.\u003C/p>\u003Cp>Speaker 2: So So you'd have to have input output capabilities. What do you expect? And then as\u003C/p>\u003Cp>Speaker 0: you say,\u003C/p>\u003Cp>Speaker 2: dry run mode, not save, but often, you know, maybe the change that I'm making, I then getting that and then doing something. So I'm sending it to that I'm sending a webhook out data payload that comes back, you know, depending on how complex you make a flow. Mhmm. My general recommendation is if flows get that complex, go write a\u003C/p>\u003Cp>Speaker 0: hook. But it's Well\u003C/p>\u003Cp>Speaker 1: Well it\u003C/p>\u003Cp>Speaker 0: it there is gonna be a point.\u003C/p>\u003Cp>Speaker 2: It's a balancing act. Right? There there are I I like flows for admin kinds of functions where state management user control. When I get into really complex conditional lock, do doing this in these boxes so much faster to write TypeScript, be done with a hook on the backside. That's my Yeah.\u003C/p>\u003Cp>Speaker 1: The the similar to yeah. What I wanted to say is this sounds, like, very similar to some type of bash script or something. You know, some some type of scripting, where as soon as you need conditions or something, it's probably better to make it a program. Because, who likes to write bash? Basically, you know, it it gets it gets gnarly really quickly.\u003C/p>\u003Cp>So as soon as you need sophisticated stuff, some type of conditions that branch into something and do something with arrays or something, it's probably better to actually use a programming language. And,\u003C/p>\u003Cp>Speaker 0: I, yeah, I don't know. It really depends on a lot of things because one one is like, do you even know TypeScript or JavaScript in the first place? I think that's an important one. I think by, you know, doing it manually as as code, you also have a lot more opportunities to break it bad. You know, make it insecure, just make it an optimized break stuff tremendously hard.\u003C/p>\u003Cp>And also in, the chat somebody pointed out, you know, with flows, you do get the the logs and sort of the ability to explore the steps and what went wrong. So it's it's an interesting take, Jonathan, because what we're saying is, like, as as of today, you know, when it gets complicated, you wanna switch to code because the flows, UX, and UI just doesn't isn't good enough yet for complicated stuff. Right? So Right.\u003C/p>\u003Cp>Speaker 2: Yeah. Yeah. It is.\u003C/p>\u003Cp>Speaker 0: But I I'm hopeful.\u003C/p>\u003Cp>Speaker 2: If if we make this kind of what we're talking about, if we get to that point in these next few iterations on maybe it does become I don't actually need hooks as often. Right? I could be you know, hooks could just be when I need external library.\u003C/p>\u003Cp>Speaker 0: Yeah. Exactly.\u003C/p>\u003Cp>Speaker 2: Allow within flow at the moment.\u003C/p>\u003Cp>Speaker 0: I'm just I'm very I'm very hopeful that by by some of these seemingly small but very big changes, like adding the manual trigger so you can at least just try it out, I think we can actually get this to a point where\u003C/p>\u003Cp>Speaker 2: HOOX\u003C/p>\u003Cp>Speaker 0: is gonna be the more complicated one to do, you know, because it's like, yes, you have a black box and do whatever, but you don't get all of the debugging niceties and and all of the comments. Not that it's a battle. I mean, at the end of the day, it's just pick whatever you want, what's worked best for you. But I think that we can reverse that take, honestly, that flows could be I think that might be my personal challenge. Make flows the default for Jonathan.\u003C/p>\u003Cp>That's my measure of success.\u003C/p>\u003Cp>Speaker 2: Writes the worst TypeScript he's ever seen.\u003C/p>\u003Cp>Speaker 0: If he says I prefer flows over hooks, it means we did a good job.\u003C/p>\u003Cp>Speaker 2: Perfect. I love it.\u003C/p>\u003Cp>Speaker 0: Project Jonathan is what we call it. Cool. Okay.\u003C/p>\u003Cp>Speaker 2: If you can keep me from writing code, it's always a good.\u003C/p>\u003Cp>Speaker 0: It's always a good idea. So there's there's definitely a couple of unresolved You know, as per usual, I with the eye on the clock. As per usual, we're gonna be wrapping up. We've been taking a lot of notes during all of this, and it's, again, very divergently thinking. We're gonna be compiling all of these notes and ideas from everything that we just talked about and everything on the chat.\u003C/p>\u003Cp>Thank you for that. Into, you know, a proper RFC document and figure out what does this project upgrade flows, x y z, you know. What does that look like? What do we see as the must have? What can we get done in a sort of initial sprint?\u003C/p>\u003Cp>There have been, I think, like, 4 or 5 different discussions that are all sort of asking for the same thing, which is, like, improve Flows debugging. But they're all various sort of smaller bits and pieces of a, to me, bigger Flows 2 point o type of upgrade. So we're gonna be trying to compile those and sort of merge them into one sort of flows project, if that makes sense. Just as a quick summary, I think just the the upgrades to the logs that we talked about, you know, making them, like, explorable. I guess that's the right the right word.\u003C/p>\u003Cp>Giving them its own page, giving it more space, making it easier to step through, you know, the execution of a flow. Definitely a big must have. And the ability to trigger a flow from where you're editing it with some sort of, you know, preloaded payload from a previous run or something you can manually adjust so you can actually try out what the hell it is that you're building without having to go all over the app. I think it's gonna be a very, very important thing to have. Last question from from the chat here before we wrap up.\u003C/p>\u003Cp>Someone had said that many of these ideas could be implemented by the community in a custom module? No. Yes. Community can build whatever they want as a custom module at the end of the day. That is very true.\u003C/p>\u003Cp>And with the, you know, upcoming release of, for marketplace project, I'm also very curious to see, you know, what people will do with this type of stuff. Right? Somebody could, definitely, make a flow flows log module and just make it super custom or super proprietary or super flexible, whatever they want Whatever they want, really. Cool. Okay.\u003C/p>\u003Cp>There was one more that snuck in with an upvote. One final thing. Can we have access to the flow manager from the flows service so we can do more things with flows from extensions? May may may. No problems.\u003C/p>\u003Cp>So so It depends. It depends. Now I'll I'll, it's oddly tucked away compared to the extension manager, which should also similarly be tucked away, actually. Anyways, no. The the the reason for the hesitation is more around updates that I kinda wanna do to those services in the first place.\u003C/p>\u003Cp>Right? So I know I wanna do some sweeping upgrades to what those services look like and how they work in the first place. So I'm hesitant to to add new stuff onto the services service that we know might change already. Right? So I I don't wanna introduce something new that's gonna change then fast after, if that makes sense.\u003C/p>\u003Cp>That being said, yes, I do wanna make sure that extensions do have access to all of those types of internal things, which is also a reason why we've been moving a lot more stuff into individual libraries. Right? So I don't know. For for those who have been watching the repo like a hawk, we just moved sort of the environment variable extraction and handling different library with the same sort of idea, right, where an extension can just import the Directus ENV library and then use the same sort of ENV handling that, Directus does itself. We're we're basically doing that across the board, and the services is one of those things that I wanna do like that.\u003C/p>\u003Cp>And I can definitely imagine there being eventually being, you know, a Directus flows library that contains, you know, this flows manager state, so that extensions just can import it just like the direct as API would with TypeScript typing. I I heard you. Community, I heard you. With proper TypeScript typing and everything as well. So that's that's the only reason why I'm a little hesitant to promise anything better, as of right now.\u003C/p>\u003Cp>Any cool. That marks 11 sharp on the clock on my end. I think this was a very interesting session so far. This is a little bit more divergently rambling, than doing an existing discussion, but I think we've touched on a couple of very, very important points. Any any other closing thoughts?\u003C/p>\u003Cp>Speaker 2: If I could remember the dad joke from Bryant this morning, I would tell it, but I suck at remembering jokes. So\u003C/p>\u003Cp>Speaker 0: Well, tune in next time for for\u003C/p>\u003Cp>Speaker 2: John's phone dad joke.\u003C/p>\u003Cp>Speaker 0: With all that being said, thank you to the audience. Thank you for watching. If you're watching this on Directus TV, Directus dot a 0/tv, Hi. Be sure to watch the previous versions of this video down below. And we'll see you guys in 2 weeks, I think.\u003C/p>\u003Cp>Or are we skipping that one? Because it's sleep week, I think. Maybe oh, TBD. There will be one.\u003C/p>\u003Cp>Speaker 2: I think our next one's in March, because the I think or no. No. It's actually the other way around. We have one more month. We're skipping the first one in March.\u003C/p>\u003Cp>That was the\u003C/p>\u003Cp>Speaker 0: See you guys in 2 weeks then.\u003C/p>\u003Cp>Speaker 2: I remember now. My poor old brain catching up.\u003C/p>\u003Cp>Speaker 0: It's all in the event tab. Exactly. Keep your eye on it.\u003C/p>\u003Cp>Speaker 2: It's all in the event tab.\u003C/p>\u003Cp>Speaker 0: Thanks, everybody.\u003C/p>\u003Cp>Speaker 2: Kevin's keeping us honest. Cheers, everyone. Bye.\u003C/p>\u003Cp>Speaker 0: Bye bye.\u003C/p>","Alright. Yeah. So, Jonathan, you already, briefly introduced that seeing all the hiccups, I don't know if we're gonna cut that. But just to restart it, we're gonna be talking about flows today. We're really gonna be starting with this 15 8 70 about improving the activity panel. But, realistically, as far as I'm concerned, it's sort of a smaller piece of a bigger discussion around upgrades to flows. Right? So for those out of the loop, we introduced that flow system as a way to do event based, actions and operations, kinda like you could with hooks, or custom endpoints, but doing it in a no code type of way. Right? So you configure when you want your flow to trigger and then step by step configure individual operations, individual nodes of sort of this this path, that you wanna execute. The original version of that was really much designed as a, start with the basics, see what people wanna use it for, see where what what the best improvements are gonna be. So we shipped it a little bit lightweight, you know, with a handful of operations and have been more and more over time. But it has been becoming increasingly obvious that there's, a lot of improvements that would be really nice to have, especially when it comes to debugging, sort of helping configuring some of these pieces. So with that being said Yes. Discussion. So for Daniel, who's flying blind here, we're looking at the one about the logs first. Right? So if you're currently running a flow, optionally if you have it enabled, it's enabled by default. It will keep track of the data that sort of went through the various operations, and then saves it to, a logs tab that you can see on the right hand side of the flow. This is basically the primary way at the moment where you can debug what is happening under the hood, because otherwise, you know, there it's it's the way where you can see what data came actually through the trigger and how you've modified the data points in between. So over the Jonathan, you're you're showing it out what that looks like now on your own instance. What are some of the points in this initial discussion that triggered this this conversation? You've got a lot of the ease and access to that information, as well as the ability to control, like, durations. Some of the problems we run into with flows, especially if someone once they get them into production, if they still have the activity and logging turned on, you can fill up your activity revisions tables really quickly. And there's you know, the mechanisms for cleaning that up are, you know, another flow, or direct database access or other kinds of things where you've gotta manage your activity and revision logs and so forth. Common recommendation that I make is once you've done your testing and you've got your flows functioning is to disable the activity and logging. But there are cases where you may want that and logging just for audit trackability on actions and things that people are doing with flows. So, I think some of that is just the general trigger and management of that. Other things that, tend to cause struggle for people in flows is the way that you access this instead of being able to say, look at the data from the log directly in something that I'm working on. There's been a again, there's a number of ways that we can kind of shake and look at this. But the general thing is this kinda lives over here. I can't edit this while I'm looking at this, so the the interactions with logs and the work that you're doing is kind of a it's a bit of a hindrance when you're doing the development phase of flow development. So it's just a more a nuisance than anything else. But the the inability to say edit something here, I have to actually come here to check. So if I'm looking for variables or data or what are the things looking like in here, what's my payload? Now I've gotta remember this data structure or copy this data somewhere else because I wanna actually do something with it. I wanna interact with it. I wanna use those variables. So it's kind of a it's a weird transition kind of back and forth. Some of the systems that we we got in some inbound activity on some other tickets and feedback that we got from some clients on the enterprise side, was you know, they showed showed us some other systems that have similar no code kinds of flow capabilities. And logs, instead of living in, like, a side panel in a weird way, kind of live with the operations themselves. So there's just some general ideas and thoughts around how that interaction in the UX kind of works. Data wise, I don't think anybody's complaining about the information that shows up in here. That tends to be you know, it's fairly easy to work with and deal with. I think it's more the kind of user interactions with data. Yeah. For me, personally, I've ran into this when I tried to set up a flow which triggers another flow, which then leads you to, you know, switching between those 2. And then you have to check that again, but then you forgot on the first flow, forgot something, and you have to switch back. And, you know, so people do run into this, and, I've experienced this myself. So, generally, if I if I experience this, the general user will probably also experience this. So this is a very valid point, in my opinion, and, we should we should improve this a little bit. You're muted, Jonathan. Sorry. You're muted. You look very passionate, though. I'll give you that. But Sorry. I'm not gonna mute. So so what that does is, you know and that's why we saw this very same thing as we started doing some internal research on just this ticket. We rapidly diverged into we've got 4 or 5 other kinds of spec, and that's why we it's kinda leading into this call today. We were talking about the fact that there's some general overall flows improvements that I think we'd like to see across the boards. But the logging and activity, you know, that's that kinda triggered this action was really about that the way that those logs interact and how you have to it's kind of a separation of what is a common function. Yeah. Definitely. Totally agree. And, like the other comment on the chat said, switching is painful. Yes. An auto refresh for logs would go a very long way because I I do think that these two things are very, service the same niche, service the same pain. Because you you want to have up to date logs and see what is different, what do I have to work with, what can I work with, and not being able to have that on auto refresh, for example? Is the same thing as context switching back and forth, and you want to refresh and whatever. So I think these two pieces are very similar and and and try to work on the same pain, basically. So, good point from the chat. Thank you very much. So there's a lot of lot of, I saw the word divergent on the screen. Just made me think there's a lot of divergent ideas happening at the same time. Right? We're talking about a lot of smaller optimizations like the auto refresh or some sort of way to make that context switching a little bit less painful. If we take a deeper look at this discussion, though, that sort of triggered everything, are there any particular pain points about the way we describe or show those logs that is currently sort of, something that should be improved? I'm kinda skimming through this guy. See some people typing in the chat. Please let us know if you have experience in using flows and would like to, contribute. We're here for you. I think on the Trigger log is the hardest to understand. I'm still on. So on that log side, the other key thing that's being pointed out here is there are differences in the inbound payloads based on whether you're doing a create, update, or delete operation. You do have some variation in the trigger payload bodies. And, again, I don't know that it's a bad thing, but it is one of the things that's called out as a there's differences in the pathing, say, to the collection or the item, based on what type of event triggered the action. Yep. Yeah. Very good one. That that makes a lot of sense, and it's it's it's explainable from a technical perspective, but also makes sense where it's where where the pain point's coming from. So earlier on, when we just did the hooks initially, the decision was made to differentiate between create a single thing and create multiple things, which in turn means that sometimes you get a single ID as a sort of, string or a number, and sometimes you get an array of ID strings or a number, which is basically just a bigger discussion around what does that hook payload look like. Right? Because everything is based on the same internal, event system. So, you know, a flow is triggered based on the same hook that you get from, a hook extension, for example. It's all the same thing. Then, the difference between, you know, trigger dot keys, trigger dot body dot keys, etcetera, sometimes it's payload, sometimes it's not, That really depends on the type of trigger, which, again, you know, doesn't necessarily make it make it better, but it is, you know, explainable where it's coming from, where. If you're having an endpoint, you know, with a a trigger request, now you're dealing with a sort of user payload that was submitted that could be anything. Right? If you're dealing with a hook, it's a pre pre known format for what our hooks fire. But, you know, it's there's a difference. There's gonna be a difference, and that is that's definitely tricky. Somebody said, if hooks supported loops, we probably wouldn't need the differentiation for 1 versus multiple. Hook supported loops. I'm not entirely sure what you mean by that because a hook is just a bit of JavaScript, so you could loop over whatever you want. Right? Oh, flows. Oh. Oh, I see. Gotcha. Gotcha. Gotcha. Gotcha. Yeah. So we're basically saying, you know, if you have a way to just say do this flow against every item in the triggered whatever trigger keys, then we can basically just drop the one hook and make everything an array all the time, sort of get rid of some of that confusion, which for the record Yeah. Makes a ton of sense to me. I mean, every every insert into the database could be 1 or multiple things. And if you do one thing, it's just an area of one thing. Right? It's basically it's it's easy to explain. So I I do agree with that sort of general sentiment. Even though for the record, that would be a quite a big breaking change and totally wreck everybody's existing flows and extensions. So TBD TBD. As mentioned, the extension shed will be very possible to create a repeat operation for all elements in an array extension with exposing a single function from the flows manager. Yeah. Yeah. No. Absolutely. Yeah. That's very true. Very true. Cool. There is one more, thing in the chat here from our very own Brian saying remembering the key names for operations is a pretty big headache for me. Why are the keys only showing on hover? Where can I not copy them? Which has been a thing all over the app. And just trying to remember what that key name is. That's a very good point. And I think, you know, overall in the app, we've sort of on the side of making things sort of, what's the right word? User friendly is such an empty thing, but, like, look pretty for nontechnical users. Right? So a lot of stuff gets, what we call title formatted. Family friendly. Yeah. Exactly. We we we title format a lot of that stuff, so it looks prettier in the UI. But totally. Yeah. For things like flow logs, you know, which is inherently a very technical thing, flows is only available for admin users, which are generally speaking, a little bit more of the on the technical side. Those should most likely just be the technical keys. Right? Render them in monospace and just lean into it. Because why why show them as a title formatted version and then have it only show on hover that you can then not copy paste because it's a tooltip. Right? It that that makes a ton of sense, and that is just a perfect sort of tiny little tiny little tweak that's a huge quality of life improvement. Jonathan, I hope that was in the notes somewhere now. Yep. I'm taking some notes in in a separate section, over in the the actual internal notion doc that we've got running on this guy. So I'm trying to capture pretty much it. Another good point here too is, like, why even have a pretty name if you just have the key? You know? Good point. Good point. I think having some sort of description is a nice, you know, nice to have where at least you can write, like, a mini description, but you wouldn't really use the name for that anyways necessarily. Cool. Okay. Just looking at the discussion, though, because I see we're sort of, what, 1 eighths of the way on the scroll on the page. So I'm kinda curious to see if there's any other points in this particular discussion that we haven't really touched on. That's easy to forget. So these ones we just looked at. I think, the suggestion by our own Oh, the the JSON object wrapping. Object wrapping was the other big thing. Again, having this in the side panel, data here, you can start to see if you get long things. It it actually goes off screen and ends up, you know, and you I don't even think it enables a scroll. I'm not sure you can even get to long data that's being displayed in the log there. So some form of wrap, at least, if we're gonna continue in this panel. I think, ultimately, I think we'd like to maybe move this out of the panel anyway. It'll end up somewhere else in the UX. But something for us to keep in mind is that JSON wrapping, and we have that captured as well in a I was just gonna say that it's there it it's I can already also see there's no way to search or filter through logs. Right? That is another, you know, in. The only thing we show about the log is just a time stamp and then a rel as a time stamp. But I'd I'd say an obvious next step is to sort of move that out of the sidebar into just a proper, you know, layout like we do with other things all over the place. So you get the searching, you get the filtering, and we can have a proper detailed view, or draw our although a detail page is probably gonna be nicer for that. Save a little bit more space, for things like that overflowing scroll and just presenting it nicer. Although, then, you know, we create a new problem, which is now the logs live outside of the flow where you configure them. So at that point, you know, we also wanna make sure that we have some sort of way where you can render that maybe as a split view, maybe you can sort of 50 50 between the flow that you're creating and then seeing the logs of that flow with this layout. Because I do believe that keeping them in context or at least having some sort of link back and forth, from, you know, where you're configuring the the law, the flow and configuring the log is gonna be important. From the chat, having logs and operations might be helpful for that. Yes. Yes. Yes and no. It's it's I'm I'm, to me, the logs on operations is an addition, not a replacement. I think personally it's very valuable that you can see, you know, the full, execution path in a log. You can see, you know, at 2 pm today we started with this, we started with it, that one failed, and then we did this, and then here's the data that went through it and what we concluded with. I do think it's important to have that sort of consolidated together, but the the logs and operations, I do agree, would have really be a really nice addition to that where you can just look like, okay. In the last couple of runs, here's the day that it came in and went out of this particular box in your flow. Right? I don't know if that's gonna be a deep link or maybe just an info. Almost feels like you could have, like, a split panel down here that had the normal, like, search layout capabilities of searching through the logs, could be an interesting use case for this where you'd Mhmm. Similar to Visual Studio and other kinds of console logs where when you're doing this kind of development, you've got logging information you can see down here. Because I also think some of the other nice things with flows would be able to have, like, step through. Right? Being able to step through and see data at certain points, what's going on as you're debugging and working on the flow itself. But then as you say, having an actual, you know, log panel or maybe there's a, like, in a sub ten under flows where you can go to the logs and just see logs full screen, be able to search. Because once my flow is operating, I think the the DERF, pointed out that they're they like logs turned on so when users report issues hours later, they can go back and search the logs. And in that case, I'm not looking at the flow. I'm looking at what's the data, what's the flow, what happened, what errors, what things do I see. So cool. Because the nice thing by putting the again, this for for those new to the stream, this is very much a session of divergently thinking. Right? We're just gonna go brainstorm a bunch, like, what will be the ideal state and then take it back towards the end to, like, okay. What is an actual realistic next step? So I can also imagine, you know, closing your eyes thinking about it, if we have a proper detail page, like a full full screen view for the logs for one particular run. Right? We could actually render sort of a smaller, graphical representation of your flow as you have configured it, in in here, and then just show you. You can sort of replay it, so to speak. So we can just show you step 1, and then that's the data that came in and out based on the logs that you're looking at. Right? So instead of just having a long list top to bottom, you could effectively just get a visual replay, of that particular flow operation. I think that could be an interesting one too. Because then you really get to visualize the the execution of that flow because you're effectively trying to follow a path through your flow with the log. But right now, the log is always gonna be a a sort of, what's the right word, a one dimensional list, top to bottom. Right? Chronological. But, you're thinking about your flow, potentially, in more of a graphical tree. Right? Where it's like you have option b, and then you branch off, etcetera, which is not really, represented in the logs in any sort of way right now. From the chat, somebody you could almost use the exact same UI as the flow editing page for that. Yeah. No. Yeah. Yeah. Exactly. Maybe a little bit smaller so you have the whole thing, you know, in view at the same time, and we just can highlight whichever box we're currently showing you. Yeah. I think that could be a very interesting visual representation. It becomes very interactive at that point. Right? Where it's almost like, you know, the logs will just be represented with some sort of timeline bar where it's like, okay. You read operation 1 out of 16 steps, and then you can just go to the next one. Then the visual representation up top just sort of, like, highlights which box we're on. Right? And then just go to the next one, go to the next one, go to the next one. I still think we would have to have some sort of way where it's just, like, show me the whole thing as a JSON blob. Don't make me go through this this pretty thing, but I'm pretty hopeful that that could help, really help debug what's going on here. Speaking of which, why is the flow edit page the default? The view page seems kinda pointless. Yeah. Agreed. Done. So easy it can be sometimes. I I think the the honest answer is that kinda came from flows being initially designed as using the exact same UI and UX and order of operations as dashboards, where that is, very different, obviously, where dashboard is definitely read read only by default, and then only if you wanna change something to your panels for the order of the dashboard or that kind of stuff that you really go edit it. But in this particular case, I agree because it's like, what is really the difference between read and editing it? The only difference for read is that you can't, you know, click a button, but there's nothing that's really, you know, different between the two states. Right? So just getting rid of that read only view, I mean, it it makes sense to me, honestly. Food for thought. It's not not something we're just gonna we'll have to double check if that all makes sense, but just you know? Well, let's say let's play with that thought a little bit. So let's say we make a new page, detailed page, which features everything that we want. Would we like to then be more stringent on how it looks? So maybe take away the ability to point, to to place nodes wherever you want so we can, you know, for example, make it, smaller for the detail page because we probably don't have the same amount of space as of right now. Is that something that we would like to do? I don't know. Like, how important is that even? I think for the flow detail page, for the if you're talking about the flow detail page, it's not important. It's it's really more of a visual aid. This is like if you're mentally, you know, visioning what your flow looked like when you created it, you can see it sort of, like, go through the go through the motion. So it's really more meant as a graphical element that is more for, it's kinda like a map. It's kinda what I see it like. Right? It's it's a nice to have, not really a requirement. What I was kinda thinking we could potentially get away with though is instead of rendering the full boxes with everything in it, which just be the name or just an empty box for that matter. What we could do, though, it's I don't know if you've ever ever played with this, but if you have a dashboard set up Jonathan, do you happen to have a dashboard in this this demo instance? Plenty. You gotta love it. Dashboards and sort of the underlying panels and the the viewport stuff. Yeah. Exactly. It has a button that just sort of zoom out the fit. And also a full screen button for those who don't. Pro tip for you. So you can full screen and make it fit on your your, fit on your screen. But we could use that exact same thing for doing just sort of a mini representation of, of your flow at the top of this flow's detail log page. Right? Because you don't need to see all the exact details. It's mostly just as a graphical map for going through your flow. This could be a very interesting trick. Similar similar tools I've seen, you can actually zoom in or out. You can actually zoom your view so you can see more of your flow or all of your flow. And then when you double click or click on something, then you get back into the item view or the detailed view. So back in our flows example here. Right? You'd be able to, you know, have a zoom option or be able to scroll in or out and zoom your view similar to a map style the way we do with the geospatial kinds of things. So very similar to that would be fun. I wish I could see the screen right now, but, I thought there's something Oh, right. About exhibit. I forgot. For example, yeah, if if we decide to, you know, like, restructure the visuals or want to provide a different type of view, for example, like, we don't have to have boxes. We could also have, like, circles, for example, which could be smaller, take out the space. Maybe they're horizontal or something. I'm not sure if you showed this, right now. I'm sorry for that. But Oh, no. No. No. No. It's I just I just love the the very bit of a sidebar. I just absolutely love the the artistic way you brought that just now. Maybe instead of rectangles, they could be circles. Yes. But yeah. No. You're absolutely right. Because we the nice thing is we know the exact dimensions of each box. Right? So we could theoretically, for a graphical overview, render each box at a half height and offset all of the, x and y positions by, you know, the number of boxes high To sort of recreate the diagram in a more compact view. For sure. Yeah. Good point. So let's let's noodle on this idea for logs on the actual operation box. Right? So would that be a, sort of additional button, I guess? Because I'm also sort of operating under this. It's edit mode by default all the time. So I could imagine that maybe next to the edit button, there's just some sort of logs link. And now that I'm thinking about it even more. Pre filter the logs to the particular one you're looking at, all that kind of fun stuff. Yeah. Because now that I'm thinking about it, we save the logs as one row with a bunch of JSON in it for the whole flow execution. Right? That's the, that's the log item that we have. So there's no real way to just say, give me all of the logs for just the update data operation, because you're looking about all of the, you know, all of the, all of the data from the whole flow, and then we have to sort of filter it back down. But, you know, we could consider, although the amount of data is gonna get out of control real quick, but we could consider saving, you know, a log row in the database for each operation step instead of for the whole flow. But we gotta make sure that we have some sort of automated retention setting and and a bunch of indexes, indices for that, to not completely wreck your database. Because if we're now creating 5 new records per flow instead of 1, then you're talking about millions and millions of data points, which, you know, depending on your database might not matter. This has been a point in the discussion. The person that started then was already interested in some type of way to for example, similar to the activities, issue that we had, recently where, you know, big or large instances have trouble with, I don't know, I don't know, 2,000,000 activity entries and some type of schedule that clears logs or, for example, you only want to retain those who are at most, I don't know, 30 days old, for example. Some type of rule maybe which could, lighten the load a little bit would be helpful, I think. Oh, a 100%. Yeah. Yeah. The 100%. The the main reason we haven't had that before, I haven't done that yet, is because we didn't have support for this use yet. Right? And that's really a requirement. Because if you wanna delete with a filter on a timestamp and you don't have an index on that timestamp, now it might take your database, you know, minutes to just go through a table of that size. So that's that's also where that sort of sprint came through to, like, support indices and now collaborating with the the contributor there to to get that across the finish line. Because then once we have proper support for indices because because I do wanna make sure that, you know, whatever we do for the system stuff needs to be available to the end user. Right? So once we have support for indices, we can then enable indices for the system tables for, like, the timestamp in activity and and same for flow logs and stuff. And then the second piece of that is gonna be a setting that says, what do you want your, you know, low log retention to be? And it should be an environment variable, I guess, or maybe it's a per flow option. T b t b d on that. Right? Maybe there's an environment variable for the the maximum number you can set, and then in the app, there's a drop down, whatever. We'll have to figure it out. But, yeah, to your point, if you can configure, I only wanna keep 7 days worth of flow logs for this flow. I feel like that's a must have for any sort of upgrade that we're gonna be doing the flows, because it's so easy to just now accidentally end up with a couple of 100. Actually, that reminds me, I think, Kevin the other day did a fantastic little flow that he sent over where he was using it for, for beddlesnakes. But I also saw his flow logs in the sidebar already be in the 100, and I was like, how how long have you been running this right now? Right? You're gonna have 1,000 tens of 1,000 of those, so we need to have some sort of retention for that, which I could imagine, you know, if you have a flow that you know you're running a lot and you want it to be lowers, think it has to be per flow. Food for thought. Food for thought for sure. So then when we're thinking about, you know, one other thing I know about the debugging of, flow specifically is that right now to test anything, you have to trigger the actual thing that triggers this. Right? So, as of right now, if, Jonathan wanted to test this ready for review flow in any way, he would have to save this, quit, go to his articles collection, and then manually trigger it. Right? Oh, it's so painful. It is so painful to debug these things, because you have to do just that. Right? I have to go I have to go save, then I have to go to our to my systems over here. I have to go to articles. I mean, at this point, normally, I've got an you're already kind of nabbed here, but now I've gotta open an article, and then I've gotta go through the actions of whatever I'm testing. So ready for review case. I have to push the button, then we go back, and then we're gonna go back to flows. We go back to ready for review. Now I have to go to logs, and now I can look at logs and see what's going on, test flow or not. So you're in here, you're traveling through, and you're looking at your payloads, and at your options wherever you are in the debug process, then you're closing out. Now you're going back to edit. So many mouse It's a pain is what I'm hearing. It's a pain in the butt. Flow is awesome, but it is it is painful to do the administration. That's why we're here. That's why we're here. Yeah. So one thing I think just wanna add another point from from him. Yeah. Sorry. Go. Go. Go. Go. No. Please. Please. Yeah. Yeah. Because, this this then touches the issue of alright, so let's you you want to create a flow. You want to try it out. You have to try it out in order to actually make it work. But then comes the thing, alright, so let's say I have an existing flow, and it's running. It should continue on running, but I want to, I want to edit it without changing the actual running flow, which would technically be something like, alright. Let's duplicate this flow so I can play around with it. And then, after I'm done with my modification, then I switch them or, basically, disable the previous one and enable the next one. So some type of let's let's call it, like, very, very lightly versioning. Yes. Oh, the chat. The chat is exactly it. Once they have the whole tag. Right. So so if, yeah, if you have a couple of, like, important very important flows running in production systems, you don't want to, you know, edit them willy nilly. So that's the that's the another thing, which is can be can be painful because as of right now, there's technically no duplicate button, which is, not as nice as it could be. And, it's it's a difficult one, isn't it? Because I'm also thinking about some of the triggers. Would that make sense? Because if you make a new version of a an endpoint, right, and an endpoint has a UUID to run it. But then if you create a duplicate, now the endpoint is different. So then if you wanna make that your production one, now you have a different endpoint. Right? So it's like the the duplicate and then kill the old one flow pun intended of updating flows might not work for every trigger. Also, if you create a new version of a flow that uses, like, an event hook for, like, an item save on articles or something, like, in this example. Yeah. It would have to be some sort of dedicated versioning because if you create a duplicate, then now you're firing both of your flows. Right? You know, a very, like, naive solution to that event problem would be to have the duplicated flow immediately be set to disabled. So if you duplicate duplicate something, the duplicate one is disabled, so it doesn't fire. And then you can play around with it, change something, and then enable it yourself. Yeah. Somebody in the chat that or somebody's plural in the chat, we're also saying, you know, you can obviously have a local dev instance or a dev copy where you could configure a new flow and then sort of import it at once so you don't, you know, mess anything up on production. Very true. Very true. Wanna make sure, you know, we keep we can Yeah. All the use ASM license. This this then goes hand in hand with the next thing that I wanted to bring up with with the same thing. So let's say you have your dev instance, and then you want to sync your synchronize your flow to the production instance. Alright? There's no version control, basically. If you don't use, like, an actual extension, which you can put into your Git, version control, you would have to manually duplicate or use the API or something to to get the flow over or synchronize between your two instances. Mhmm. Well, luckily, we talked about that particular problem 2 weeks ago in the last episode. That's exactly right. Like and subscribe. Exactly. The link right below the like button. Is that what they say? Yeah. I'm gonna have the sidebar here. Exactly. Circling back, though, because we we have, I think, 2 or 3 different, UX points with, like, a couple of different solutions. So one thing that I think is a must have for sort of this flows upgrade project that we're putting together here is that there needs to be a button on the trigger where you can manually trigger that trigger. The difficulty will be what data do we trigger it with, and how can we help you make that data realistic? Right? That is gonna be the difficulty there, which is kind of what we haven't done before. Because right now, with this manual trigger on an article, you know, the data format for that, like we talked about with the chat a little bit earlier, it's very specific to that particular article and that particular, data model for the article if it's like a filter hook or something. So if you have a manual play button, so to speak, we need to have some sort of way where you can sort of fake what that event looks like. We can pre pre generate a couple of ones based on your instance, I guess. Because, like, we know for the manual trigger that you get the primary key of an article. Right? That's what you would trigger with. So when you hit a play button, I imagine that we would have to show some sort of modal or a dialogue that allows you to put in a JSON object, I guess, with what that sort of, fake data looks like. And for some of the triggers, I think we can prepare that cause we can we can pre fill, you know, a fake article manual run cause we know the format, collection, keys, etcetera. For some of them, you don't need to do anything at all. Like a cron thing, you can just play because there's no real, you know, trigger data coming in, maybe a timestamp, but I'm not a 100% sure. For an endpoint, though, there there's no way for us to know what that looks like. Right? Because the payload is user edit, so we don't really know do with that. So so some of the things I've seen with other tools, then this goes this even goes back 20 plus years ago using WebLogic's BEA workflow engines. You could actually take data from previous runs, so from the logs essentially. You could actually generate your payloads dynamically from that, or have say, I wanna capture this data, and I wanna actually reuse that as the test mechanism and essentially create your test data from an existing run. And then, ultimately, you could even edit at that point, you could edit the payload. So if you wanted to change some of the data attribution for subsequent runs, you could actually just quickly edit. So as part of the you know, that kind of play operation, you would actually get some dialogue capability and say, I wanna use either an existing or, in some way, create or save your payload and then fire that in. And in that way, you know, we don't have to be trying to generate it. We can just say, you can either run it normally, go and trigger the action. You know. Another way that I've done some of it is, like, have an incognito window with log you know, I I don't have to actually do what I just showed you, which is exit my flow. I can actually do the testing from another user. You can there there are some ways you can simplify or streamline that just a little bit. And you may be testing that permission set anyway. Then you may have permissions and restrictions, and you may be testing that as part of your application anyway. You'd have a test user with those permission. But being able to capture that information from an existing log or flow, run would be super cool and helpful. And that's some of what we've captured some of that already. We have the logs. I mean, we have all of that data to your point. Like, if if there was a previous run, we'd know exactly, you know, what what information was there anyway. So we could definitely use that to to prefill it. Is this sort of manual trigger for well, manual trigger is a bad bad name because we already have a thing called manual trigger. But it's this sort of play button. Let's call it that. Is that something you'd wanna do for the whole flow, like, on the trigger level, or is that something you'd also wanna be able to do per operation itself? Because somebody before was like, you know, I used the run script operation a lot. I can also imagine that it would be really useful then to just just be able to say, okay. Just replay my run script a couple of times. But what I was just about to say showed up in the chat. Shout out to the Dev once more. Operations depend on a lot of context from what happened before. Right? Yep. That would be more like that step through capability, right, where you you can step through and, you know, in debug mode, essentially pause. Right? The you know, you have your your break point. And at that point, you stop. You can actually analyze and look at the data. So, I mean, this does become very much ID style kind because that's what this really is. We're we're doing ID development. The idea is you would have these kinds of breakpoint capabilities to be able to stop, look at what data and parameters, be able to look back through the current context, what does it look like. Am I getting what I expect? Okay. Okay. Then step through debug. And it gets complex because we've got this mix of operations, and then you got run script that has, you know, code. Right? You know? Now do I have another debug capability with stop points and break points inside the job? You know? Yeah. Debugging that the TypeScript JavaScript in there directly. It gets very complex in that sense. But I think just the ability to be able to have a I wanna be able break point at the run script, be able to step to the next operation, then check the data and see I'll be able to multiple breakpoint options. We could get more creative down the line. I think if we can just put it at the operation level, that could it would be kinda cool if you could, you know, essentially step back, edit the data, or do something to the input, and then feed it back through, step back, step forward in in the operations themselves. Like, it's more complex than And another thing with all of this, of course, is that, these operations may very well have side of on purpose because you might ping a different endpoint. You might save something's database, whatever. Right? So if you're manually playing, you know, with Flow or even individual operations for debugging purposes or whatever else, those side effects will still be in effect. Right? And if you're trying to debug a whole flow, you know, operation 2 might be dependent on a successful response from operation number 1. Like, number 1, save something to the database. Number 2, reads it, you know, now that it has been saved or something. I'm just trying to come up with an example. Because I was thinking, you know, it it be important to think through some sort of dry run as well where you can just like, okay. This would have now saved to the database. Right? And then, oh, this would have now made a request to the API, but we didn't actually do that. We didn't want to make a Stripe subscription as part of our little testing thing right now, right, to just test if everything works. So that'll be interest interesting. Some sort of dry running, thing behind it. I I do think it's important to think through at least because of the side effects. But to again, shout out to the derp. Can't really do a universal drive run because you never know what, you know, arbitrary stuff is being used. Yeah. You'd almost have to have, like, a successful run or at least a set of data and payload options that you could edit up to say, you know, this is what I'm kind of expecting as I process through my input outputs. Mhmm. So So you'd have to have input output capabilities. What do you expect? And then as you say, dry run mode, not save, but often, you know, maybe the change that I'm making, I then getting that and then doing something. So I'm sending it to that I'm sending a webhook out data payload that comes back, you know, depending on how complex you make a flow. Mhmm. My general recommendation is if flows get that complex, go write a hook. But it's Well Well it it there is gonna be a point. It's a balancing act. Right? There there are I I like flows for admin kinds of functions where state management user control. When I get into really complex conditional lock, do doing this in these boxes so much faster to write TypeScript, be done with a hook on the backside. That's my Yeah. The the similar to yeah. What I wanted to say is this sounds, like, very similar to some type of bash script or something. You know, some some type of scripting, where as soon as you need conditions or something, it's probably better to make it a program. Because, who likes to write bash? Basically, you know, it it gets it gets gnarly really quickly. So as soon as you need sophisticated stuff, some type of conditions that branch into something and do something with arrays or something, it's probably better to actually use a programming language. And, I, yeah, I don't know. It really depends on a lot of things because one one is like, do you even know TypeScript or JavaScript in the first place? I think that's an important one. I think by, you know, doing it manually as as code, you also have a lot more opportunities to break it bad. You know, make it insecure, just make it an optimized break stuff tremendously hard. And also in, the chat somebody pointed out, you know, with flows, you do get the the logs and sort of the ability to explore the steps and what went wrong. So it's it's an interesting take, Jonathan, because what we're saying is, like, as as of today, you know, when it gets complicated, you wanna switch to code because the flows, UX, and UI just doesn't isn't good enough yet for complicated stuff. Right? So Right. Yeah. Yeah. It is. But I I'm hopeful. If if we make this kind of what we're talking about, if we get to that point in these next few iterations on maybe it does become I don't actually need hooks as often. Right? I could be you know, hooks could just be when I need external library. Yeah. Exactly. Allow within flow at the moment. I'm just I'm very I'm very hopeful that by by some of these seemingly small but very big changes, like adding the manual trigger so you can at least just try it out, I think we can actually get this to a point where HOOX is gonna be the more complicated one to do, you know, because it's like, yes, you have a black box and do whatever, but you don't get all of the debugging niceties and and all of the comments. Not that it's a battle. I mean, at the end of the day, it's just pick whatever you want, what's worked best for you. But I think that we can reverse that take, honestly, that flows could be I think that might be my personal challenge. Make flows the default for Jonathan. That's my measure of success. Writes the worst TypeScript he's ever seen. If he says I prefer flows over hooks, it means we did a good job. Perfect. I love it. Project Jonathan is what we call it. Cool. Okay. If you can keep me from writing code, it's always a good. It's always a good idea. So there's there's definitely a couple of unresolved You know, as per usual, I with the eye on the clock. As per usual, we're gonna be wrapping up. We've been taking a lot of notes during all of this, and it's, again, very divergently thinking. We're gonna be compiling all of these notes and ideas from everything that we just talked about and everything on the chat. Thank you for that. Into, you know, a proper RFC document and figure out what does this project upgrade flows, x y z, you know. What does that look like? What do we see as the must have? What can we get done in a sort of initial sprint? There have been, I think, like, 4 or 5 different discussions that are all sort of asking for the same thing, which is, like, improve Flows debugging. But they're all various sort of smaller bits and pieces of a, to me, bigger Flows 2 point o type of upgrade. So we're gonna be trying to compile those and sort of merge them into one sort of flows project, if that makes sense. Just as a quick summary, I think just the the upgrades to the logs that we talked about, you know, making them, like, explorable. I guess that's the right the right word. Giving them its own page, giving it more space, making it easier to step through, you know, the execution of a flow. Definitely a big must have. And the ability to trigger a flow from where you're editing it with some sort of, you know, preloaded payload from a previous run or something you can manually adjust so you can actually try out what the hell it is that you're building without having to go all over the app. I think it's gonna be a very, very important thing to have. Last question from from the chat here before we wrap up. Someone had said that many of these ideas could be implemented by the community in a custom module? No. Yes. Community can build whatever they want as a custom module at the end of the day. That is very true. And with the, you know, upcoming release of, for marketplace project, I'm also very curious to see, you know, what people will do with this type of stuff. Right? Somebody could, definitely, make a flow flows log module and just make it super custom or super proprietary or super flexible, whatever they want Whatever they want, really. Cool. Okay. There was one more that snuck in with an upvote. One final thing. Can we have access to the flow manager from the flows service so we can do more things with flows from extensions? May may may. No problems. So so It depends. It depends. Now I'll I'll, it's oddly tucked away compared to the extension manager, which should also similarly be tucked away, actually. Anyways, no. The the the reason for the hesitation is more around updates that I kinda wanna do to those services in the first place. Right? So I know I wanna do some sweeping upgrades to what those services look like and how they work in the first place. So I'm hesitant to to add new stuff onto the services service that we know might change already. Right? So I I don't wanna introduce something new that's gonna change then fast after, if that makes sense. That being said, yes, I do wanna make sure that extensions do have access to all of those types of internal things, which is also a reason why we've been moving a lot more stuff into individual libraries. Right? So I don't know. For for those who have been watching the repo like a hawk, we just moved sort of the environment variable extraction and handling different library with the same sort of idea, right, where an extension can just import the Directus ENV library and then use the same sort of ENV handling that, Directus does itself. We're we're basically doing that across the board, and the services is one of those things that I wanna do like that. And I can definitely imagine there being eventually being, you know, a Directus flows library that contains, you know, this flows manager state, so that extensions just can import it just like the direct as API would with TypeScript typing. I I heard you. Community, I heard you. With proper TypeScript typing and everything as well. So that's that's the only reason why I'm a little hesitant to promise anything better, as of right now. Any cool. That marks 11 sharp on the clock on my end. I think this was a very interesting session so far. This is a little bit more divergently rambling, than doing an existing discussion, but I think we've touched on a couple of very, very important points. Any any other closing thoughts? If I could remember the dad joke from Bryant this morning, I would tell it, but I suck at remembering jokes. So Well, tune in next time for for John's phone dad joke. With all that being said, thank you to the audience. Thank you for watching. If you're watching this on Directus TV, Directus dot a 0/tv, Hi. Be sure to watch the previous versions of this video down below. And we'll see you guys in 2 weeks, I think. Or are we skipping that one? Because it's sleep week, I think. Maybe oh, TBD. There will be one. I think our next one's in March, because the I think or no. No. It's actually the other way around. We have one more month. We're skipping the first one in March. That was the See you guys in 2 weeks then. I remember now. My poor old brain catching up. It's all in the event tab. Exactly. Keep your eye on it. It's all in the event tab. Thanks, everybody. Kevin's keeping us honest. Cheers, everyone. Bye. Bye bye.",[226,227,228],"6cf228e3-12c4-472f-bc3a-a9cfe6f16cb3","adfbc5b5-8825-4bfc-91b7-2702779b8af9","e9fd3c4b-6d03-4791-b250-59c07d49f7a4",[],{"id":133,"number":134,"show":122,"year":135,"episodes":231},[137,138,139,140,141,142,143,144,145,146,147,148,149],{"id":140,"slug":233,"vimeo_id":234,"description":235,"tile":236,"length":212,"resources":237,"people":240,"episode_number":244,"published":245,"title":246,"video_transcript_html":247,"video_transcript_text":248,"content":8,"seo":8,"status":130,"episode_people":249,"recommendations":253,"season":254},"conditional-fields-nested-relations","916080169","In this recording of our live event on February 22 2024, Rijk, Jonathan, and Daniel discuss the support of nested relational values in conditional fields to build more flexible content editors","4764c83c-2464-4764-8ef3-9d310502315d",[238],{"name":159,"url":239},"https://github.com/directus/directus/issues/8228",[241,242,243],{"name":163,"url":164},{"name":166,"url":167},{"name":169,"url":170},4,"2024-02-29","Conditional Fields & Relational Values","\u003Cp>Speaker 0: Love it all.\u003C/p>\u003Cp>Speaker 1: Yeah. Hello. Welcome everybody once again. Thank you for joining us again in our biweekly, bi monthly. I always forget the difference between the 2, but they're also interchangeable.\u003C/p>\u003Cp>Our bimonthly, twice a month, session where we go over, you know, feature requests and try to go in deep, find all of the edge cases, think about everything that we possibly wanna support ever of the universe, and then bring it back down to number 42. Today, we're talking about supported nested relational values in conditional fields, which feels like a, oh, just support nested relational values. Easy. Until you start thinking about it for real, which is what we're gonna do today, and realize that it's probably not as easy as it sounds because that seems to be far from the course for these sessions.\u003C/p>\u003Cp>Speaker 0: As it always So\u003C/p>\u003Cp>Speaker 1: before we dive in on the every single time, before we get in too deep on the technical problems, you wanna, outline what what this is all about, Daniel?\u003C/p>\u003Cp>Speaker 0: Yes. So, just for anyone that has not used this feature before, it's pretty, I think it's pretty niche. I mean, I have not extensively used it in the past, but, a little bit here and there. And I think lots of people, share this experience. But, if if you use this feature, conditional fields, you will eventually run into this little problem.\u003C/p>\u003Cp>So it is about the ability to conditionally render, for example, or hide or show or change fields inside of your collection edit or your item edit page depending on other fields. So you open up an item and you have a couple of groups depending on how much information there is inside of your item. It might be useful for you as a user or for, you know, to make it easier for actual users of your directus instance to hide a couple of fields, for example, so lessen the, you know, initial information overload, for example. Or you could also make use of it to actually enhance the visual, the the user experience. There's lots of stuff that you can do.\u003C/p>\u003Cp>Also, you know, require different fields if a different field has a specific condition, if it meets a specific condition. So lots of interesting stuff that you can do and, like, really, really customize how your editing experience looks, how it feels, and improve it for your users. And, so this is just the overall, like, high level description of what this does. But this issue that has been opened for a little bit, a little tiny, tiny, tiny while. So, it is about this exact scenario.\u003C/p>\u003Cp>So where you want a field to have a new, let let's say you want to hide something depending on if this item has some type of property in in a relation. I don't think I, describe this very well. But, so you want the to apply these conditions depending on some nested property. And this currently is a little bit tricky, for us because this stems stems from an architecture standpoint, like, how our forms work as of right now. So this is not like, you know, we're just missing a little if statement maybe, and then we could enable this.\u003C/p>\u003Cp>It's a little bit more more involved, but we'll explore this a little bit. So, yeah, this is what this issue is about. You want to, you know, conditionally style or, you know, change your existing fields depending on the nested property. And it's currently a little problematic because if you open up a form or your item page, I mean, we currently do not load every single nested relation because, you know, that it could be bad. It could be good.\u003C/p>\u003Cp>It could be bad depending on how large your item is. So, technically, if you open up your item page, we do not have that type of information as of right now. So you can't actually apply conditions because we don't have that information inside of the form, which is the root of the problem. So how do we fix that? Good question.\u003C/p>\u003Cp>Speaker 1: Problem number 2 is we might not even have access to the info that you're trying to use, which makes this a heck of a lot more tricky to think.\u003C/p>\u003Cp>Speaker 2: Yeah. Tack tack on permissions, and suddenly this gets very, very complicate. I mean and how deep is this? Right? So in my case, right, where many to any, this can this, I've seen clients with anywhere from 5 to 18 levels deep in this relational model.\u003C/p>\u003Cp>How much data do you load up into the current view? Right? This can get very\u003C/p>\u003Cp>Speaker 1: first, Gary, you know, this\u003C/p>\u003Cp>Speaker 0: can get a little bit of hands in from the chat. You know? Let's involve the chat a little bit. So So just\u003C/p>\u003Cp>Speaker 1: to just to summarize this to, those three main Please,\u003C/p>\u003Cp>Speaker 0: let's\u003C/p>\u003Cp>Speaker 1: problems at first. Right? So right now, those conditional fields are just using the information that is visible on the form, right, with the edits applied because it needs to be reactive to what the user does. Then once you go relationally deep, we have a bit a problem because that information just doesn't exist in the context of that page at present time. Right?\u003C/p>\u003Cp>So that in and of itself could be easy enough by saying, okay. Let's just fetch all of the paths that are used within the conditional fields, and then at least we have that data. But we fetch it separately from the actual form content just for conditional fields purposes. That would solve part of this. Right?\u003C/p>\u003Cp>But then the second problem that makes that part a little tricky is that we have to merge it with the edits made by the user in the form. Right? So now we're dealing with differences in data types and how you configure them, which is one of the the sort of bigger the the second issue. Because theoretically speaking, you know, conditional fields check against the staged value of the form. So therefore, if you select, you know, a many to one item, you could check against the ID that you have selected.\u003C/p>\u003Cp>If you make a nested update, you could theoretically, through the rules, check for the nested value and and change it. The difficulty is, like, if you select an existing item, now the data that is staged is just a UUID. Right? It's not a nested object of values. So if your conditional field says, author names or nested name and author has to be reg, then it becomes tricky if you select the existing author because now you're checking the rule is nested field name has to be reg, but you're checking it against the u a d string.\u003C/p>\u003Cp>Right? Because that's the actual data that you're about to save. So that's that's another big big mismatch there. And that problem compounds the further down you go, obviously. Right?\u003C/p>\u003Cp>So the other thing is when you update, a one to many, we have that difference in syntax where you can provide an array of all the items or you can provide, you know, the create update, delete statements individually, which is what the app uses because it's still easier to manage for larger datasets. But that again also means that you now have to check against 2 data types and it works a little bit unlike you would expect. Right? That's kind of the the the TLDR for this. The 3rd major issue is permissions.\u003C/p>\u003Cp>Right? So as an administrator, you could set hide, a certain set of fields if a hidden field for this user, like, that's something they can't see is enabled or disabled, which for the end user is invisible and therefore the app can't actually run the check against it because it doesn't even know that the field exists. Right? So that needs a totally different solution where the check doesn't even happen on the app client side. The check happens on the server side.\u003C/p>\u003Cp>So it can check against data that the client user might not even have access to in the first place. Right? So those are the 3 major sort of problem spaces that we have with this particular feature. All of which need some sort of specialized solution for conditional fields. And hopefully, we can find some sort of direction that is 1, you know, one endpoint that rule them all, so to speak.\u003C/p>\u003Cp>Speaker 0: That's a top order. I guess. We we have some interactions. Yeah. Exactly.\u003C/p>\u003Cp>So we have a little bit of chat. How about having a field, that just show calculated data from other columns? So it's not a column in a database, a column just for showing some calculation.\u003C/p>\u003Cp>Speaker 1: So if I'm understanding correctly, to summarize that, what we're saying is instead of trying to use the nested values like an actual nest of the tree, why not have one alias field that just pulls up the relevant bit of data? So it's always just the string name, for example, from an author, and then you can conditional fields against that. Right? So instead of trying to dynamically do it against the whole tree, you're just pulling out the data that's relevant, and then the conditional fields check only runs on the top level.\u003C/p>\u003Cp>Speaker 0: Alright. But lots to think about. There we go. I've done it in. Fit this problem before, so what I do is to just create another extra foreign key.\u003C/p>\u003Cp>Speaker 1: It can\u003C/p>\u003Cp>Speaker 0: be used to filter the current items onto many drop down. Problem is that the user need to do another selection to enable this filtering.\u003C/p>\u003Cp>Speaker 1: That's kind of a similar idea. Right? Yeah. Where it's like instead of trying to nest it deeply, you just pull the value back up in some sort of way, either automatically or by having the user chip choose it, and then you operate against the static value of that field. Now the the interesting thing here is that one of the problems that we're seeing is that the way it works technically makes sense.\u003C/p>\u003Cp>Right? You you validate the conditions against whatever the third stage value is with the user's changes applied. Where it falls on its face is that the expectation is that it will do nested relational lookups and then dynamically apply the changes in that tree and then check against that. Right? So that could potentially solve for the first two.\u003C/p>\u003Cp>Right? Where we're saying, okay. We can make some sort of utility function that says, what is the conditional field rule? What data do we need for that? Then apply the current edits on top of that in a way that fits the model, right, the model for the conditional fields.\u003C/p>\u003Cp>So, therefore, if you selected an an ID for many to 1, we have to go fetch the nested data for that so not the permission. I saw it on the screen. It's in a different order now. So it's for the the app data context and then the nested relationships. For the permissions piece, though, we have an issue.\u003C/p>\u003Cp>Right? Because at the, like, the end of the day, we cannot run that in the app. That's that's basically the long story short. So those for for those who have been eyeing the GitHub repo like a hawk, there was actually a PR not too long ago with an issue, in a in a similar vein, but about the permission checks. Right?\u003C/p>\u003Cp>So some users were running into some issues where the application would allow you to change fields that you didn't have update permission to, for that exact reason because the update permissions were using a field that the app cannot read because you didn't have read permissions to those fields. So, therefore, the app couldn't know if you had access or not. So it would just default to, like, okay. You can do it. And then once you hit save, the API would just throw an error and be like, no.\u003C/p>\u003Cp>You cannot do it actually. Right? The way we solved for that is with a new endpoint in the API that basically say, hey. For the current user, am I able to update this particular item in this particular collection? Right?\u003C/p>\u003Cp>And it will return, like, these are the fields that you can edit, as far as I understand. I I'm a little hazing the execs, you know, IO, but that is effectively the gist of it. Right? And it feels like It feels like this feature will probably go in a very similar direction, where we need to have some sort of API endpoint where the app can say, okay. Here's the current about to be safe changes.\u003C/p>\u003Cp>For the for the current user, what should the conditional state be, I guess? Right? Because that's the only way. If the the app cannot read fields that are used in the conditions, it's kinda game over. Right?\u003C/p>\u003Cp>However\u003C/p>\u003Cp>Speaker 0: Interesting. How how would how would that endpoint look like? Like, what type of payload how would that translate all of the different requirements that we have? Interesting.\u003C/p>\u003Cp>Speaker 1: So I'd imagine I I know the requirements generally are, a, we need to fetch all of the data that is used in the, conditional fields rules. Right? So we just have to look up what are all the fields and what is the whole tree that is used within the conditional fields and fetch just those in the exact same structure so so we can run the checks against it. Right? Then we need to dynamically apply all of the staged changes from the user because one very important use case for conditional fields is things like, you know, you click a toggle and you show and hide fields conditionally.\u003C/p>\u003Cp>Right? That's kind of one of the major use cases for this. So it needs to be real time. And then the last thing right now, I'm pretty sure that's, it just returns. I I think what we do right now is we effectively just loop over and and then merge the field's configuration for the current item with the conditional field result, sort of smash them together.\u003C/p>\u003Cp>Right? So if, like, the default field is hidden in your conditional fields, you have field that's visible, then that takes precedence, and we merge them together by by field key. Right? So we dynamically update the area of fields that exist within the form based on that logic. So to translate that into an endpoint, you would most likely have to have an endpoint that takes what collection are we in, what item are we in, because that might affect, you know, the the IDs and all that kind of stuff.\u003C/p>\u003Cp>And then what is the changes that you've currently made so we can dynamically merge those and then do all of that logic on the server side and effectively return a new list of fields that should be visible in the app. Right? That's theoretically possible. Tricky thing, performance. Right?\u003C/p>\u003Cp>Speaker 0: It it is exactly. Like, I was already, like like, inhaling and just to, you know, finish your sentence so I can say that. Exactly. So, yeah, that that would probably then lead to, you know, some delay because, let's say, you type a name pretty quickly, you know, like, example, whatever. Now you made, like, I don't know, 6, 7, 8, whatever it is that you're typing.\u003C/p>\u003Cp>The key presses, alright, do we debounce those? Then, alright, we have another little delay. So we then have to contact the API, which gets the stuff back, and then we have another little delay. And then the whole experience might suffer depending on how exactly we do it. Because, like, even if we now if we now, start, like, debouncing, that could lead to other problems.\u003C/p>\u003Cp>You know? Like, if if we want something to change, if the the the the text field contains a specific substring or something. Yeah. Then then that won't trigger fast enough, basically, which, you know, is kinda not the point.\u003C/p>\u003Cp>Speaker 1: That is that's really hitting it on the head because this has to be you click a toggle, stuff shows up. That's that's the goal. Right? So it needs to be immediate and interactive. So if you debounce it for a second or something, to your point, the experience is gonna suck because you click a button and then Yeah.\u003C/p>\u003Cp>You're already looking somewhere else and then magically stuff shows up.\u003C/p>\u003Cp>Speaker 2: Right? This, it's instant. Right? Because the app has all the context and data and permissions and things that it needs, so this is instantaneous for this to show or hide. Mhmm.\u003C/p>\u003Cp>You know, make required, do whatever. The the toggle here, the app side is doing all that, and it's almost instantaneous where you go server side now if you're having to send back to server. I'm wondering, does WebSockets' real time kinds of capabilities help at all in this space if we work towards I mean, again, we've always wanted to make the app real time so that we can do, you know, multi multi user editing of records and things.\u003C/p>\u003Cp>Speaker 1: Yeah. I think, realistically, the main it it would reduce the network latency a little bit, but I think the main time spent on this is re fetching the existing item data and then merging on the changes. Right? Now\u003C/p>\u003Cp>Speaker 0: this is a\u003C/p>\u003Cp>Speaker 1: nice segue because I just read it in the chat. Does it have to be solved dynamically on the fly? Question mark. I think the answer is yes, unfortunately, because it's based on the current user changes, so it's always have to be dynamic. Is it possible to require users to save the query somewhere, save like a SQL stored procedure kind of thing?\u003C/p>\u003Cp>If so, would that make it easier to resolve? Yes and no. I mean, it's again, because it's based on the current sexual users changes, we can't really have that prepared because you don't know what those changes will be. That being said, you know, if the item that you've just read, we could cache that for a little while. Right?\u003C/p>\u003Cp>The tricky bit is just when do you invalidate that cache? That's been a bit of an issue before, right, where right now we have to sort of auto purge the whole thing and it's kind of inefficient, which is a very high on my personal wish list item, but let's not psych sidetrack too much on that in this one. So so the the problem is we can cache that particular call to the database and just be like, oh, in the last, you know, 10 minutes, we already fetched this. It's probably the same. But if some other user changed it in between, you know, it gets a little bit tricky.\u003C/p>\u003Cp>But we could cache the database call for sure for sure. If so, would that make it easier to resolve? Yeah. It would make it a little bit faster. We still have the network latency though.\u003C/p>\u003Cp>Right? Even if the API would just respond immediately from all the caches and skips all the execution, just by the nature of it having to go over the Internet, you know, you might have your the the API that you're talking to might be in a different region or something that might be, you know, a 100 200 milliseconds latency just from that. And then it's just the experience is gonna suffer a lot. Like, a lot. Right?\u003C/p>\u003Cp>Yeah. To a point where, oh, I see our own team here in the chat mentioning a similar thing where it's like, maybe conditions should just not support fields you don't have the permissions to. Because that way, you know, all the commissions, because then then you have this issue where it has to be on the API side. Right? So maybe one of the requirements that we're learning here now is that it kinda has to be on the app just to be able to keep that instant, feedback loop going.\u003C/p>\u003Cp>And then to mention for conditions not to support fields you don't have permissions to though, you have to configure it on a sort of per role basis what those conditions are because only on the role do you know what fields are available in the condition, Which is true, although that makes configuration hack a lot more annoying. Because if you just have you know, I wanna show an email field when you click, subscribe to newsletter or something. Then now you have to reconfigure that for every single role. Right? Yeah.\u003C/p>\u003Cp>Chicken. There's always plan c, which is just aggressively saying no relational fields and conditions. That's kind of what we've been doing so far. You know? It it sucks.\u003C/p>\u003Cp>Speaker 2: Does Paul is does the new policy system maybe allow us some better flexibility so that it's not on a per role? It's configured, but\u003C/p>\u003Cp>Speaker 1: Oh, don't get me started.\u003C/p>\u003Cp>Speaker 2: But, again,\u003C/p>\u003Cp>Speaker 1: it's a lot of and no.\u003C/p>\u003Cp>Speaker 2: It does require, I think I think this I I think the the idea is this really has to be either real time in some way, you know, WebSockets implementation, the app itself. Goal longer term is to have that kind of capability anyway. But with a policy based, you know, if we are able to, you know, walk the conditional tree and we can we can see that and pull the data necessary. Now it might be that we wanna limit, you know, number of conditions that you can apply or number of levels deep you can go with a conditional. Right?\u003C/p>\u003Cp>Because I don't know that we can have an you know, the infinite depth capabilities. You know, I can go 18 levels deep in a condition that seems insane to kinda try and cash all that, or even manage\u003C/p>\u003Cp>Speaker 1: all that in front end.\u003C/p>\u003Cp>Speaker 2: But is it you know, maybe it's a 1 or a 2 level deep is what is allowed, from a conditional rules perspective kind of thing where it's manageable, controllable, and sustainable.\u003C/p>\u003Cp>Speaker 1: The the thing to me though when it comes to conditional fields, to me, that is more a form builder type of thing than an access control type of thing. So having to configure how the form behaves on a policy to policy basis feels hard to manage, if that makes sense. Because now you're the output form is just it's hard to expect what it's hard to know what to expect once you have, you know, multiple different policies doing multiple different things when it comes to form building. Now this is a complete sidebar. That's also the beauty of these sessions.\u003C/p>\u003Cp>Right? Divergent thinking.\u003C/p>\u003Cp>Speaker 0: Love it.\u003C/p>\u003Cp>Speaker 1: Here we go. Strap in, folks. It's there's there's another singer, Annette. See I see you nodding over there. But one thing that we have been sort of, you know, floating the idea of is this idea of, like, what if we decouple the data model from the form.\u003C/p>\u003Cp>Right? So it's decouple the actual actual how you interact with the data from the data model itself. So therefore, you could have multiple forms for the same database table. Right? And then in a policy or in a role or whatever, you would choose what is the form that we wanna use for this particular table, for this particular set of users.\u003C/p>\u003Cp>Because the one of the other known I mean, issues might be a bit of a big word, but one of the other downsides that I've on my personal wish list, it's kinda like if you have read access, we we show and hide fields that you'd expect. Right? You don't know that a field exists. It doesn't show up in the form. It also means that if you're doing a form building exercise where you have, like, multiple columns, like, 2 things side by side, and all of a sudden one disappears, you know, the form kind of reflows, but it it results in a bit of an unexpected state.\u003C/p>\u003Cp>Right? Mhmm. So by having, you know, that form, having that form decoupled from the data model, now you could just say, okay. We're gonna make a form that we know will look exactly like this. Like, what you see is what you get for the form or the role that we attach it to.\u003C/p>\u003Cp>This is, again, a way bigger discussion than just a little brain fart dumping out into the world here. But that is that is, you know, one of the ways around this because then you do have conditional fields per role or per policy group or whatever you wanna call it.\u003C/p>\u003Cp>Speaker 0: Alright. Many, many different things. I'm trying to I'm trying to find a way where we can, you know, like like, define a little pathway for us right now, but it's it's very hard because there's so much so many different things that we could do, technically. So yeah. Yeah.\u003C/p>\u003Cp>My initial feeling, like, when I read about this was, yeah, it sounds very reasonable, like, in the naive way, you know, the very naive, first understanding of the of the problem. Very similar or basically what you said in the beginning. Alright. So we do know when we open the form, what people used inside of the conditions. Alright.\u003C/p>\u003Cp>How about we then fetch those things, all of the related stuff to separately from the table? Alright. So far so good. Then the permission issue comes in. Alright.\u003C/p>\u003Cp>Are they allowed to read this? Yes. No. Alright. What do we do if they and, and then it gets tricky, and then it starts to spiral.\u003C/p>\u003Cp>Alright. Goddamn. Okay.\u003C/p>\u003Cp>Speaker 1: We got we got\u003C/p>\u003Cp>Speaker 0: a couple. Yeah. We we got a couple of steps that sound like alright. Alright. Maybe maybe yes.\u003C/p>\u003Cp>Yeah. And okay, permissions.\u003C/p>\u003Cp>Speaker 1: There's there's always the point where we could put limitations in place. Right? It's like, we like to think with the least amount of limitations as we can while keeping it fast. But to Tim's point earlier, we could make a line in the sand and say, okay. You know what?\u003C/p>\u003Cp>Nested relational data is only allowed if you have read access to those those data points. Otherwise, it's just not intended to work. Because that way, we can remove the server component, keep it on the app site, and make it work the way you'd expect to make it work fast. But we put a ceiling in place to make that happen. Right?\u003C/p>\u003Cp>That is a very real, a very real in between. I'm I'm still been noodling on that that idea that you had, Jonathan, to, like, could WebSockets potentially help with this? And the more I think about it, the more I'm like, maybe, just maybe. Because if that database call is heavily cached and we send, you know, a message of, like, here's the stage change ID such and such, and then the API will just respond as fast as it can with, like, the the combined change and the new form that comes out of that. If we can heavily cache it enough, we can make that work.\u003C/p>\u003Cp>Now I see Tim typing in the chat. I'm curious if he's gonna say the same thing. I knew it. That was exactly what I was gonna say. He put in the chat, WebSockets are great, but we cannot rely on them for stuff like this as they're not a hard requirement to run direct this.\u003C/p>\u003Cp>Speaker 2: Not yet.\u003C/p>\u003Cp>Speaker 0: And this is this is a\u003C/p>\u003Cp>Speaker 1: different question, of course. Like, should it be a hard requirement or not? Right? Because and this is again a a bit of a sidecar sidebar from from this, this particular discussion. Because the way we implement the WebSockets right now I mean, first and foremost, we haven't really used them in the app yet, for very similar reasons to this actually, which is, like, we have to be careful with relying on stuff, maybe, yes, no, and then tricky tricky.\u003C/p>\u003Cp>The the the real question is, you know, WebSockets are not supported everywhere like regular HTTP requests are. Right? So for example, there's there's a couple of platform as a service providers that just will not work with WebSockets in your container or something. Right? Because there's so many hoops you could jump through.\u003C/p>\u003Cp>You gotta go from, like, you know, the CDN to, like, some sort of load balancer to some sort of proxy container to some sort of, you know, container that has the actual connection. Yeah. And to to Tim's point in the chat now too, if you wanna do snazzy things on the edge, like scaling back to 0 containers or something, you cannot have a persistent connection at all. Right? Which is another very good point.\u003C/p>\u003Cp>I know there was another this another discussion thread that has seen some activity recently around, being able to run directives in a serverless environment, which, oh, boy, is a whole different session of one of these. I'm sure. But if that were ever, you know, a deployment target that we wanna officially support, then WebSockets are just out. They're just unavailable to rely on, right? And then the question really becomes like, okay, what what is more important to us supporting serverless environment scaling down to 0?\u003C/p>\u003Cp>Or are we gonna say, well, Directus is just a a a tool that is intended to be a long running server because with cron jobs and hooks and all that kind of stuff. And therefore, WebSockets are just enabled just like the API and you can use them and we can heavily rely on it in the app to make it faster and a better experience. Right? That is gonna be a difficult call to make, because it's it's it's, at the end of the day, a little bit of a subjective one. I know it's it's, we haven't really done all the pros and cons of research and all that kind of stuff.\u003C/p>\u003Cp>But it's like, you know, people have very strong opinions on this kind of stuff. Very strong opinions.\u003C/p>\u003Cp>Speaker 0: We have to be careful, with Tim. He probably has one of those.\u003C/p>\u003Cp>Speaker 1: Like, one of those nasty opinions.\u003C/p>\u003Cp>Speaker 0: One of these nasty, nasty opinions. Oh, no. No. No. No.\u003C/p>\u003Cp>Alright. Yeah. Yeah. With the angel emoji. Alright.\u003C/p>\u003Cp>So far so good. Then let's maybe, you know, do the little, exercise. Alright. Let's say we go down that route that we mentioned with alright. You can't put conditions on stuff that you can't read or that this specific user can't read.\u003C/p>\u003Cp>Alright. This would have a couple of repercussions. Right? Like, then alright. You have multiple different different user roles.\u003C/p>\u003Cp>Do you then, as an admin that is configuring this collection, do you want to? Probably not. But do you want to actually configure then these things between different roles all the time. That sounds like a big pain, to be honest. Like, very annoying.\u003C/p>\u003Cp>Would we? Yeah. I mean, we do have to attach it to some kind of role. Right? Because, as of right now, you know, there can be, like, unlimited different types of user roles.\u003C/p>\u003Cp>Yeah. And some of them can read those fields. Some of them don't. We don't know that. Would we like to share this then with some type of diffing between those?\u003C/p>\u003Cp>But oh, man. This this just sounds like spaghetti, like, the largest bowl of spaghetti that you can think of. Weird. It doesn't sound enticing to go down.\u003C/p>\u003Cp>Speaker 1: Yeah. I think the the the conflict that we're finding ourselves in is that we know you can configure conditions for fields that you might not have access to and then it doesn't work. Right? So what are we gonna do to help the admin user in that situation? Like, we need to educate them on this.\u003C/p>\u003Cp>We need to educate them on the, on the on the limitation there or show it somehow or prevent them from making that mistake in the first place by connecting it tightly to a role somehow. Because once you connect it tightly to a role, we know what fields are available, and we can only service those in the conditions. Right? Mhmm. I agree with your earlier sentiment when you were, like, configuring that on the role and having to reconfigure it for every single role that might access this thing feels like a nightmare.\u003C/p>\u003Cp>That feels like so much extra work. Mostly because and and I briefly touched on this before, but mostly because I really see this as a form building tool, not so much an access control thing. Right?\u003C/p>\u003Cp>Speaker 0: Yeah.\u003C/p>\u003Cp>Speaker 1: It's to me, it's similar that you wanna have 2 fields side by side. I wanna have one show up and hide based on the value of the other. That's that's all sort of form building magic, not so much access control magic. So I I kinda strongly feel like we don't wanna conflate those 2 and and put, like, too much form building stuff in access control. Because it Right.\u003C/p>\u003Cp>Speaker 0: It just makes me context. Yeah. Thanks. So, similarly alright. How about then we reverse this a little bit?\u003C/p>\u003Cp>So, let's say, as of right now, you know, the admin goes into the collection thingy into the conditions and configures, you know, how it's supposed to look like, all of the different conditions, you know, height depending on this checkbox, make the title red. And then we attach a roll to that filter and we can now check, you know, is this role can this role even apply this filter? And we can immediately just say, oh, no. This role is not compatible with this filter because it can't read x and y and z. And this would also solve, like, solve let's let's in big big big quotation marks, solve that problem of, you know, like, having multiple user problems having multiple user roles that you could, you know, just say, alright.\u003C/p>\u003Cp>But this filter is, yeah. I I'm already, like, thinking while I'm talking. So then you come into this whole thing. Alright. Maybe you want to have different conditions for different user roles.\u003C/p>\u003Cp>Maybe.\u003C/p>\u003Cp>Speaker 1: Here we are again.\u003C/p>\u003Cp>Speaker 0: Here we go. Here we go.\u003C/p>\u003Cp>Speaker 1: Love it. That's the moment where it starts spinning again. Tim, just in the chat, does not make sense to build your forms based on what fields you have access to? Which, yes, I think that is kinda closing closing in on the the sort of wild wicked idea of saying, what if you can just configure multiple different forms and you can just make a form that is dedicated to, you know, one one role? So that way you can you know for a fact that all the conditions exist and all the fields exist, and the way you configure the form and the layout is tailor made for that role because the only fields that exist are the ones that exist for the, for the item.\u003C/p>\u003Cp>Speaker 0: Yeah. I can I can feel I can already, like, feel the pain through just thinking about this of, you know, the then, like, synchronizing between different types of forms between different types of user roles and oh, man? It's getting it's getting a little bit of rough. Let's say let's say rough. Alright.\u003C/p>\u003Cp>Tim has another thing. You effectively already do that using access control as the form will not render fields you don't have access to. Yeah.\u003C/p>\u003Cp>Speaker 1: Which I think might become an issue at some point in the not too distant future. Because one other thing that we've sort of been been noodling about, Jetta the Jetta, is the idea of a little bit more flexible grit for forms. So right now, it's it's a 2. Right? You can either make a full width or you have 2 side by side.\u003C/p>\u003Cp>That's it. We also just been thinking about, like, what if we make that just a configurable number with some with some responsive breakpoints potentially. You could make it a 12 grid. You could make it in the 8 grid. Whatever.\u003C/p>\u003Cp>Right? At that point, if the field in in column number 6 disappears because of redexes, we cannot we can no longer sort of cleverly reflow it, to make sense. Right? Because now we legitimately just don't know where things are supposed to go anymore on the page because it just it it just has to be become a a gap, basically. At that point, we might end up having to just show, like, there used to be a field here, but you don't know about it.\u003C/p>\u003Cp>Right? Because otherwise, the whole form layout is\u003C/p>\u003Cp>Speaker 0: tell anyone.\u003C/p>\u003Cp>Speaker 1: Because otherwise, the form layout is just gonna look either broken because you're gonna end up with blank spots all over the place, or, you know, if if we're trying to I I think it's safe to say that we're trying to sort of reorganize it on the fly. It will break, because we just don't know what needs to go where at that point. Because it would be a multidimensional grid. Right? That will be 2 dimensional because you can have things go 2 rows or 2 columns, etcetera, and then you have a problem.\u003C/p>\u003Cp>Right? Kinda like, I think of dashboards basically in terms of just positioning stuff all over the place. But if we go that route, if if that ever comes to fruition, right, again, it's just a random thought. It's not actively being worked on or anything. But, if we're going in that direction, I think we need to have some sort of way to have a form per role anyways.\u003C/p>\u003Cp>Because otherwise, you know, you're gonna either have a form with a bunch of holes in it or with place holders that you're like, hee hee. You can't actually see this. Or, you know, or it just needs to be per role because that way you can just make one that is, you know, tailor made for for that particular role.\u003C/p>\u003Cp>Speaker 0: Well, whether or not, we're actually, you know, looking into this, we already have our first customer. Then he said, I'm sold on the option to build a form per roll.\u003C/p>\u003Cp>Speaker 1: So good.\u003C/p>\u003Cp>Speaker 0: Sold it already. It was fast.\u003C/p>\u003Cp>Speaker 2: I like it. So if we can inherit, like, a global so it inherits the the default kinda data model form that you configure, and then allow you to adjust that on the specific role, I think that's actually pretty freaking cool because we do have those kinds of use cases where, you know, this particular business and especially if we could apply specific conditionals on that form, it means that, you know, my business user versus my consumer user could have a very different form experience intentionally and different conditionals. Right? The the default conditional for the business user presets those conditions and organization. I I kinda love the idea.\u003C/p>\u003Cp>Whether or not again, this this comes back to whether or not this actually we we decide to allow additional depth, you know, conditionals. Just having that particular feature seems kind of amazing. As long as we can inherit the default, then if I don't need that kind of capability, I can just use the default and manage the default that we'll get. If I've got a custom reason for adjusting the form. Pretty brilliant.\u003C/p>\u003Cp>I like it.\u003C/p>\u003Cp>Speaker 0: So there's a question by Benny Wade. Could we make groups configurable per row rather than making a whole form per row? Keep it a bit more modular.\u003C/p>\u003Cp>Speaker 1: AKA, can we nest these forms?\u003C/p>\u003Cp>Speaker 0: Yeah. That that Let's\u003C/p>\u003Cp>Speaker 1: check as we check-in with our friend v form and see how he feels about it.\u003C/p>\u003Cp>Speaker 0: -Oh, boy. Can't wait. Guys, if you enjoy\u003C/p>\u003Cp>Speaker 1: messaging, please. Where you have the forms that or the view of the page or whatever you wanna call it is the same for everybody, but then you just have a section where it's like this section only shows up for x role. Right? Could be interesting. That is a conditional field in and of itself, of course, where it's like, the condition is show or hide this thing if current role is x y z.\u003C/p>\u003Cp>Right? Which now I'm thinking about it. I'm pretty sure that exists. Present time. I'm pretty sure you can this is something I'll have to test, actually, because I know we have those dynamic variables for current user and current role in those.\u003C/p>\u003Cp>I don't remember if we support those in conditional fields. Because if we do, you can step a group and have a conditional field on the group that says current role equals x y z and then hide the whole group. We do not,\u003C/p>\u003Cp>Speaker 0: Tim. Tim and a chat. Why not? Why not?\u003C/p>\u003Cp>Speaker 1: He calls me out he calls me out on my bluff. It's happens happens sometimes. Yeah. But that would theoretically be a a soul for the same thing, though. Right?\u003C/p>\u003Cp>Or you could just say the whole group is hidden for a role, and therefore, no problem. You make it so that you can have the same field in different presentation section configured per role? Right. Right. So the same field multiple times.\u003C/p>\u003Cp>Yeah. That is that is another thing when it comes to dynamic form building and, just full stop dynamic form building at that point. Right? Because right now, the form is data model first. It's like you have a title field, therefore, you can now have a title input because it's 1 to 1 to the data model.\u003C/p>\u003Cp>Right? With a form building thing, maybe you have 2 title fields, like, 2 fields that point to the same underlying data thing. Right? There's instinct. I don't know why the hell you would do that, but you could.\u003C/p>\u003Cp>For for some interface, it may set I mean, in this this example where it's like you have the same field in different sections and the section show and hide based on the role, it starts to make sense again. I for admin users, it'd be interesting, but it it yeah. For sure. Then for, I I think there's a a definite interesting use case for certain data types where it would help to have multiple fields, multiple visual fields for the same underlying column. Think about, like, an address interface face or something.\u003C/p>\u003Cp>Right? Where you wanna have address line 1, 2, and then, ZIP code and all that kind of stuff, but you wanna save it as one field in your data model. Not super uncommon, or as a let long sort of search thing, right, where you have a let and a long input and then an address field, and those are all connected. So you can type in an address and it'll geo look up the let long, but then the thing that's saved in the database is just the let long. So there's definitely, you know, some additional things that we unlock with that sort of modular form idea.\u003C/p>\u003Cp>Right?\u003C/p>\u003Cp>Speaker 0: Alright. So what I gathered from this, is that we're basically about to build our own page building framework where we can dynamically close plugs. So we're basically set, you know? Like, director's page building, that sounds like a great idea. Okay.\u003C/p>\u003Cp>On the\u003C/p>\u003Cp>Speaker 1: So just to solve condition fields. That's that's the beauty of it, isn't it? How did we how did we get here for just solving nested conditional fields?\u003C/p>\u003Cp>Speaker 0: Yeah. It all started so innocently. You know?\u003C/p>\u003Cp>Speaker 1: It's true.\u003C/p>\u003Cp>Speaker 0: I just want to hide a field, and now we're basically embarking on a mission to\u003C/p>\u003Cp>Speaker 1: Okay. This is this is actually this is a good thing because this is a perfect example of the sort of, you know, request review session. For those who've been here before, you've seen this happen before. It's like we go completely off the rails in all directions, and then now let's try to see how we can actually get this back on track for nested conditional fields. Right?\u003C/p>\u003Cp>So as a you know, in a potential future utopia where you can just magically conquer up any sort of form, any sort of view that you possibly want. Great. But as of right now, I'm kind of thinking, based on everything that we talked about so far, it, to me, makes the most sense to follow Tim's suggestion from earlier, which is basically you cannot put the field and conditional fields that the user does not have read access to. Right? I think that is that is a safe call.\u003C/p>\u003Cp>I think doing it on the API side, we're never gonna be able to get it just performant enough, and we don't really wanna make WebSockets a requirement for this to work. So I think as of today, you know, what can we actually achieve in the next month or 3? We would most likely keep the client side, keep it fast so we can do all the calculations on the client. It has to be from current fields that you have read access to. The main difference that we have to do is that we have to dynamically, when you open the page the first time, we have to load up what is the nested data structure of this item based on the rules used in conditional fields.\u003C/p>\u003Cp>And then have some sort of utility function that can cleverly combine the stage changes on top of that. Right? We have to account for the differences like many to one ID versus nested object. We have to account for things like the one to many update structure versus array. But that that way, we can merge that and we can do a client side.\u003C/p>\u003Cp>Right? I don't think we should do that per role. That just feels like a nightmare to configure, to be completely honest.\u003C/p>\u003Cp>Speaker 0: Yeah. And\u003C/p>\u003Cp>Speaker 1: a lot of a lot of duplication. Again, in a utopic utopic utopic? Utopia stick future. Utopia like future. Utopian?\u003C/p>\u003Cp>Utopian future, you know, where you have more of this flexible form idea. At that point, you know, you can say, okay, When someone I'm already boring Jonathan to death, I see. When when you open this this page for this particular role, we use form xyz instead but that is again a way way future discussion. But then I think, you know, we can support the core ask for this this feature request, which is if I say nested author dot name, I expect that the lookup, what is the name of the nested author no matter what. If I select an existing one, it needs to look at the name of the existing one.\u003C/p>\u003Cp>If I change somebody's name, it needs to look at the changed name. Right? That is something that we can I'm pretty hopeful we can turn that into some sort of usability function that we can run relatively quickly on the client side and make this happen. Right?\u003C/p>\u003Cp>Speaker 0: Yeah. That shouldn't be shouldn't be impossible. Yeah. Yeah. Look at the from Natron.\u003C/p>\u003Cp>Speaker 1: And 10 rabbits with 1 multiracial conditional stone. Yeah. Exactly. As an admin that's configuring these conditional fields to another person in the chat, it would be nice to see the whole form that a person with a given role would see. Maybe a view as role option somewhere.\u003C/p>\u003Cp>Fully a 100% agree. To Jonathan's point, there's another feature request about that user impersonation. Again, very high on my personal, wish list. Right? I would love it as an admin.\u003C/p>\u003Cp>And not so not just for the for the particular form and settings or something. I really want there to be a way for admins to just say, browse the whole app, impersonating a different role so that you can just click around and see exactly what that user can see and do. Right? From a visual perspective, we'll probably have to have some sort of banner, zoom out a little bit or whatever. We'll figure it out what that looks like.\u003C/p>\u003Cp>But that way, you can just configure it, see the whole thing as, you know, that particular user. Now especially dreaming wish list, it'd be great if you could just change the form while you're on the page looking at what the form looks like for that given your role. But let's I'll get ahead of ourselves.\u003C/p>\u003Cp>Speaker 0: We're going back. We're going back, guys. Back to the page.\u003C/p>\u003Cp>Speaker 1: We're spinning. We're spinning again. We're spinning again. Let's not spin too much. Yeah.\u003C/p>\u003Cp>But no. That's a it's it is a very good idea because also with the other feature request that we talked about. Was it last time or not too long ago where we're talking about the rules and permissions as a whole. Right? And these policy units and whatnot.\u003C/p>\u003Cp>Now that these policies become way more composable, buzzword shot, we can actually you you also have the problem that it becomes a little bit harder to figure out what is the actual permission for this one user now. Right? Because it could come from multiple different places and you can have on the user overrides and that kind of stuff. So I think user impersonation becomes way more important, with that in mind as well.\u003C/p>\u003Cp>Speaker 0: Great. Let's see. We caught up to the chat. If anyone has any last questions, please let us know. There's not much time left.\u003C/p>\u003Cp>I was running out. Just the the call to action, you know, just to get them going.\u003C/p>\u003Cp>Speaker 1: Yeah. Just a moment. Please like and subscribe.\u003C/p>\u003Cp>Speaker 0: Yeah. Yeah. Yeah. Yeah.\u003C/p>\u003Cp>Speaker 1: Hit that notification bell so you'll stay up to date.\u003C/p>\u003Cp>Speaker 0: But if you truly want to stay up to date, you should head to direct us dot io/tv. I I nearly said dot tv. Yeah. Alright. No.\u003C/p>\u003Cp>But seriously, on the directors dot iotv, there's lots of interesting series that you can check out, such as this one and also other ones. And enjoy. And\u003C/p>\u003Cp>Speaker 2: see how Directus TV was built on Directus. Very cool. It's exciting.\u003C/p>\u003Cp>Speaker 1: That is pretty cool.\u003C/p>\u003Cp>Speaker 0: We have Jeron to join literally in the last minute. Hey there.\u003C/p>\u003Cp>Speaker 1: Hey there. Thank you for joining. How you doing? We're about to call it. Goodbye.\u003C/p>\u003Cp>Speaker 2: Anyway. Very, very exciting.\u003C/p>\u003Cp>Speaker 1: As always, thank everybody so much for watching. This was yet another talk where I was, like, going into it, it's like, oh, this feels like a small little bug that we could just fix. Right? And then we talk about it now, and I'm like, oh, man. Okay.\u003C/p>\u003Cp>Speaker 0: It deep go. Building a form builder and page builder. Now now\u003C/p>\u003Cp>Speaker 1: we're getting snazzy with it. But that's that's the beauty of these sessions, and I love it every time. So those are joining. Thank you so much. See you guys in 2 weeks from now.\u003C/p>\u003Cp>Or oh, no. Wait. That's the one that we're skipping for the, you know, the special week week. Yep.\u003C/p>\u003Cp>Speaker 2: It'll be, 4 weeks before our next one, folks. Thanks so much. Appreciate your patience. There's some big announcements coming that that this next week's time or next 2 week time slot is gonna be consumed with other events, and keep an eye out for the live events and things going on that week. So very exciting announcements on the way.\u003C/p>\u003Cp>We're we're excited to have such an awesome community. Have a great day. Have a great week.\u003C/p>","Love it all. Yeah. Hello. Welcome everybody once again. Thank you for joining us again in our biweekly, bi monthly. I always forget the difference between the 2, but they're also interchangeable. Our bimonthly, twice a month, session where we go over, you know, feature requests and try to go in deep, find all of the edge cases, think about everything that we possibly wanna support ever of the universe, and then bring it back down to number 42. Today, we're talking about supported nested relational values in conditional fields, which feels like a, oh, just support nested relational values. Easy. Until you start thinking about it for real, which is what we're gonna do today, and realize that it's probably not as easy as it sounds because that seems to be far from the course for these sessions. As it always So before we dive in on the every single time, before we get in too deep on the technical problems, you wanna, outline what what this is all about, Daniel? Yes. So, just for anyone that has not used this feature before, it's pretty, I think it's pretty niche. I mean, I have not extensively used it in the past, but, a little bit here and there. And I think lots of people, share this experience. But, if if you use this feature, conditional fields, you will eventually run into this little problem. So it is about the ability to conditionally render, for example, or hide or show or change fields inside of your collection edit or your item edit page depending on other fields. So you open up an item and you have a couple of groups depending on how much information there is inside of your item. It might be useful for you as a user or for, you know, to make it easier for actual users of your directus instance to hide a couple of fields, for example, so lessen the, you know, initial information overload, for example. Or you could also make use of it to actually enhance the visual, the the user experience. There's lots of stuff that you can do. Also, you know, require different fields if a different field has a specific condition, if it meets a specific condition. So lots of interesting stuff that you can do and, like, really, really customize how your editing experience looks, how it feels, and improve it for your users. And, so this is just the overall, like, high level description of what this does. But this issue that has been opened for a little bit, a little tiny, tiny, tiny while. So, it is about this exact scenario. So where you want a field to have a new, let let's say you want to hide something depending on if this item has some type of property in in a relation. I don't think I, describe this very well. But, so you want the to apply these conditions depending on some nested property. And this currently is a little bit tricky, for us because this stems stems from an architecture standpoint, like, how our forms work as of right now. So this is not like, you know, we're just missing a little if statement maybe, and then we could enable this. It's a little bit more more involved, but we'll explore this a little bit. So, yeah, this is what this issue is about. You want to, you know, conditionally style or, you know, change your existing fields depending on the nested property. And it's currently a little problematic because if you open up a form or your item page, I mean, we currently do not load every single nested relation because, you know, that it could be bad. It could be good. It could be bad depending on how large your item is. So, technically, if you open up your item page, we do not have that type of information as of right now. So you can't actually apply conditions because we don't have that information inside of the form, which is the root of the problem. So how do we fix that? Good question. Problem number 2 is we might not even have access to the info that you're trying to use, which makes this a heck of a lot more tricky to think. Yeah. Tack tack on permissions, and suddenly this gets very, very complicate. I mean and how deep is this? Right? So in my case, right, where many to any, this can this, I've seen clients with anywhere from 5 to 18 levels deep in this relational model. How much data do you load up into the current view? Right? This can get very first, Gary, you know, this can get a little bit of hands in from the chat. You know? Let's involve the chat a little bit. So So just to just to summarize this to, those three main Please, let's problems at first. Right? So right now, those conditional fields are just using the information that is visible on the form, right, with the edits applied because it needs to be reactive to what the user does. Then once you go relationally deep, we have a bit a problem because that information just doesn't exist in the context of that page at present time. Right? So that in and of itself could be easy enough by saying, okay. Let's just fetch all of the paths that are used within the conditional fields, and then at least we have that data. But we fetch it separately from the actual form content just for conditional fields purposes. That would solve part of this. Right? But then the second problem that makes that part a little tricky is that we have to merge it with the edits made by the user in the form. Right? So now we're dealing with differences in data types and how you configure them, which is one of the the sort of bigger the the second issue. Because theoretically speaking, you know, conditional fields check against the staged value of the form. So therefore, if you select, you know, a many to one item, you could check against the ID that you have selected. If you make a nested update, you could theoretically, through the rules, check for the nested value and and change it. The difficulty is, like, if you select an existing item, now the data that is staged is just a UUID. Right? It's not a nested object of values. So if your conditional field says, author names or nested name and author has to be reg, then it becomes tricky if you select the existing author because now you're checking the rule is nested field name has to be reg, but you're checking it against the u a d string. Right? Because that's the actual data that you're about to save. So that's that's another big big mismatch there. And that problem compounds the further down you go, obviously. Right? So the other thing is when you update, a one to many, we have that difference in syntax where you can provide an array of all the items or you can provide, you know, the create update, delete statements individually, which is what the app uses because it's still easier to manage for larger datasets. But that again also means that you now have to check against 2 data types and it works a little bit unlike you would expect. Right? That's kind of the the the TLDR for this. The 3rd major issue is permissions. Right? So as an administrator, you could set hide, a certain set of fields if a hidden field for this user, like, that's something they can't see is enabled or disabled, which for the end user is invisible and therefore the app can't actually run the check against it because it doesn't even know that the field exists. Right? So that needs a totally different solution where the check doesn't even happen on the app client side. The check happens on the server side. So it can check against data that the client user might not even have access to in the first place. Right? So those are the 3 major sort of problem spaces that we have with this particular feature. All of which need some sort of specialized solution for conditional fields. And hopefully, we can find some sort of direction that is 1, you know, one endpoint that rule them all, so to speak. That's a top order. I guess. We we have some interactions. Yeah. Exactly. So we have a little bit of chat. How about having a field, that just show calculated data from other columns? So it's not a column in a database, a column just for showing some calculation. So if I'm understanding correctly, to summarize that, what we're saying is instead of trying to use the nested values like an actual nest of the tree, why not have one alias field that just pulls up the relevant bit of data? So it's always just the string name, for example, from an author, and then you can conditional fields against that. Right? So instead of trying to dynamically do it against the whole tree, you're just pulling out the data that's relevant, and then the conditional fields check only runs on the top level. Alright. But lots to think about. There we go. I've done it in. Fit this problem before, so what I do is to just create another extra foreign key. It can be used to filter the current items onto many drop down. Problem is that the user need to do another selection to enable this filtering. That's kind of a similar idea. Right? Yeah. Where it's like instead of trying to nest it deeply, you just pull the value back up in some sort of way, either automatically or by having the user chip choose it, and then you operate against the static value of that field. Now the the interesting thing here is that one of the problems that we're seeing is that the way it works technically makes sense. Right? You you validate the conditions against whatever the third stage value is with the user's changes applied. Where it falls on its face is that the expectation is that it will do nested relational lookups and then dynamically apply the changes in that tree and then check against that. Right? So that could potentially solve for the first two. Right? Where we're saying, okay. We can make some sort of utility function that says, what is the conditional field rule? What data do we need for that? Then apply the current edits on top of that in a way that fits the model, right, the model for the conditional fields. So, therefore, if you selected an an ID for many to 1, we have to go fetch the nested data for that so not the permission. I saw it on the screen. It's in a different order now. So it's for the the app data context and then the nested relationships. For the permissions piece, though, we have an issue. Right? Because at the, like, the end of the day, we cannot run that in the app. That's that's basically the long story short. So those for for those who have been eyeing the GitHub repo like a hawk, there was actually a PR not too long ago with an issue, in a in a similar vein, but about the permission checks. Right? So some users were running into some issues where the application would allow you to change fields that you didn't have update permission to, for that exact reason because the update permissions were using a field that the app cannot read because you didn't have read permissions to those fields. So, therefore, the app couldn't know if you had access or not. So it would just default to, like, okay. You can do it. And then once you hit save, the API would just throw an error and be like, no. You cannot do it actually. Right? The way we solved for that is with a new endpoint in the API that basically say, hey. For the current user, am I able to update this particular item in this particular collection? Right? And it will return, like, these are the fields that you can edit, as far as I understand. I I'm a little hazing the execs, you know, IO, but that is effectively the gist of it. Right? And it feels like It feels like this feature will probably go in a very similar direction, where we need to have some sort of API endpoint where the app can say, okay. Here's the current about to be safe changes. For the for the current user, what should the conditional state be, I guess? Right? Because that's the only way. If the the app cannot read fields that are used in the conditions, it's kinda game over. Right? However Interesting. How how would how would that endpoint look like? Like, what type of payload how would that translate all of the different requirements that we have? Interesting. So I'd imagine I I know the requirements generally are, a, we need to fetch all of the data that is used in the, conditional fields rules. Right? So we just have to look up what are all the fields and what is the whole tree that is used within the conditional fields and fetch just those in the exact same structure so so we can run the checks against it. Right? Then we need to dynamically apply all of the staged changes from the user because one very important use case for conditional fields is things like, you know, you click a toggle and you show and hide fields conditionally. Right? That's kind of one of the major use cases for this. So it needs to be real time. And then the last thing right now, I'm pretty sure that's, it just returns. I I think what we do right now is we effectively just loop over and and then merge the field's configuration for the current item with the conditional field result, sort of smash them together. Right? So if, like, the default field is hidden in your conditional fields, you have field that's visible, then that takes precedence, and we merge them together by by field key. Right? So we dynamically update the area of fields that exist within the form based on that logic. So to translate that into an endpoint, you would most likely have to have an endpoint that takes what collection are we in, what item are we in, because that might affect, you know, the the IDs and all that kind of stuff. And then what is the changes that you've currently made so we can dynamically merge those and then do all of that logic on the server side and effectively return a new list of fields that should be visible in the app. Right? That's theoretically possible. Tricky thing, performance. Right? It it is exactly. Like, I was already, like like, inhaling and just to, you know, finish your sentence so I can say that. Exactly. So, yeah, that that would probably then lead to, you know, some delay because, let's say, you type a name pretty quickly, you know, like, example, whatever. Now you made, like, I don't know, 6, 7, 8, whatever it is that you're typing. The key presses, alright, do we debounce those? Then, alright, we have another little delay. So we then have to contact the API, which gets the stuff back, and then we have another little delay. And then the whole experience might suffer depending on how exactly we do it. Because, like, even if we now if we now, start, like, debouncing, that could lead to other problems. You know? Like, if if we want something to change, if the the the the text field contains a specific substring or something. Yeah. Then then that won't trigger fast enough, basically, which, you know, is kinda not the point. That is that's really hitting it on the head because this has to be you click a toggle, stuff shows up. That's that's the goal. Right? So it needs to be immediate and interactive. So if you debounce it for a second or something, to your point, the experience is gonna suck because you click a button and then Yeah. You're already looking somewhere else and then magically stuff shows up. Right? This, it's instant. Right? Because the app has all the context and data and permissions and things that it needs, so this is instantaneous for this to show or hide. Mhmm. You know, make required, do whatever. The the toggle here, the app side is doing all that, and it's almost instantaneous where you go server side now if you're having to send back to server. I'm wondering, does WebSockets' real time kinds of capabilities help at all in this space if we work towards I mean, again, we've always wanted to make the app real time so that we can do, you know, multi multi user editing of records and things. Yeah. I think, realistically, the main it it would reduce the network latency a little bit, but I think the main time spent on this is re fetching the existing item data and then merging on the changes. Right? Now this is a nice segue because I just read it in the chat. Does it have to be solved dynamically on the fly? Question mark. I think the answer is yes, unfortunately, because it's based on the current user changes, so it's always have to be dynamic. Is it possible to require users to save the query somewhere, save like a SQL stored procedure kind of thing? If so, would that make it easier to resolve? Yes and no. I mean, it's again, because it's based on the current sexual users changes, we can't really have that prepared because you don't know what those changes will be. That being said, you know, if the item that you've just read, we could cache that for a little while. Right? The tricky bit is just when do you invalidate that cache? That's been a bit of an issue before, right, where right now we have to sort of auto purge the whole thing and it's kind of inefficient, which is a very high on my personal wish list item, but let's not psych sidetrack too much on that in this one. So so the the problem is we can cache that particular call to the database and just be like, oh, in the last, you know, 10 minutes, we already fetched this. It's probably the same. But if some other user changed it in between, you know, it gets a little bit tricky. But we could cache the database call for sure for sure. If so, would that make it easier to resolve? Yeah. It would make it a little bit faster. We still have the network latency though. Right? Even if the API would just respond immediately from all the caches and skips all the execution, just by the nature of it having to go over the Internet, you know, you might have your the the API that you're talking to might be in a different region or something that might be, you know, a 100 200 milliseconds latency just from that. And then it's just the experience is gonna suffer a lot. Like, a lot. Right? Yeah. To a point where, oh, I see our own team here in the chat mentioning a similar thing where it's like, maybe conditions should just not support fields you don't have the permissions to. Because that way, you know, all the commissions, because then then you have this issue where it has to be on the API side. Right? So maybe one of the requirements that we're learning here now is that it kinda has to be on the app just to be able to keep that instant, feedback loop going. And then to mention for conditions not to support fields you don't have permissions to though, you have to configure it on a sort of per role basis what those conditions are because only on the role do you know what fields are available in the condition, Which is true, although that makes configuration hack a lot more annoying. Because if you just have you know, I wanna show an email field when you click, subscribe to newsletter or something. Then now you have to reconfigure that for every single role. Right? Yeah. Chicken. There's always plan c, which is just aggressively saying no relational fields and conditions. That's kind of what we've been doing so far. You know? It it sucks. Does Paul is does the new policy system maybe allow us some better flexibility so that it's not on a per role? It's configured, but Oh, don't get me started. But, again, it's a lot of and no. It does require, I think I think this I I think the the idea is this really has to be either real time in some way, you know, WebSockets implementation, the app itself. Goal longer term is to have that kind of capability anyway. But with a policy based, you know, if we are able to, you know, walk the conditional tree and we can we can see that and pull the data necessary. Now it might be that we wanna limit, you know, number of conditions that you can apply or number of levels deep you can go with a conditional. Right? Because I don't know that we can have an you know, the infinite depth capabilities. You know, I can go 18 levels deep in a condition that seems insane to kinda try and cash all that, or even manage all that in front end. But is it you know, maybe it's a 1 or a 2 level deep is what is allowed, from a conditional rules perspective kind of thing where it's manageable, controllable, and sustainable. The the thing to me though when it comes to conditional fields, to me, that is more a form builder type of thing than an access control type of thing. So having to configure how the form behaves on a policy to policy basis feels hard to manage, if that makes sense. Because now you're the output form is just it's hard to expect what it's hard to know what to expect once you have, you know, multiple different policies doing multiple different things when it comes to form building. Now this is a complete sidebar. That's also the beauty of these sessions. Right? Divergent thinking. Love it. Here we go. Strap in, folks. It's there's there's another singer, Annette. See I see you nodding over there. But one thing that we have been sort of, you know, floating the idea of is this idea of, like, what if we decouple the data model from the form. Right? So it's decouple the actual actual how you interact with the data from the data model itself. So therefore, you could have multiple forms for the same database table. Right? And then in a policy or in a role or whatever, you would choose what is the form that we wanna use for this particular table, for this particular set of users. Because the one of the other known I mean, issues might be a bit of a big word, but one of the other downsides that I've on my personal wish list, it's kinda like if you have read access, we we show and hide fields that you'd expect. Right? You don't know that a field exists. It doesn't show up in the form. It also means that if you're doing a form building exercise where you have, like, multiple columns, like, 2 things side by side, and all of a sudden one disappears, you know, the form kind of reflows, but it it results in a bit of an unexpected state. Right? Mhmm. So by having, you know, that form, having that form decoupled from the data model, now you could just say, okay. We're gonna make a form that we know will look exactly like this. Like, what you see is what you get for the form or the role that we attach it to. This is, again, a way bigger discussion than just a little brain fart dumping out into the world here. But that is that is, you know, one of the ways around this because then you do have conditional fields per role or per policy group or whatever you wanna call it. Alright. Many, many different things. I'm trying to I'm trying to find a way where we can, you know, like like, define a little pathway for us right now, but it's it's very hard because there's so much so many different things that we could do, technically. So yeah. Yeah. My initial feeling, like, when I read about this was, yeah, it sounds very reasonable, like, in the naive way, you know, the very naive, first understanding of the of the problem. Very similar or basically what you said in the beginning. Alright. So we do know when we open the form, what people used inside of the conditions. Alright. How about we then fetch those things, all of the related stuff to separately from the table? Alright. So far so good. Then the permission issue comes in. Alright. Are they allowed to read this? Yes. No. Alright. What do we do if they and, and then it gets tricky, and then it starts to spiral. Alright. Goddamn. Okay. We got we got a couple. Yeah. We we got a couple of steps that sound like alright. Alright. Maybe maybe yes. Yeah. And okay, permissions. There's there's always the point where we could put limitations in place. Right? It's like, we like to think with the least amount of limitations as we can while keeping it fast. But to Tim's point earlier, we could make a line in the sand and say, okay. You know what? Nested relational data is only allowed if you have read access to those those data points. Otherwise, it's just not intended to work. Because that way, we can remove the server component, keep it on the app site, and make it work the way you'd expect to make it work fast. But we put a ceiling in place to make that happen. Right? That is a very real, a very real in between. I'm I'm still been noodling on that that idea that you had, Jonathan, to, like, could WebSockets potentially help with this? And the more I think about it, the more I'm like, maybe, just maybe. Because if that database call is heavily cached and we send, you know, a message of, like, here's the stage change ID such and such, and then the API will just respond as fast as it can with, like, the the combined change and the new form that comes out of that. If we can heavily cache it enough, we can make that work. Now I see Tim typing in the chat. I'm curious if he's gonna say the same thing. I knew it. That was exactly what I was gonna say. He put in the chat, WebSockets are great, but we cannot rely on them for stuff like this as they're not a hard requirement to run direct this. Not yet. And this is this is a different question, of course. Like, should it be a hard requirement or not? Right? Because and this is again a a bit of a sidecar sidebar from from this, this particular discussion. Because the way we implement the WebSockets right now I mean, first and foremost, we haven't really used them in the app yet, for very similar reasons to this actually, which is, like, we have to be careful with relying on stuff, maybe, yes, no, and then tricky tricky. The the the real question is, you know, WebSockets are not supported everywhere like regular HTTP requests are. Right? So for example, there's there's a couple of platform as a service providers that just will not work with WebSockets in your container or something. Right? Because there's so many hoops you could jump through. You gotta go from, like, you know, the CDN to, like, some sort of load balancer to some sort of proxy container to some sort of, you know, container that has the actual connection. Yeah. And to to Tim's point in the chat now too, if you wanna do snazzy things on the edge, like scaling back to 0 containers or something, you cannot have a persistent connection at all. Right? Which is another very good point. I know there was another this another discussion thread that has seen some activity recently around, being able to run directives in a serverless environment, which, oh, boy, is a whole different session of one of these. I'm sure. But if that were ever, you know, a deployment target that we wanna officially support, then WebSockets are just out. They're just unavailable to rely on, right? And then the question really becomes like, okay, what what is more important to us supporting serverless environment scaling down to 0? Or are we gonna say, well, Directus is just a a a tool that is intended to be a long running server because with cron jobs and hooks and all that kind of stuff. And therefore, WebSockets are just enabled just like the API and you can use them and we can heavily rely on it in the app to make it faster and a better experience. Right? That is gonna be a difficult call to make, because it's it's it's, at the end of the day, a little bit of a subjective one. I know it's it's, we haven't really done all the pros and cons of research and all that kind of stuff. But it's like, you know, people have very strong opinions on this kind of stuff. Very strong opinions. We have to be careful, with Tim. He probably has one of those. Like, one of those nasty opinions. One of these nasty, nasty opinions. Oh, no. No. No. No. Alright. Yeah. Yeah. With the angel emoji. Alright. So far so good. Then let's maybe, you know, do the little, exercise. Alright. Let's say we go down that route that we mentioned with alright. You can't put conditions on stuff that you can't read or that this specific user can't read. Alright. This would have a couple of repercussions. Right? Like, then alright. You have multiple different different user roles. Do you then, as an admin that is configuring this collection, do you want to? Probably not. But do you want to actually configure then these things between different roles all the time. That sounds like a big pain, to be honest. Like, very annoying. Would we? Yeah. I mean, we do have to attach it to some kind of role. Right? Because, as of right now, you know, there can be, like, unlimited different types of user roles. Yeah. And some of them can read those fields. Some of them don't. We don't know that. Would we like to share this then with some type of diffing between those? But oh, man. This this just sounds like spaghetti, like, the largest bowl of spaghetti that you can think of. Weird. It doesn't sound enticing to go down. Yeah. I think the the the conflict that we're finding ourselves in is that we know you can configure conditions for fields that you might not have access to and then it doesn't work. Right? So what are we gonna do to help the admin user in that situation? Like, we need to educate them on this. We need to educate them on the, on the on the limitation there or show it somehow or prevent them from making that mistake in the first place by connecting it tightly to a role somehow. Because once you connect it tightly to a role, we know what fields are available, and we can only service those in the conditions. Right? Mhmm. I agree with your earlier sentiment when you were, like, configuring that on the role and having to reconfigure it for every single role that might access this thing feels like a nightmare. That feels like so much extra work. Mostly because and and I briefly touched on this before, but mostly because I really see this as a form building tool, not so much an access control thing. Right? Yeah. It's to me, it's similar that you wanna have 2 fields side by side. I wanna have one show up and hide based on the value of the other. That's that's all sort of form building magic, not so much access control magic. So I I kinda strongly feel like we don't wanna conflate those 2 and and put, like, too much form building stuff in access control. Because it Right. It just makes me context. Yeah. Thanks. So, similarly alright. How about then we reverse this a little bit? So, let's say, as of right now, you know, the admin goes into the collection thingy into the conditions and configures, you know, how it's supposed to look like, all of the different conditions, you know, height depending on this checkbox, make the title red. And then we attach a roll to that filter and we can now check, you know, is this role can this role even apply this filter? And we can immediately just say, oh, no. This role is not compatible with this filter because it can't read x and y and z. And this would also solve, like, solve let's let's in big big big quotation marks, solve that problem of, you know, like, having multiple user problems having multiple user roles that you could, you know, just say, alright. But this filter is, yeah. I I'm already, like, thinking while I'm talking. So then you come into this whole thing. Alright. Maybe you want to have different conditions for different user roles. Maybe. Here we are again. Here we go. Here we go. Love it. That's the moment where it starts spinning again. Tim, just in the chat, does not make sense to build your forms based on what fields you have access to? Which, yes, I think that is kinda closing closing in on the the sort of wild wicked idea of saying, what if you can just configure multiple different forms and you can just make a form that is dedicated to, you know, one one role? So that way you can you know for a fact that all the conditions exist and all the fields exist, and the way you configure the form and the layout is tailor made for that role because the only fields that exist are the ones that exist for the, for the item. Yeah. I can I can feel I can already, like, feel the pain through just thinking about this of, you know, the then, like, synchronizing between different types of forms between different types of user roles and oh, man? It's getting it's getting a little bit of rough. Let's say let's say rough. Alright. Tim has another thing. You effectively already do that using access control as the form will not render fields you don't have access to. Yeah. Which I think might become an issue at some point in the not too distant future. Because one other thing that we've sort of been been noodling about, Jetta the Jetta, is the idea of a little bit more flexible grit for forms. So right now, it's it's a 2. Right? You can either make a full width or you have 2 side by side. That's it. We also just been thinking about, like, what if we make that just a configurable number with some with some responsive breakpoints potentially. You could make it a 12 grid. You could make it in the 8 grid. Whatever. Right? At that point, if the field in in column number 6 disappears because of redexes, we cannot we can no longer sort of cleverly reflow it, to make sense. Right? Because now we legitimately just don't know where things are supposed to go anymore on the page because it just it it just has to be become a a gap, basically. At that point, we might end up having to just show, like, there used to be a field here, but you don't know about it. Right? Because otherwise, the whole form layout is tell anyone. Because otherwise, the form layout is just gonna look either broken because you're gonna end up with blank spots all over the place, or, you know, if if we're trying to I I think it's safe to say that we're trying to sort of reorganize it on the fly. It will break, because we just don't know what needs to go where at that point. Because it would be a multidimensional grid. Right? That will be 2 dimensional because you can have things go 2 rows or 2 columns, etcetera, and then you have a problem. Right? Kinda like, I think of dashboards basically in terms of just positioning stuff all over the place. But if we go that route, if if that ever comes to fruition, right, again, it's just a random thought. It's not actively being worked on or anything. But, if we're going in that direction, I think we need to have some sort of way to have a form per role anyways. Because otherwise, you know, you're gonna either have a form with a bunch of holes in it or with place holders that you're like, hee hee. You can't actually see this. Or, you know, or it just needs to be per role because that way you can just make one that is, you know, tailor made for for that particular role. Well, whether or not, we're actually, you know, looking into this, we already have our first customer. Then he said, I'm sold on the option to build a form per roll. So good. Sold it already. It was fast. I like it. So if we can inherit, like, a global so it inherits the the default kinda data model form that you configure, and then allow you to adjust that on the specific role, I think that's actually pretty freaking cool because we do have those kinds of use cases where, you know, this particular business and especially if we could apply specific conditionals on that form, it means that, you know, my business user versus my consumer user could have a very different form experience intentionally and different conditionals. Right? The the default conditional for the business user presets those conditions and organization. I I kinda love the idea. Whether or not again, this this comes back to whether or not this actually we we decide to allow additional depth, you know, conditionals. Just having that particular feature seems kind of amazing. As long as we can inherit the default, then if I don't need that kind of capability, I can just use the default and manage the default that we'll get. If I've got a custom reason for adjusting the form. Pretty brilliant. I like it. So there's a question by Benny Wade. Could we make groups configurable per row rather than making a whole form per row? Keep it a bit more modular. AKA, can we nest these forms? Yeah. That that Let's check as we check-in with our friend v form and see how he feels about it. -Oh, boy. Can't wait. Guys, if you enjoy messaging, please. Where you have the forms that or the view of the page or whatever you wanna call it is the same for everybody, but then you just have a section where it's like this section only shows up for x role. Right? Could be interesting. That is a conditional field in and of itself, of course, where it's like, the condition is show or hide this thing if current role is x y z. Right? Which now I'm thinking about it. I'm pretty sure that exists. Present time. I'm pretty sure you can this is something I'll have to test, actually, because I know we have those dynamic variables for current user and current role in those. I don't remember if we support those in conditional fields. Because if we do, you can step a group and have a conditional field on the group that says current role equals x y z and then hide the whole group. We do not, Tim. Tim and a chat. Why not? Why not? He calls me out he calls me out on my bluff. It's happens happens sometimes. Yeah. But that would theoretically be a a soul for the same thing, though. Right? Or you could just say the whole group is hidden for a role, and therefore, no problem. You make it so that you can have the same field in different presentation section configured per role? Right. Right. So the same field multiple times. Yeah. That is that is another thing when it comes to dynamic form building and, just full stop dynamic form building at that point. Right? Because right now, the form is data model first. It's like you have a title field, therefore, you can now have a title input because it's 1 to 1 to the data model. Right? With a form building thing, maybe you have 2 title fields, like, 2 fields that point to the same underlying data thing. Right? There's instinct. I don't know why the hell you would do that, but you could. For for some interface, it may set I mean, in this this example where it's like you have the same field in different sections and the section show and hide based on the role, it starts to make sense again. I for admin users, it'd be interesting, but it it yeah. For sure. Then for, I I think there's a a definite interesting use case for certain data types where it would help to have multiple fields, multiple visual fields for the same underlying column. Think about, like, an address interface face or something. Right? Where you wanna have address line 1, 2, and then, ZIP code and all that kind of stuff, but you wanna save it as one field in your data model. Not super uncommon, or as a let long sort of search thing, right, where you have a let and a long input and then an address field, and those are all connected. So you can type in an address and it'll geo look up the let long, but then the thing that's saved in the database is just the let long. So there's definitely, you know, some additional things that we unlock with that sort of modular form idea. Right? Alright. So what I gathered from this, is that we're basically about to build our own page building framework where we can dynamically close plugs. So we're basically set, you know? Like, director's page building, that sounds like a great idea. Okay. On the So just to solve condition fields. That's that's the beauty of it, isn't it? How did we how did we get here for just solving nested conditional fields? Yeah. It all started so innocently. You know? It's true. I just want to hide a field, and now we're basically embarking on a mission to Okay. This is this is actually this is a good thing because this is a perfect example of the sort of, you know, request review session. For those who've been here before, you've seen this happen before. It's like we go completely off the rails in all directions, and then now let's try to see how we can actually get this back on track for nested conditional fields. Right? So as a you know, in a potential future utopia where you can just magically conquer up any sort of form, any sort of view that you possibly want. Great. But as of right now, I'm kind of thinking, based on everything that we talked about so far, it, to me, makes the most sense to follow Tim's suggestion from earlier, which is basically you cannot put the field and conditional fields that the user does not have read access to. Right? I think that is that is a safe call. I think doing it on the API side, we're never gonna be able to get it just performant enough, and we don't really wanna make WebSockets a requirement for this to work. So I think as of today, you know, what can we actually achieve in the next month or 3? We would most likely keep the client side, keep it fast so we can do all the calculations on the client. It has to be from current fields that you have read access to. The main difference that we have to do is that we have to dynamically, when you open the page the first time, we have to load up what is the nested data structure of this item based on the rules used in conditional fields. And then have some sort of utility function that can cleverly combine the stage changes on top of that. Right? We have to account for the differences like many to one ID versus nested object. We have to account for things like the one to many update structure versus array. But that that way, we can merge that and we can do a client side. Right? I don't think we should do that per role. That just feels like a nightmare to configure, to be completely honest. Yeah. And a lot of a lot of duplication. Again, in a utopic utopic utopic? Utopia stick future. Utopia like future. Utopian? Utopian future, you know, where you have more of this flexible form idea. At that point, you know, you can say, okay, When someone I'm already boring Jonathan to death, I see. When when you open this this page for this particular role, we use form xyz instead but that is again a way way future discussion. But then I think, you know, we can support the core ask for this this feature request, which is if I say nested author dot name, I expect that the lookup, what is the name of the nested author no matter what. If I select an existing one, it needs to look at the name of the existing one. If I change somebody's name, it needs to look at the changed name. Right? That is something that we can I'm pretty hopeful we can turn that into some sort of usability function that we can run relatively quickly on the client side and make this happen. Right? Yeah. That shouldn't be shouldn't be impossible. Yeah. Yeah. Look at the from Natron. And 10 rabbits with 1 multiracial conditional stone. Yeah. Exactly. As an admin that's configuring these conditional fields to another person in the chat, it would be nice to see the whole form that a person with a given role would see. Maybe a view as role option somewhere. Fully a 100% agree. To Jonathan's point, there's another feature request about that user impersonation. Again, very high on my personal, wish list. Right? I would love it as an admin. And not so not just for the for the particular form and settings or something. I really want there to be a way for admins to just say, browse the whole app, impersonating a different role so that you can just click around and see exactly what that user can see and do. Right? From a visual perspective, we'll probably have to have some sort of banner, zoom out a little bit or whatever. We'll figure it out what that looks like. But that way, you can just configure it, see the whole thing as, you know, that particular user. Now especially dreaming wish list, it'd be great if you could just change the form while you're on the page looking at what the form looks like for that given your role. But let's I'll get ahead of ourselves. We're going back. We're going back, guys. Back to the page. We're spinning. We're spinning again. We're spinning again. Let's not spin too much. Yeah. But no. That's a it's it is a very good idea because also with the other feature request that we talked about. Was it last time or not too long ago where we're talking about the rules and permissions as a whole. Right? And these policy units and whatnot. Now that these policies become way more composable, buzzword shot, we can actually you you also have the problem that it becomes a little bit harder to figure out what is the actual permission for this one user now. Right? Because it could come from multiple different places and you can have on the user overrides and that kind of stuff. So I think user impersonation becomes way more important, with that in mind as well. Great. Let's see. We caught up to the chat. If anyone has any last questions, please let us know. There's not much time left. I was running out. Just the the call to action, you know, just to get them going. Yeah. Just a moment. Please like and subscribe. Yeah. Yeah. Yeah. Yeah. Hit that notification bell so you'll stay up to date. But if you truly want to stay up to date, you should head to direct us dot io/tv. I I nearly said dot tv. Yeah. Alright. No. But seriously, on the directors dot iotv, there's lots of interesting series that you can check out, such as this one and also other ones. And enjoy. And see how Directus TV was built on Directus. Very cool. It's exciting. That is pretty cool. We have Jeron to join literally in the last minute. Hey there. Hey there. Thank you for joining. How you doing? We're about to call it. Goodbye. Anyway. Very, very exciting. As always, thank everybody so much for watching. This was yet another talk where I was, like, going into it, it's like, oh, this feels like a small little bug that we could just fix. Right? And then we talk about it now, and I'm like, oh, man. Okay. It deep go. Building a form builder and page builder. Now now we're getting snazzy with it. But that's that's the beauty of these sessions, and I love it every time. So those are joining. Thank you so much. See you guys in 2 weeks from now. Or oh, no. Wait. That's the one that we're skipping for the, you know, the special week week. Yep. It'll be, 4 weeks before our next one, folks. Thanks so much. Appreciate your patience. There's some big announcements coming that that this next week's time or next 2 week time slot is gonna be consumed with other events, and keep an eye out for the live events and things going on that week. So very exciting announcements on the way. We're we're excited to have such an awesome community. Have a great day. Have a great week.",[250,251,252],"bad648f8-fb30-4a79-ab4f-df5678800ac9","b1a78d8c-341f-4e4e-91d7-1c98574b7b6c","a09e4bf5-1fa6-4813-b642-53b986e1fdf9",[],{"id":133,"number":134,"show":122,"year":135,"episodes":255},[137,138,139,140,141,142,143,144,145,146,147,148,149],{"id":141,"slug":257,"vimeo_id":258,"description":259,"tile":260,"length":156,"resources":8,"people":261,"episode_number":265,"published":266,"title":267,"video_transcript_html":268,"video_transcript_text":269,"content":8,"seo":8,"status":130,"episode_people":270,"recommendations":271,"season":272},"inline-data-editor","926603960","In this recording of our live event on March 21 2024, Rijk, Jonathan, and Daniel discuss inline editing.","db868174-6a9e-4823-9962-382f5bd55cb1",[262,263,264],{"name":163,"url":164},{"name":166,"url":167},{"name":169,"url":170},5,"2024-03-28","Inline Data Editor","\u003Cp>Speaker 0: Hello, everybody. Welcome to feature request review with me as a host today, joined by the good old Reich, Van Zanten himself and Jonathan Wagner. Hello. Hello, everybody. Thank you for coming.\u003C/p>\u003Cp>Very exciting to see you all. Quite quite the quite the collection of people we have here from Algeria, Japan, everywhere. Germany, Austria. No. No.\u003C/p>\u003Cp>No. I nearly said it. But, yeah, today today, everybody's, apparently favorite topic because there's so much demand here in the channel right now. Inline editing, which can mean a lot of things. So let's just take a look at what a small example could look like.\u003C/p>\u003Cp>If you take a look at the screen shared footage of Jonathan, you'll see this is our feature request that got in, which you can vote on, by the way, in case, some people are not aware of this feature in our discussions in the director's repository. You may vote on stuff that gets implemented into the software, which is pretty cool. And, today's topic is about inline editing. If we scroll up a little bit to the top to the screenshot, you might have seen this in other interfaces online, you know, when you use Notion or whatever, like, many many sites implement this a little bit differently. You know, on Trello boards, you can click into the title, then you can change the title right then and there without a pop up or something.\u003C/p>\u003Cp>And, yeah, why why doesn't have direct as this yet? It's a good question. I mean, there are many, many different things that we could talk about. And, in case you have any questions or stuff that you want to share, please feel free to use the chat. We're excited to engage with you guys.\u003C/p>\u003Cp>It would be fun, a sign of life like previously. That would be nice. And how about how about we jump in right into a couple of questions? Let me quickly, give one second. Alright.\u003C/p>\u003Cp>So by looking at this, you know, basic example with the with the input field, I mean, the the first question to me is, alright. Like, how how much can we blow this up to, because Directus is very, very versatile, and, people build the craziest displays and interfaces and very, very customizable different pieces. How do they fit into this, and if we just target, like, simple inputs, for example, like in these simple example with, like toggles or text inputs. What about relations? Because those tend to be very nice to deal with.\u003C/p>\u003Cp>And, how about we go over to give over to Rijk for this one? How do you feel about different types of inputs for inline editing? Do you think we should, like, aim to be able to do everything in in in line editing? Should we reduce it down? Should we only support a sub set?\u003C/p>\u003Cp>How do you feel about inline editing in itself?\u003C/p>\u003Cp>Speaker 1: I mean, when it comes to inline editing, I think the first question that we gotta ask ourselves and everybody watching is like, what does that even mean in the first place? Is it kinda like a spreadsheet where everything is just a cell where you can change whatever you see? Is it more like, a table view by default where everything looks pretty through those displays, And then you have some sort of edit state. Is it like, an edit state where we render a whole interface in line? Or is there some sort of dialogue overlay that we're seeing when you click on one of the cells, so to speak, to to stay in spreadsheet terms.\u003C/p>\u003Cp>So I think the first question really is what is what is inline editing? What does it even mean? Right? Because we do have a different feature request for a spreadsheet view, which I think very closely overlaps, but there's definitely differences. And then I think the other question, of course, I mean, relationships, we'll dive into that in 5 minutes.\u003C/p>\u003Cp>But, if you think about the basics, I think one of the thing that we're doing with direct is with all the interfaces is to make sure that you can edit the data in a way that makes sense for what the data is. Right? So, a very basic example, you know, a slider could be a better representation for a numeric value that you're using for whatever it is that you're building. Right? But You wanna use a slider to control the value.\u003C/p>\u003Cp>When it comes to inline editing, you know, if we're looking at this screenshot where the reserve column right now presumably is in this edit state, you know, if we're dealing with inline editing in its sort of truest form, does that mean that it just turns into a sort of raw value input? Or do we include interfaces kinda like we are with a regular form? Right. So when it comes to a date value to name something, the technical value is always gonna be that that what's the exact spec, the, ISO 8601. Is that the thing that you wanna be editing?\u003C/p>\u003Cp>I would argue, probably not. You probably wanna have, you know, the data interface that you have configured for that field, which then leads to the question, does that even fit wherever we're doing this inline editing presumably in this table layout. Right? And I think we're we're quickly reaching the question then is like, okay, do interfaces even fit? And if they don't, how do we present it otherwise?\u003C/p>\u003Cp>Speaker 0: Right? Yeah. To your example, like, even even a simple slider, which is a nice way to input, like, a specific value inside of a range, which could be, you know, like, relevant to the use case, you know, where you want to restrict. You maybe you don't allow, like, negative numbers or something. But if if we allow, like, editing via raw values, then somebody might put in, you know, minus 1 or something, and then you very quickly run into the issue that you mentioned.\u003C/p>\u003Cp>We want to give people the tools to, like, input stuff as as as comfortably as possible with using, like, nice interfaces and displaying like, even displaying, you know, with with the value that you see inside of the table might, like, might not actually be the wrong value just like you described with the, like, date time, for example. So there's a disconnect there and, like, for, like, nontechnical users, for example. No. It could be it could feel bad, you know, from a user experience standpoint where they like if if marketing salespeople, what what was the thing that's, somebody said I won't name any names, but somebody said, like, the scariest thing that marketing people see is, like, a UUID somewhere. So we're dealing with UUIDs.\u003C/p>\u003Cp>Yeah. It is, is a scary endeavor, so you have to be quite careful with the display. So yeah. Yeah. Speaking to that, we have why don't we explain a little bit about the difference between our interfaces and displays?\u003C/p>\u003Cp>Because, you know, indirect is also 2 different things. What are those? How do I use those? What can they do?\u003C/p>\u003Cp>Speaker 1: Good question. So so from I'll I'll prefixes was sort of the theoretical idea behind it while Jonathan here pulls up the actual difference and how you configure them. So the basic idea is that a display, controls how a raw value is displayed in line, importantly. So it's really meant to be part of a sentence or one of the cells in a table or, you know, part of a description or something. So if you think about a, labels display, it can be configured to render it as a small color dot with a tooltip, with the idea being you can then render that in the title of a page, or in the description of a card or inside of a table.\u003C/p>\u003Cp>Right? The interface is really the the way you edit the value. So if you go and you open an item, it's basically the form field, section of of how you interact with that data. So it's really the difference between sort of block level, in CSS terms, editing of the data versus inline displaying of that same data. Importantly, those 2 can be very different representations of the same data.\u003C/p>\u003Cp>Right? So the image display will just be a tiny thumbnail where an image interface is like a bigger box where you can drag and drop stuff in and you have, like, preview and some more metadata available. They are at present a different thing. And the display is then Yeah. So so Jonathan right now is, you know, adding, a related values you know, those displays, and compose them all together to really control how an individual item is presented.\u003C/p>\u003Cp>Right? So on the collection detail page 2, there is a display template setting where, again, you can render individual fields as part of one title string. And then that's how it displays the individual pieces of data. So when it comes to editing them in line, one of the interesting, challenges that we're gonna be facing when it comes to the table layout specifically is that the value that you're seeing in here, it's very likely that that's not the value that you're gonna be editing. Right?\u003C/p>\u003Cp>Speaker 2: And is it a toggle? Is it something that you enable or disable? If you haven't enabled, what happens? If you don't have an enabled or how do I access the record? Because currently, you know, I just know that I can just click anywhere on the row, and it will open the item for me, and I can edit the item.\u003C/p>\u003Cp>How do we trigger, you know, you start to get into that. So we've got the whole interfacing aspect, relational content, allowed or not allowed. It feels like at least maybe you could almost do it in, like, an iterative. So start with the normal input fields, date fields, the the simpler interfaces and things to deal with versus relational. Relational gets complicated, right, depending on how deep or how complex that relational is.\u003C/p>\u003Cp>Now in order to edit this translation, well, that requires now that I get the full translational split toggle side by side translations kinds of things, and is that beneficial in this kind of a in this kind of utility? Yeah. Toggles, drop downs, you know, some of this, some of the more string text slash\u003C/p>\u003Cp>Speaker 1: Is this is there there is a a another additional question when it comes to how do we then render an interface to change the data, which is that there's gonna be a couple of them where the interaction would be way nicer if it's, like, truly in line. Like, so if we, if you think about a toggle, like a checkbox. Right? Kinda like the default checkboxes for selecting items. But let's say you have, you know, an on or off state on your own custom item.\u003C/p>\u003Cp>In your display, ideally, I just wanna click it and it flips. I I don't wanna click it then open a dialogue that shows me just one toggle anyways, and then close it, and then change it that way. You know what I mean? And I think the same goes for basic text values or basic numbers where I just wanna be able to click the text, edit it, and then that's it. Right?\u003C/p>\u003Cp>I don't wanna have to deal with clicking it, seeing a popover, drop down dialog, whatever it may be, then change it there because it's just another step away for something that feels like it could have been a spreadsheet, basically.\u003C/p>\u003Cp>Speaker 2: Yep.\u003C/p>\u003Cp>Speaker 0: With that example, you know, with just clicking in and changing something, Tim also brought up a nice point because, with nullable values, like, even such a simple thing as a, like, togglable checkbox, if that is even a word, you know, we already run into, like, a small little, thing, like, okay, what if you want to set it to null? You know? Like, if you uncheck the thing, it's false, but you want it to be null. Do we do we, you know, do we, like, enable triple, like, stateful checkboxes that support 3 values? Do we want to have, like, a ellipse that gives you, like, a setting for that?\u003C/p>\u003Cp>Like, similar to our v form where, you know, you're allowed to enter a raw value, but that's another piece of UI that would have to be somewhere some at some point. Yeah. Exactly. For strings, similar in that vein, you know, for strings, do you want a, empty string, or do you want a null value? Alright?\u003C/p>\u003Cp>How do you differentiate between those?\u003C/p>\u003Cp>Speaker 1: And it can even differ,\u003C/p>\u003Cp>Speaker 0: you know, from from to\u003C/p>\u003Cp>Speaker 1: Yeah. All of those are problems that we have solved in the form context. Right? Because even in the form, there's just the field label drop down that says empty this value, which is effectively nullifying it. So the question is also how much of that do we wanna pull a level up in here versus how much of that do we just say oh well if you explicitly wanna change a boolean back to a null, you can always go to the page detail thing and then do it there.\u003C/p>\u003Cp>Right? There is an escape hatch, and we could make the call to say, well, you know, the toggle display goes between true and false. And if you need to reset it back to that null state for whatever specific reason, you can always go to the detail page, and do it there. Right? And I think similarly for the string empty update, empty string, null, that that question is a question that we've currently solved on the interface settings, I believe.\u003C/p>\u003Cp>Therefore, an input interface, you can say empty string becomes null, and then that's just the value it, you know, stages, it emits. So if we go the route where we use the exact same interface you have already configured as the way to edit it in line, that problem should sort of automatically be solved. Right? Because we're using the same interface with the same settings, and then that should be fine as is. Where that part gets super interesting though, is how do we deal with conditional fields within the context of that row?\u003C/p>\u003Cp>So the way conditional fields currently work is, you know, you have the whole form of on the field, you have the whole form on the page, and then we can use the values of the form and sort of connect the dots. Right? And use it that way. On a row in a table though, the fields that are displayed might be completely different. The second piece to that is gonna be for conditional fields.\u003C/p>\u003Cp>They're now react reactive in real time where if you make a change to one field, sort of real life like, real time updates it elsewhere. When you're in the context of an individual row, and I think this is just a bigger question overall, is, like, does it auto save every time you sort of blur the input that you change something in? Or is there gonna be a save button that is like, okay. Now you've made all the changes and you hit save once.\u003C/p>\u003Cp>Speaker 0: That's a very good question. Like, especially for, like, the togglable checkboxes or whatever because, like, if you just miss click somewhere and all of a sudden, that could be a big change, you know, like with flows and automations and other stuff that runs or update events, fire something. If you hit publish on something, that should be, there should be a mechanism, you know, to stop making mistakes, you know, like, accidentally, if you have, like, you know, is active or is published field on some type of blog post or whatever, and you don't want to accidentally just oops. Oops. It's live now.\u003C/p>\u003Cp>Oopsie. Would would be nice if we could avoid that, but, yeah, that opens up another can of worms. You know? Like, how do we do you configure this on a field level? Do you configure this on a column level, on a, preset level?\u003C/p>\u003Cp>Like, where where do you where would you like to do that? That's also the thing. Because very good point from the chat also from the, is currently, for example, the displays do not know, like, which item they belong to. They are very stupid in that way with quotation marks where they just Yeah. Display a value.\u003C/p>\u003Cp>This is why they're called displays.\u003C/p>\u003Cp>Speaker 1: It's it's a presentation, presentation layer. Yeah. Yeah. Yeah.\u003C/p>\u003Cp>Speaker 0: So if if we would like to have the, you know, like, mutable, displays or whatever, you know, if we decide to go that down that road. So, we would have to provide the displays with the item ID in the collection, like, in every place because there's not not only displays only in the table view, in the tabular layout, but also in, like, titles and drop downs or whatever. Like, any and they could be at any place at any time, which makes this a little bit, dangerously spaghettty like, which\u003C/p>\u003Cp>Speaker 1: which which also, kind of bleeds into a similar yet different question, which is where do we allow inline editing in the first place? Because we're assuming we're sort of assuming the table layout right now because that's the most commonly seen elsewhere. I mean, I'm I'm sure that people that have ever seen Airtable are like, that's that's the way. But at the same time, the the question is, do we inline edit elsewhere? Like, if you have a status icon in your page title, does that become an inline editable thing?\u003C/p>\u003Cp>Right? In the chat somebody says we'd appreciate it for the card layout, maybe even the calendar. I would agree. So on the card layout, if you have in your description of an individual card, you have a a text display. If you click the description, can you now edit the description of a card in line, which opens up a big can of worms, especially from a UX design perspective.\u003C/p>\u003Cp>Speaker 2: I I guess because because we're we're concatenating that into a string in the display right now for a card. Right?\u003C/p>\u003Cp>Speaker 0: Mhmm. Mhmm.\u003C/p>\u003Cp>Speaker 1: So if we're just The same for page titles for the for for that matter or the calendar layout. Yeah. Yeah.\u003C/p>\u003Cp>Speaker 0: And Tim, Tim, another fun, fun little thing that could happen if you're already editing something and you have auto refresh enabled. Somebody updated your stuff in between the edits, and now you have another edge case. Love it. Love it. Love it.\u003C/p>\u003Cp>Love it.\u003C/p>\u003Cp>Speaker 1: Which is gonna be the same issue that you have with, you know, the regular form. So I'm hopeful that whatever solution we come\u003C/p>\u003Cp>Speaker 2: up with that right now.\u003C/p>\u003Cp>Speaker 1: Yeah. Exactly. Whatever solution we come up with for that, I'm sure the same solution should also then work here. But Yeah. For this So this is a good example in the cars layout.\u003C/p>\u003Cp>Right? So in that right side bar, you see title, subtitle, and you can configure any combination of the different fields with any sort of additional strings in between, for like adding a dollar sign in front of price. That kind of stuff. Right? So in this particular case, it becomes extra interesting.\u003C/p>\u003Cp>Because if you now were to click on the number of the price in that description line, do you expect it to be editable? Right? And how do you determine that? Yes or no? Because making every editable globally at all times feels like a UX nightmare waiting to happen, but it also unlocks a lot of flexibility.\u003C/p>\u003Cp>Right? So it's a tricky one as many things are.\u003C/p>\u003Cp>Speaker 0: Of course. So how about how about then we take a different look? So now we thought about tables and the current layout and whatever. Technically, there's also another option of adding a new layout, like you mentioned earlier, with the spreadsheet layout, which could be the point where you do that type of stuff. I don't know.\u003C/p>\u003Cp>Maybe, you know, I'm just, you know, throwing stuff in the room right now just to discuss a little bit. But Yeah.\u003C/p>\u003Cp>Speaker 1: Because it does have the mute display thing. Yeah.\u003C/p>\u003Cp>Speaker 0: Yeah. Yeah. So maybe if it turns out to be better or easier or whatever, the spreadsheet layout could be an interesting point where we could tackle this, but, then we have new, cans of worms and cans and of worms stacked upon each other, you know, till this evening.\u003C/p>\u003Cp>Speaker 1: Stack a can.\u003C/p>\u003Cp>Speaker 0: Which which is fun. Yeah. Because, you know, a spreadsheet layout people come into a spreadsheet layout with lots of preconceived notions. Is that the is that the word? And\u003C/p>\u003Cp>Speaker 1: Like, I think expectations is the word I would say. Yeah.\u003C/p>\u003Cp>Speaker 0: Expectations. Yeah. Yeah. Yeah. Yeah.\u003C/p>\u003Cp>Expectations and and stuff that they would like to have or that they expect to be there because it's, you know, spreadsheets are, daily used by billions of people. So they do want to have, like, conventions and keyboard navigation and different stuff that they already, you know, introduced to the day to day life with bulk renaming, whatever formulas. Maybe they think that this is then an actual spreadsheet that they can do calculations in, which is another cool feature that we would like to have probably from\u003C/p>\u003Cp>Speaker 1: different feature requests for a different day. Yeah.\u003C/p>\u003Cp>Speaker 0: Exactly. Exactly. Exactly. So spreadsheet seems to be a very big thing, for me personally. Yeah.\u003C/p>\u003Cp>Speaker 1: I think to me it's just a very different thing, isn't it, than than this inline editing approach that we're talking about? Because I fully agree with what you're saying. If you close your eyes and you think spreadsheet, there's a whole set of rules that come with that. That if you miss one of them, you have a bad spreadsheet. Right?\u003C/p>\u003Cp>Because if you look at Excel versus Google Sheets versus Excel on the web or even Apple's, what they call it, numbers, they are all effectively identical in the exact same settings, exact same thing you can do. It's a right or wrong approach. So, funnily enough, for a session like this, it would be a very short call because it's like spreadsheet. It's basically a known entity at that point. Right?\u003C/p>\u003Cp>I think where it gets interesting to me, and this is sort of the the the Airtable spreadsheet equivalent. It's like, you're not dealing with the spreadsheets. You're dealing with a table that you can edit in line. But it's not a pure spreadsheet in the technical term, right, where you're dealing with cells with raw values, so to speak, rather than UI elements where you edit the values. Yeah.\u003C/p>\u003Cp>Same thing in the chat was was coined there. The reason why I immediately started thinking about okay. So our display is now editable as a concept is basically from that modular fashion. Right? Because making one new layout that does inline editing sure.\u003C/p>\u003Cp>We could totally make that happen. We could also make it an option of the regular table layout and then that's it. Right? To me the interesting question for this is really like, is there a way to make it work for any display anywhere? And is that something that we wanna do or not?\u003C/p>\u003Cp>Because by doing so, you get the tabular layout feature out of the box but you also unlock it elsewhere. Like, if you have, a list of one to many items on, a record, each of those one to many items now also has inline editing because they are using displays to render those values. Right? So it it just, like, it transforms this discussion from an inline table editor to a bigger sort of, like, what does that editing in situ look like across the board?\u003C/p>\u003Cp>Speaker 0: Very, very good question. I wish I would have the answer to it, but, yeah, like you said, I mean, for for for example, for the, like, relational stuff, I could see, you know, reusing the existing drawer that pops up in different places, which could be a nice experience. You know, if you let's say you have a, a website collection with blog posts or something, articles, whatever. And as the drawer opens and you can use the currently already existing, like, relations go through the list, it it's it's with pagination and stuff. That could be nice.\u003C/p>\u003Cp>But like you said earlier, if for smaller fields, it feels like add UX if you, you know, just want to change one text and then the drawer opens or, like, a pop up opens with just one input. That's, like, at that point, it just feels very not thought through, which I would like to avoid. Yeah. We got correlate with this PR. Yeah.\u003C/p>\u003Cp>Yeah. Yeah. The the batch editing is also a nice thing. So slightly different.\u003C/p>\u003Cp>Speaker 1: There's also the the, the bigger question here, Which is\u003C/p>\u003Cp>Speaker 0: As it always is?\u003C/p>\u003Cp>Speaker 1: As it always is. But it's that's that's what these sessions are. For those who are new, in these sessions, we always go find all of the edges and then take it back into what is actually realistic in the next step. But so think about it. If if we're now dealing so so you we explained it before that the displays were meant as a presentational only unit and interfaces are meant as an editable unit of the same value.\u003C/p>\u003Cp>Right? But now we're saying: What if displays are editable, but only at sometimes? So some displays like a string we wanna make inline editable, Some displays like a checkbox inline editable. And some like a relational related values or something we wanna have a click with some sort of dialogue to to have the space to make it a proper editing experience. Right?\u003C/p>\u003Cp>The question could also be, should those still be 2 separate entities or should they all be interfaces? And based on how we where we're rendering an interface, it can display in different ways. Right? So if you have an interface on a form where it has enough space to grow, it can show as a proper big input. But if you try to squash it into a cell of a table, it just drops the visual representation of an input and becomes one of those underline only in inputs for example.\u003C/p>\u003Cp>Right? Because then with a read only prop, yes or no, you can toggle between a string that's just rendered as a string. Or when you click it, it switches into this inline interface version, basically. Know what I mean? Because then for a display one, it can always just be interactive for an input, you can just click to start typing for, a related values one or a relation when you can click it and it would just do it in a pop over or dialogue or something along those lines.\u003C/p>\u003Cp>Speaker 2: So depending on the interface type or the interface implementation, you could allow or disallow inline editing ongoing. Right? Right.\u003C/p>\u003Cp>Speaker 1: It it would basically mean that the interface is always the thing that controls how it's displayed, because therefore you can have the interface control how that interactivity works in that display context. Now, that does, of course, come with the the side effect that you can no longer have a different display per interface like we currently allow. So theoretically, you could use, you know, a text input interface, and then an icon display if you wanted to. Or, you know, you can have a rating input that is a slider and then a display that's that's rendered as stars. I don't have the stats on how popular that is.\u003C/p>\u003Cp>Like, that would be a breaking change where we remove that. At the same time it also makes it easier to configure. Right? Because you can have, okay, I'm using the icon this, icon interface, and at smaller scales, it turns into an icon display. Right?\u003C/p>\u003Cp>Speaker 2: So I guess another option could be that if you toggle the, you know, inline capability here, then the display gets turned off. Right? You don't have display capability. So you don't have a breaking change, you have the ability to come in and edit an existing interface, keep the existing display capabilities where I don't know what the overhead looks like for that, but something that we could think about instead of just outright ripping this out because I I still think, again, this is gonna be, I think, the most common case where I would want the ability to do, like, inline editing is on strings and numbers and dates. Right?\u003C/p>\u003Cp>Those are the, you know,\u003C/p>\u003Cp>Speaker 1: the The the simple somebody in the the chat called it the simple\u003C/p>\u003Cp>Speaker 2: stuff. Yeah. If I'm dealing with relational, you know, now you're dealing with complex, you know, you're you're just as easily popping into the item at that point to edit a relational setup potentially. Now down the line, that could change, but I think the most common things, you know, based on the ticket that we got inbound was around I just wanna be able to update some numbers, and I'll be able to quickly go through and adjust some numbers. I wanna adjust some text, and it's not a bulk edit because I'm not making them all the same, but I wanna be able to quickly edit things in line.\u003C/p>\u003Cp>Relational's I don't know. My brain my brain, I can see the nicety of it to be able to quickly just pop an interface and make a change without having to open the entire work, you know, in and out of a record to do that, but I think short term initial implementation. But if we added a toggle here or a function that says, you know, disable the display, if you go to inline, then you get the interface, and that is the display.\u003C/p>\u003Cp>Speaker 1: Woah. Say say that again. So That last part,\u003C/p>\u003Cp>Speaker 2: if you\u003C/p>\u003Cp>Speaker 1: have a display but you use an interface and you toggle it, you now have a display. You lost me in that last part.\u003C/p>\u003Cp>Speaker 2: No. No. So I'm saying that if we add a new if we add the feature for inline on the interface so if specific interface designed to support inline, and you just say, I wanna use the inline or I don't know where we would set that.\u003C/p>\u003Cp>Speaker 1: I think it's set up based on the type. Yeah. Yeah. Yeah. Yeah.\u003C/p>\u003Cp>Yeah. I think somebody in the chat mentioned that it's too. It might have been the derp. Yeah.\u003C/p>\u003Cp>Speaker 2: It gives you the, you know, if I make c one in here, it overrides display. Right? Display is essentially either disabled, right, becomes grayed out here, or it's just ignored, and with a note here that says if I check-in line, then boom display is no longer utilized. We're gonna utilize the interface spec for that.\u003C/p>\u003Cp>Speaker 1: So so, you know, in the chat, mentioned a similar idea in that we could also have and this is a direct quote. We could also have multiple optional components for a single interface, like an inline version and a block version of the same interface. And then when the inline interface version exists, that can be used instead of the display, and then gray out the display to you your point.\u003C/p>\u003Cp>Speaker 0: Yeah.\u003C/p>\u003Cp>Speaker 1: Because the,\u003C/p>\u003Cp>Speaker 2: this gets ignored. As long as there's a note or a warning, you know, even if someone does set it here, it's just ignored. If in line is enabled here, then it just gets ignored.\u003C/p>\u003Cp>Speaker 1: Because the reason to then ignore the displays is because you kinda want the display itself to be editable at all times at that point. Like a checkbox, interface in the an inline checkbox interface would just be a toggle that's always active for you to click on. Because the comment that was just made in the chat too is like, you say you're loading a nested relational simple column in a table. You need simple editing. But in terms of toggling, you know, you can use the display by default.\u003C/p>\u003Cp>And then when you turn on an edit mode, maybe all of those in line ones are displayed so you still have displays. It gets tricky. So so the reason I'm saying that is we have things like the, formatted value display which is basically, a very configurable string. Right? You can make it bold, italic.\u003C/p>\u003Cp>You can make it, a different font if you wanted to. If you wanna go crazy with themes, you can make it Comic Sans. Would would highly recommend doing that. Ben's gonna kill me. Then, so those displays are and and you can have a text prefix.\u003C/p>\u003Cp>Right? That's where it gets a little tricky. So the display can show additional data that's not the, like, present in the value. So if we wanted to keep that level of flexibility, like, a rating display being stars. If you have an inline number input, now you kinda kill the usefulness of this rating display.\u003C/p>\u003Cp>Speaker 0: Yeah. The the drawing drawing the line, what is considered simple, is also very hard. Like, for me, for example, like, a many to one relation, for example, I mean, that's basically a drop down. No. A drop down doesn't seem to me to be, like, a complicated change, so to speak, like, a complex update.\u003C/p>\u003Cp>Yeah. But from a user standpoint, not from the implementation detail standpoint, but from a, like, oh, I just want to change the user. That's like one, you know, one click, select the user, select another user, be done. That seems like a simple thing, technically, you know, but it's still a relational change.\u003C/p>\u003Cp>Speaker 1: Yeah.\u003C/p>\u003Cp>Speaker 0: Wait. What did the doer say?\u003C/p>\u003Cp>Speaker 1: I mean, it's you kinda wanna what they're saying is you want the way that you're editing the value to to look the same after you're done editing it. So if you're looking at I think the obvious ones are, the toggle again. You wanna click it and you just edit it in the way it's presented. If you have a rating display, you wanna just click on the number of stars and that's the way you edit the value that you're seeing. When it comes to, like, a related values thing where it shows x number of items, it gets a little finicky.\u003C/p>\u003Cp>Right? If you're talking about the formatted value display where you might have, you know, a dollar sign prefix or something, Now it also gets tricky because now the moment you edit the value, it shows something completely different than you have displayed. Right? I think with dates, there's a different expectation, but if you think about the raw value underneath, it's just a string. It's an ISO 8601 string.\u003C/p>\u003Cp>So if you were to click a nicely formatted in your local language date, and you click it, and now all of a sudden it turns into a technical string, that'd be a bad experience. Right? Even though you could inline edit it as a string, which is not probably not what you want.\u003C/p>\u003Cp>Speaker 0: But what's also funny about like the ISO strings is that, you know, often are like, usually they're stored in like UTC universal time. So, like, people Right.\u003C/p>\u003Cp>Speaker 2: Yeah.\u003C/p>\u003Cp>Speaker 0: In other time zones, might not even know what to actually put in there because, you know, they want to select, alright. This should happen every day at, you know, 8 in the morning or something like some some whatever date. And, then all all of a sudden, the UTC time is completely different. And then you're like, oh, no. This this field's not good.\u003C/p>\u003Cp>What is it? I don't know. And again, yeah, it it really depends on the time zone of the server itself of your database or whatever. And then\u003C/p>\u003Cp>Speaker 1: I mean, at that point, it's it's game over. You really need to have some sort of proper data interface that handles that under the hood and then those presentational side of it. There is this is this is where the discussion is is interesting to me though, because it's like we're basically saying, do we have a small interface or do we have an editable display? And what's the difference? Right?\u003C/p>\u003Cp>Because when it comes to the date the date time specifically, the the basic of the date display is that it basically just takes the raw value and then shows it in whatever is appropriate for your locale. Right? So in the USA, it does the, objectively ridiculous thing. And I moved here by choice, mind you, of month slash day slash year. Right?\u003C/p>\u003Cp>And then elsewhere, it'll just do the proper thing of day, month, year.\u003C/p>\u003Cp>Speaker 0: Right? Shot's fired.\u003C/p>\u003Cp>Speaker 1: But I can imagine that if you have an inline editable date interface, you can just, you know, just like the system native one, basically, you can click on any of those parts and just type in what you want. Right? It doesn't have to be a whole selection, UI, and all that kind of stuff. So sorry for air format.\u003C/p>\u003Cp>Speaker 0: Yeah. The the American people go to great, great, great lengths to not actually use some type of normal measurement. Like, how long is something? Yeah. I don't know.\u003C/p>\u003Cp>2 2 and a half elbows or something. That's something how high how high is this building? I don't know. It's at 20 1,000 feet. I don't know how big is a feet.\u003C/p>\u003Cp>Speaker 1: What? Oh, man. This derails very quickly though. Next session, we'll spend, it's a full hour on the Imperial system.\u003C/p>\u003Cp>Speaker 0: Oh, no. Somebody's actually this relates to the discussion. Yeah. Great. Okay.\u003C/p>\u003Cp>Sure. Sure.\u003C/p>\u003Cp>Speaker 1: Okay. Yeah. Yeah. Yeah. Yeah.\u003C/p>\u003Cp>This yeah. At least take a bit of context.\u003C/p>\u003Cp>Speaker 2: Everything should be millimeters. He's Google. The Australians got it right there.\u003C/p>\u003Cp>Speaker 1: There there's a good point in the chat though. Let's say you're storing a height value in millimeters or centimeters or meters or something, but then you wanna display it with a display, you know, in feet or inches or that kind of stuff. If you then inline edit it, what are you now inline editing? Because if it would be an interface where you're doing the value, you're now editing, I suppose, the millimeters, but you're showing it as foot. You know what I mean?\u003C/p>\u003Cp>Or as as inches.\u003C/p>\u003Cp>Speaker 2: Oh, don't do it. Don't do it. Just do millimeters.\u003C/p>\u003Cp>Speaker 1: Well, yeah, that's not always appropriate.\u003C/p>\u003Cp>Speaker 2: We're we're not that dumb. We we figure it out. Mhmm. We're we're slowly being converted to metric by the by the global corporate infrastructure. We're getting there.\u003C/p>\u003Cp>I actually flip all my stuff. I use Metrc on everything now.\u003C/p>\u003Cp>Speaker 0: Good boy. Good boy.\u003C/p>\u003Cp>Speaker 1: From FCW comes in with the question, you know, what if we click on a cell, which is one of the displays, and then the field whatever that field's interface appears, just like it does in the form, and I could pop over and it will be prefocused or something. That is very close to basically where we started the discussion. So I'm glad that we're coming full circle, in in converging it back down. Because that would be, in terms of implementation, by far the simplest way for us to build this. Right?\u003C/p>\u003Cp>It's like, don't care about any of this stuff. You click it, you open a little pop over and then you change it and it's done. I also like simple things.\u003C/p>\u003Cp>Speaker 2: Drop down, you get your whatever.\u003C/p>\u003Cp>Speaker 1: You get effectively everything. Now there is. One major downside with that, that we've sort of hinted at, but not explicitly called out like this, Which is I believe that there's a lot of data types where you wanna edit it truly inline and not in a popover. So you have a checkbox, if you click it, you wanna have it change. You don't wanna have it open a popover with an inline toggle that you then click to change the other thing.\u003C/p>\u003Cp>I think when you have a small, text input Drop downs.\u003C/p>\u003Cp>Speaker 2: Drop downs, same thing.\u003C/p>\u003Cp>Speaker 1: Change the change the drop downs, same thing. Right? Both data entry gets frustrating in that model and I would agree. Like, I think for a drop down, you just wanna click it. It needs to show the drop down section.\u003C/p>\u003Cp>It'd be a bit of an annoying UX if it then opens a pop over with the same dropdown again that you then click to to have a nested popover down, I guess, which would also be a bit annoying.\u003C/p>\u003Cp>Speaker 2: Very much agreed.\u003C/p>\u003Cp>Speaker 1: I do think that for me, one of the requirements from a UX design perspective is that we have some sort of truly in line flavor for some of those, and then use the pop over for the interfaces where it doesn't make sense. Right?\u003C/p>\u003Cp>Speaker 2: I like it.\u003C/p>\u003Cp>Speaker 1: Picky stuff. But it's it's also hard to it's also difficult to decide which ones make sense and which ones don't. Because I'm thinking about our color display, which is just a tiny dot in its smallest form. If you click that, do we really have to show the full color interface? Because again, it's more like a a select.\u003C/p>\u003Cp>Right? It's more like a drop down. You could just click the tiny preview and then edit the drop down items directly. But how do we how do you control that, right? Which is, I think, what we're getting at is sort of the suggestion from the DIRF earlier, which kinda says, it's up to the interface to communicate somehow whether or not it is, inline editable.\u003C/p>\u003Cp>Yeah. So I think this is a good example, John. Jonathan. Exactly. It's like this whole drop down, we could just render that the moment you click on the little preview in line, right?\u003C/p>\u003Cp>It doesn't have to have this whole interface again because the only real thing that you care about for the interface is the part in the drop down, right? So from the chat, if interfaces have an inline variant those could be used inline and then fall back to popover if the interface doesn't have an inline variant. I think that is basically what I'm suggesting then. Yeah. Because then for the color in line variant, it can just render it, you know, nice and in line.\u003C/p>\u003Cp>For, a one to many interface where we know it's like there's there's no way to do the whole UI in a table row, it would use a pop over and just render whatever needs in there. I don't know though if interfaces should always have an inline variant, and it is then in charge of what goes in the popover because I can also imagine that the UX of how you wanna deal with an interface itself within the constraints of a pop over smaller window can be different. So if you think about the pagination for a one to many, for example, if you have that configured to, paginate at 50 and the individual rows of a once many are pretty big. You know, they're the regular size of an interface or, input height is what we call it. For a consistent view on the form, it looks nice.\u003C/p>\u003Cp>But if you cram that into a small popover, there's gonna be a lot of overflow scrolling now in that tiny little, in that tiny little pop over. We could go full modal. This is from the chat. Let me mind you. We could go full modal and make people suffer, which we could, but I I kinda to me, it's no longer in line editing then.\u003C/p>\u003Cp>Right? You just have a short cord to open a single field. But I could imagine that yeah. John, thanks for pulling this up. Like that left column section you're seeing there.\u003C/p>\u003Cp>I could imagine that the interface itself has an alternative rendering mode where it can just compress it down a hell of a lot more to be a better experience in a sort of pop over context. Popovers on mobile would be particularly a pain in the neck. Another one from the chat. Yeah. Yeah.\u003C/p>\u003Cp>Absolutely true. Which, in that case, you know, there is the opportunity to say for mobile, if we're rendering a popover, we're just rendering it as a dialogue or it might take over the full screen. There there's ways to responsibly handle that responsibly, responsibly.\u003C/p>\u003Cp>Speaker 0: Okay. So just looking at the time, real quick since we are approaching the hour mark. I think yeah. But I I think we landed on a quite the nice, let's say, idea on how to tackle this because, you know, nothing is, you know, struck in stone, but I I do think I do think I like the approach of, you know, you can have interfaces, you can have displays, and you can have inline interfaces, which sounds very reasonable to me. But then, like you said, alright.\u003C/p>\u003Cp>Where do we control what pops in, what doesn't pop in?\u003C/p>\u003Cp>Speaker 1: And I think it will have to be the interface, honestly. Because I could, an input interface, it knows that it could be handled in line. There's no way real way for us to to see that from the outside in. Right? I mean, we could always have, like, a lookup table somewhere, but it would only work for the stuff we the stuff we ship in core, not for extensions, which is a big part of this, of course.\u003C/p>\u003Cp>I I I think that the the question that I'm struggling with now is really what is the difference displays and interfaces in this paradigm. Right? Because now we're rendering interfaces in the place of a display, sometimes. And I'm I'm now just starting to think with this whole in line editing idea, maybe a display is just a read only inline version of the interface. It it does remove that flexibility that we talked about earlier where you could have a different display value for a input value.\u003C/p>\u003Cp>But to me, it would sort of solve for some of the complexity in configuration and some of these questions that when is it when is it a display? When is it an inline interface? How do you control between the 2? How do you toggle? Etcetera etcetera.\u003C/p>\u003Cp>Because that way we could say, well, in every interface needs an inline and a block version. The block version is what we use on forms and bigger pages. The inline version is what we use in title cards and table rows and that kinda stuff. And then it is read only or it's not. Like we currently already have.\u003C/p>\u003Cp>You know, we have read only forms, for permissions and all that kind of stuff. And a display is effectively just a read only inline version of the interface. And then if you have the editable table layout which is just a toggle. Maybe it's always on tbd. The inline version of the interface now controls if it's a pop over or not.\u003C/p>\u003Cp>So the inline version of a die, of a checkbox. Just click it. It immediately interactive. In line version of a text input. Click it.\u003C/p>\u003Cp>You can type in line version of a relational, one to many or something. By default, it'll just show 6 items. But then when you click it, the popover has the actual editable part. Right? But I think it could be the same the same interface.\u003C/p>\u003Cp>It's all interfaces at that point.\u003C/p>\u003Cp>Speaker 0: Interface is all the way down.\u003C/p>\u003Cp>Speaker 1: I mean, it would reduce it. So so one of the other parts is, like, there is a bit of confusion around the difference between interface and display. And I feel like a lot of people configure an interface by setting up a new field and then don't know that displays even exist. Cause if you configure a new field, it's very easy to skip over it and never know it's there. Right?\u003C/p>\u003Cp>So I also think there is a case to be made that it would improve the experience for a lot of the people that normally don't, really take the time to go over every single option that exists because it can be a bit overwhelming, you know, arguably. There's a lot of stuff you can configure.\u003C/p>\u003Cp>Speaker 0: That sounds good to me.\u003C/p>\u003Cp>Speaker 1: It'd be a gigantic rate and change, so don't worry about that.\u003C/p>\u003Cp>Speaker 0: This is not something we can just\u003C/p>\u003Cp>Speaker 1: in a little 10.1. Here you go. Bang.\u003C/p>\u003Cp>Speaker 0: Looks good to me. Ship it.\u003C/p>\u003Cp>Speaker 1: But I I think to me, that would sort of solve it because then for the table layout, you can have a toggle somewhere that says make it editable. Yes or no. For and for any of the layouts, really. For the tabular layout, we can make it editable by default. For the cards layout, we could say it's probably not a good idea to do it for some but for others because now the layout's in control.\u003C/p>\u003Cp>I think there's there's something to it.\u003C/p>\u003Cp>Speaker 2: Very cool stuff.\u003C/p>\u003Cp>Speaker 0: Good stuff, guys. Any last questions from the, audience? Your chance is now.\u003C/p>\u003Cp>Speaker 1: Forever hold your peace. Winston.\u003C/p>\u003Cp>Speaker 2: Final cue.\u003C/p>\u003Cp>Speaker 0: Forever hold your peace.\u003C/p>\u003Cp>Speaker 2: If you're if you're still awake.\u003C/p>\u003Cp>Speaker 1: Yeah.\u003C/p>\u003Cp>Speaker 2: Oh, let's see. Vincent.\u003C/p>\u003Cp>Speaker 0: Someone type it. Well, then, thank you everybody.\u003C/p>\u003Cp>Speaker 1: Thank you. Bored everybody to death.\u003C/p>\u003Cp>Speaker 2: We've hard hard boiled a few eggs.\u003C/p>\u003Cp>Speaker 0: Lovely. Thanks for tuning in. In case you enjoyed this, there's much more of this on directors.io/tv. If you want to go there, there's lots and lots of interesting shows for you. Lots of good, great entertainment.\u003C/p>\u003Cp>And, feel free to join us next time for another very interesting topic. Thank you for linking the show, Kevin. Oh, yeah. Fire emojis. Yes.\u003C/p>\u003Cp>Very good. Thank you everyone for tuning in. We hope you have a\u003C/p>\u003Cp>Speaker 2: great day. Enjoy your week, folks. Have a good night. Good\u003C/p>\u003Cp>Speaker 0: night. Strong feelings, please let us know. The discussion is open. The issues are open.\u003C/p>\u003Cp>Speaker 1: That way.\u003C/p>","Hello, everybody. Welcome to feature request review with me as a host today, joined by the good old Reich, Van Zanten himself and Jonathan Wagner. Hello. Hello, everybody. Thank you for coming. Very exciting to see you all. Quite quite the quite the collection of people we have here from Algeria, Japan, everywhere. Germany, Austria. No. No. No. I nearly said it. But, yeah, today today, everybody's, apparently favorite topic because there's so much demand here in the channel right now. Inline editing, which can mean a lot of things. So let's just take a look at what a small example could look like. If you take a look at the screen shared footage of Jonathan, you'll see this is our feature request that got in, which you can vote on, by the way, in case, some people are not aware of this feature in our discussions in the director's repository. You may vote on stuff that gets implemented into the software, which is pretty cool. And, today's topic is about inline editing. If we scroll up a little bit to the top to the screenshot, you might have seen this in other interfaces online, you know, when you use Notion or whatever, like, many many sites implement this a little bit differently. You know, on Trello boards, you can click into the title, then you can change the title right then and there without a pop up or something. And, yeah, why why doesn't have direct as this yet? It's a good question. I mean, there are many, many different things that we could talk about. And, in case you have any questions or stuff that you want to share, please feel free to use the chat. We're excited to engage with you guys. It would be fun, a sign of life like previously. That would be nice. And how about how about we jump in right into a couple of questions? Let me quickly, give one second. Alright. So by looking at this, you know, basic example with the with the input field, I mean, the the first question to me is, alright. Like, how how much can we blow this up to, because Directus is very, very versatile, and, people build the craziest displays and interfaces and very, very customizable different pieces. How do they fit into this, and if we just target, like, simple inputs, for example, like in these simple example with, like toggles or text inputs. What about relations? Because those tend to be very nice to deal with. And, how about we go over to give over to Rijk for this one? How do you feel about different types of inputs for inline editing? Do you think we should, like, aim to be able to do everything in in in line editing? Should we reduce it down? Should we only support a sub set? How do you feel about inline editing in itself? I mean, when it comes to inline editing, I think the first question that we gotta ask ourselves and everybody watching is like, what does that even mean in the first place? Is it kinda like a spreadsheet where everything is just a cell where you can change whatever you see? Is it more like, a table view by default where everything looks pretty through those displays, And then you have some sort of edit state. Is it like, an edit state where we render a whole interface in line? Or is there some sort of dialogue overlay that we're seeing when you click on one of the cells, so to speak, to to stay in spreadsheet terms. So I think the first question really is what is what is inline editing? What does it even mean? Right? Because we do have a different feature request for a spreadsheet view, which I think very closely overlaps, but there's definitely differences. And then I think the other question, of course, I mean, relationships, we'll dive into that in 5 minutes. But, if you think about the basics, I think one of the thing that we're doing with direct is with all the interfaces is to make sure that you can edit the data in a way that makes sense for what the data is. Right? So, a very basic example, you know, a slider could be a better representation for a numeric value that you're using for whatever it is that you're building. Right? But You wanna use a slider to control the value. When it comes to inline editing, you know, if we're looking at this screenshot where the reserve column right now presumably is in this edit state, you know, if we're dealing with inline editing in its sort of truest form, does that mean that it just turns into a sort of raw value input? Or do we include interfaces kinda like we are with a regular form? Right. So when it comes to a date value to name something, the technical value is always gonna be that that what's the exact spec, the, ISO 8601. Is that the thing that you wanna be editing? I would argue, probably not. You probably wanna have, you know, the data interface that you have configured for that field, which then leads to the question, does that even fit wherever we're doing this inline editing presumably in this table layout. Right? And I think we're we're quickly reaching the question then is like, okay, do interfaces even fit? And if they don't, how do we present it otherwise? Right? Yeah. To your example, like, even even a simple slider, which is a nice way to input, like, a specific value inside of a range, which could be, you know, like, relevant to the use case, you know, where you want to restrict. You maybe you don't allow, like, negative numbers or something. But if if we allow, like, editing via raw values, then somebody might put in, you know, minus 1 or something, and then you very quickly run into the issue that you mentioned. We want to give people the tools to, like, input stuff as as as comfortably as possible with using, like, nice interfaces and displaying like, even displaying, you know, with with the value that you see inside of the table might, like, might not actually be the wrong value just like you described with the, like, date time, for example. So there's a disconnect there and, like, for, like, nontechnical users, for example. No. It could be it could feel bad, you know, from a user experience standpoint where they like if if marketing salespeople, what what was the thing that's, somebody said I won't name any names, but somebody said, like, the scariest thing that marketing people see is, like, a UUID somewhere. So we're dealing with UUIDs. Yeah. It is, is a scary endeavor, so you have to be quite careful with the display. So yeah. Yeah. Speaking to that, we have why don't we explain a little bit about the difference between our interfaces and displays? Because, you know, indirect is also 2 different things. What are those? How do I use those? What can they do? Good question. So so from I'll I'll prefixes was sort of the theoretical idea behind it while Jonathan here pulls up the actual difference and how you configure them. So the basic idea is that a display, controls how a raw value is displayed in line, importantly. So it's really meant to be part of a sentence or one of the cells in a table or, you know, part of a description or something. So if you think about a, labels display, it can be configured to render it as a small color dot with a tooltip, with the idea being you can then render that in the title of a page, or in the description of a card or inside of a table. Right? The interface is really the the way you edit the value. So if you go and you open an item, it's basically the form field, section of of how you interact with that data. So it's really the difference between sort of block level, in CSS terms, editing of the data versus inline displaying of that same data. Importantly, those 2 can be very different representations of the same data. Right? So the image display will just be a tiny thumbnail where an image interface is like a bigger box where you can drag and drop stuff in and you have, like, preview and some more metadata available. They are at present a different thing. And the display is then Yeah. So so Jonathan right now is, you know, adding, a related values you know, those displays, and compose them all together to really control how an individual item is presented. Right? So on the collection detail page 2, there is a display template setting where, again, you can render individual fields as part of one title string. And then that's how it displays the individual pieces of data. So when it comes to editing them in line, one of the interesting, challenges that we're gonna be facing when it comes to the table layout specifically is that the value that you're seeing in here, it's very likely that that's not the value that you're gonna be editing. Right? And is it a toggle? Is it something that you enable or disable? If you haven't enabled, what happens? If you don't have an enabled or how do I access the record? Because currently, you know, I just know that I can just click anywhere on the row, and it will open the item for me, and I can edit the item. How do we trigger, you know, you start to get into that. So we've got the whole interfacing aspect, relational content, allowed or not allowed. It feels like at least maybe you could almost do it in, like, an iterative. So start with the normal input fields, date fields, the the simpler interfaces and things to deal with versus relational. Relational gets complicated, right, depending on how deep or how complex that relational is. Now in order to edit this translation, well, that requires now that I get the full translational split toggle side by side translations kinds of things, and is that beneficial in this kind of a in this kind of utility? Yeah. Toggles, drop downs, you know, some of this, some of the more string text slash Is this is there there is a a another additional question when it comes to how do we then render an interface to change the data, which is that there's gonna be a couple of them where the interaction would be way nicer if it's, like, truly in line. Like, so if we, if you think about a toggle, like a checkbox. Right? Kinda like the default checkboxes for selecting items. But let's say you have, you know, an on or off state on your own custom item. In your display, ideally, I just wanna click it and it flips. I I don't wanna click it then open a dialogue that shows me just one toggle anyways, and then close it, and then change it that way. You know what I mean? And I think the same goes for basic text values or basic numbers where I just wanna be able to click the text, edit it, and then that's it. Right? I don't wanna have to deal with clicking it, seeing a popover, drop down dialog, whatever it may be, then change it there because it's just another step away for something that feels like it could have been a spreadsheet, basically. Yep. With that example, you know, with just clicking in and changing something, Tim also brought up a nice point because, with nullable values, like, even such a simple thing as a, like, togglable checkbox, if that is even a word, you know, we already run into, like, a small little, thing, like, okay, what if you want to set it to null? You know? Like, if you uncheck the thing, it's false, but you want it to be null. Do we do we, you know, do we, like, enable triple, like, stateful checkboxes that support 3 values? Do we want to have, like, a ellipse that gives you, like, a setting for that? Like, similar to our v form where, you know, you're allowed to enter a raw value, but that's another piece of UI that would have to be somewhere some at some point. Yeah. Exactly. For strings, similar in that vein, you know, for strings, do you want a, empty string, or do you want a null value? Alright? How do you differentiate between those? And it can even differ, you know, from from to Yeah. All of those are problems that we have solved in the form context. Right? Because even in the form, there's just the field label drop down that says empty this value, which is effectively nullifying it. So the question is also how much of that do we wanna pull a level up in here versus how much of that do we just say oh well if you explicitly wanna change a boolean back to a null, you can always go to the page detail thing and then do it there. Right? There is an escape hatch, and we could make the call to say, well, you know, the toggle display goes between true and false. And if you need to reset it back to that null state for whatever specific reason, you can always go to the detail page, and do it there. Right? And I think similarly for the string empty update, empty string, null, that that question is a question that we've currently solved on the interface settings, I believe. Therefore, an input interface, you can say empty string becomes null, and then that's just the value it, you know, stages, it emits. So if we go the route where we use the exact same interface you have already configured as the way to edit it in line, that problem should sort of automatically be solved. Right? Because we're using the same interface with the same settings, and then that should be fine as is. Where that part gets super interesting though, is how do we deal with conditional fields within the context of that row? So the way conditional fields currently work is, you know, you have the whole form of on the field, you have the whole form on the page, and then we can use the values of the form and sort of connect the dots. Right? And use it that way. On a row in a table though, the fields that are displayed might be completely different. The second piece to that is gonna be for conditional fields. They're now react reactive in real time where if you make a change to one field, sort of real life like, real time updates it elsewhere. When you're in the context of an individual row, and I think this is just a bigger question overall, is, like, does it auto save every time you sort of blur the input that you change something in? Or is there gonna be a save button that is like, okay. Now you've made all the changes and you hit save once. That's a very good question. Like, especially for, like, the togglable checkboxes or whatever because, like, if you just miss click somewhere and all of a sudden, that could be a big change, you know, like with flows and automations and other stuff that runs or update events, fire something. If you hit publish on something, that should be, there should be a mechanism, you know, to stop making mistakes, you know, like, accidentally, if you have, like, you know, is active or is published field on some type of blog post or whatever, and you don't want to accidentally just oops. Oops. It's live now. Oopsie. Would would be nice if we could avoid that, but, yeah, that opens up another can of worms. You know? Like, how do we do you configure this on a field level? Do you configure this on a column level, on a, preset level? Like, where where do you where would you like to do that? That's also the thing. Because very good point from the chat also from the, is currently, for example, the displays do not know, like, which item they belong to. They are very stupid in that way with quotation marks where they just Yeah. Display a value. This is why they're called displays. It's it's a presentation, presentation layer. Yeah. Yeah. Yeah. So if if we would like to have the, you know, like, mutable, displays or whatever, you know, if we decide to go that down that road. So, we would have to provide the displays with the item ID in the collection, like, in every place because there's not not only displays only in the table view, in the tabular layout, but also in, like, titles and drop downs or whatever. Like, any and they could be at any place at any time, which makes this a little bit, dangerously spaghettty like, which which which also, kind of bleeds into a similar yet different question, which is where do we allow inline editing in the first place? Because we're assuming we're sort of assuming the table layout right now because that's the most commonly seen elsewhere. I mean, I'm I'm sure that people that have ever seen Airtable are like, that's that's the way. But at the same time, the the question is, do we inline edit elsewhere? Like, if you have a status icon in your page title, does that become an inline editable thing? Right? In the chat somebody says we'd appreciate it for the card layout, maybe even the calendar. I would agree. So on the card layout, if you have in your description of an individual card, you have a a text display. If you click the description, can you now edit the description of a card in line, which opens up a big can of worms, especially from a UX design perspective. I I guess because because we're we're concatenating that into a string in the display right now for a card. Right? Mhmm. Mhmm. So if we're just The same for page titles for the for for that matter or the calendar layout. Yeah. Yeah. And Tim, Tim, another fun, fun little thing that could happen if you're already editing something and you have auto refresh enabled. Somebody updated your stuff in between the edits, and now you have another edge case. Love it. Love it. Love it. Love it. Which is gonna be the same issue that you have with, you know, the regular form. So I'm hopeful that whatever solution we come up with that right now. Yeah. Exactly. Whatever solution we come up with for that, I'm sure the same solution should also then work here. But Yeah. For this So this is a good example in the cars layout. Right? So in that right side bar, you see title, subtitle, and you can configure any combination of the different fields with any sort of additional strings in between, for like adding a dollar sign in front of price. That kind of stuff. Right? So in this particular case, it becomes extra interesting. Because if you now were to click on the number of the price in that description line, do you expect it to be editable? Right? And how do you determine that? Yes or no? Because making every editable globally at all times feels like a UX nightmare waiting to happen, but it also unlocks a lot of flexibility. Right? So it's a tricky one as many things are. Of course. So how about how about then we take a different look? So now we thought about tables and the current layout and whatever. Technically, there's also another option of adding a new layout, like you mentioned earlier, with the spreadsheet layout, which could be the point where you do that type of stuff. I don't know. Maybe, you know, I'm just, you know, throwing stuff in the room right now just to discuss a little bit. But Yeah. Because it does have the mute display thing. Yeah. Yeah. Yeah. So maybe if it turns out to be better or easier or whatever, the spreadsheet layout could be an interesting point where we could tackle this, but, then we have new, cans of worms and cans and of worms stacked upon each other, you know, till this evening. Stack a can. Which which is fun. Yeah. Because, you know, a spreadsheet layout people come into a spreadsheet layout with lots of preconceived notions. Is that the is that the word? And Like, I think expectations is the word I would say. Yeah. Expectations. Yeah. Yeah. Yeah. Yeah. Expectations and and stuff that they would like to have or that they expect to be there because it's, you know, spreadsheets are, daily used by billions of people. So they do want to have, like, conventions and keyboard navigation and different stuff that they already, you know, introduced to the day to day life with bulk renaming, whatever formulas. Maybe they think that this is then an actual spreadsheet that they can do calculations in, which is another cool feature that we would like to have probably from different feature requests for a different day. Yeah. Exactly. Exactly. Exactly. So spreadsheet seems to be a very big thing, for me personally. Yeah. I think to me it's just a very different thing, isn't it, than than this inline editing approach that we're talking about? Because I fully agree with what you're saying. If you close your eyes and you think spreadsheet, there's a whole set of rules that come with that. That if you miss one of them, you have a bad spreadsheet. Right? Because if you look at Excel versus Google Sheets versus Excel on the web or even Apple's, what they call it, numbers, they are all effectively identical in the exact same settings, exact same thing you can do. It's a right or wrong approach. So, funnily enough, for a session like this, it would be a very short call because it's like spreadsheet. It's basically a known entity at that point. Right? I think where it gets interesting to me, and this is sort of the the the Airtable spreadsheet equivalent. It's like, you're not dealing with the spreadsheets. You're dealing with a table that you can edit in line. But it's not a pure spreadsheet in the technical term, right, where you're dealing with cells with raw values, so to speak, rather than UI elements where you edit the values. Yeah. Same thing in the chat was was coined there. The reason why I immediately started thinking about okay. So our display is now editable as a concept is basically from that modular fashion. Right? Because making one new layout that does inline editing sure. We could totally make that happen. We could also make it an option of the regular table layout and then that's it. Right? To me the interesting question for this is really like, is there a way to make it work for any display anywhere? And is that something that we wanna do or not? Because by doing so, you get the tabular layout feature out of the box but you also unlock it elsewhere. Like, if you have, a list of one to many items on, a record, each of those one to many items now also has inline editing because they are using displays to render those values. Right? So it it just, like, it transforms this discussion from an inline table editor to a bigger sort of, like, what does that editing in situ look like across the board? Very, very good question. I wish I would have the answer to it, but, yeah, like you said, I mean, for for for example, for the, like, relational stuff, I could see, you know, reusing the existing drawer that pops up in different places, which could be a nice experience. You know, if you let's say you have a, a website collection with blog posts or something, articles, whatever. And as the drawer opens and you can use the currently already existing, like, relations go through the list, it it's it's with pagination and stuff. That could be nice. But like you said earlier, if for smaller fields, it feels like add UX if you, you know, just want to change one text and then the drawer opens or, like, a pop up opens with just one input. That's, like, at that point, it just feels very not thought through, which I would like to avoid. Yeah. We got correlate with this PR. Yeah. Yeah. Yeah. The the batch editing is also a nice thing. So slightly different. There's also the the, the bigger question here, Which is As it always is? As it always is. But it's that's that's what these sessions are. For those who are new, in these sessions, we always go find all of the edges and then take it back into what is actually realistic in the next step. But so think about it. If if we're now dealing so so you we explained it before that the displays were meant as a presentational only unit and interfaces are meant as an editable unit of the same value. Right? But now we're saying: What if displays are editable, but only at sometimes? So some displays like a string we wanna make inline editable, Some displays like a checkbox inline editable. And some like a relational related values or something we wanna have a click with some sort of dialogue to to have the space to make it a proper editing experience. Right? The question could also be, should those still be 2 separate entities or should they all be interfaces? And based on how we where we're rendering an interface, it can display in different ways. Right? So if you have an interface on a form where it has enough space to grow, it can show as a proper big input. But if you try to squash it into a cell of a table, it just drops the visual representation of an input and becomes one of those underline only in inputs for example. Right? Because then with a read only prop, yes or no, you can toggle between a string that's just rendered as a string. Or when you click it, it switches into this inline interface version, basically. Know what I mean? Because then for a display one, it can always just be interactive for an input, you can just click to start typing for, a related values one or a relation when you can click it and it would just do it in a pop over or dialogue or something along those lines. So depending on the interface type or the interface implementation, you could allow or disallow inline editing ongoing. Right? Right. It it would basically mean that the interface is always the thing that controls how it's displayed, because therefore you can have the interface control how that interactivity works in that display context. Now, that does, of course, come with the the side effect that you can no longer have a different display per interface like we currently allow. So theoretically, you could use, you know, a text input interface, and then an icon display if you wanted to. Or, you know, you can have a rating input that is a slider and then a display that's that's rendered as stars. I don't have the stats on how popular that is. Like, that would be a breaking change where we remove that. At the same time it also makes it easier to configure. Right? Because you can have, okay, I'm using the icon this, icon interface, and at smaller scales, it turns into an icon display. Right? So I guess another option could be that if you toggle the, you know, inline capability here, then the display gets turned off. Right? You don't have display capability. So you don't have a breaking change, you have the ability to come in and edit an existing interface, keep the existing display capabilities where I don't know what the overhead looks like for that, but something that we could think about instead of just outright ripping this out because I I still think, again, this is gonna be, I think, the most common case where I would want the ability to do, like, inline editing is on strings and numbers and dates. Right? Those are the, you know, the The the simple somebody in the the chat called it the simple stuff. Yeah. If I'm dealing with relational, you know, now you're dealing with complex, you know, you're you're just as easily popping into the item at that point to edit a relational setup potentially. Now down the line, that could change, but I think the most common things, you know, based on the ticket that we got inbound was around I just wanna be able to update some numbers, and I'll be able to quickly go through and adjust some numbers. I wanna adjust some text, and it's not a bulk edit because I'm not making them all the same, but I wanna be able to quickly edit things in line. Relational's I don't know. My brain my brain, I can see the nicety of it to be able to quickly just pop an interface and make a change without having to open the entire work, you know, in and out of a record to do that, but I think short term initial implementation. But if we added a toggle here or a function that says, you know, disable the display, if you go to inline, then you get the interface, and that is the display. Woah. Say say that again. So That last part, if you have a display but you use an interface and you toggle it, you now have a display. You lost me in that last part. No. No. So I'm saying that if we add a new if we add the feature for inline on the interface so if specific interface designed to support inline, and you just say, I wanna use the inline or I don't know where we would set that. I think it's set up based on the type. Yeah. Yeah. Yeah. Yeah. Yeah. I think somebody in the chat mentioned that it's too. It might have been the derp. Yeah. It gives you the, you know, if I make c one in here, it overrides display. Right? Display is essentially either disabled, right, becomes grayed out here, or it's just ignored, and with a note here that says if I check-in line, then boom display is no longer utilized. We're gonna utilize the interface spec for that. So so, you know, in the chat, mentioned a similar idea in that we could also have and this is a direct quote. We could also have multiple optional components for a single interface, like an inline version and a block version of the same interface. And then when the inline interface version exists, that can be used instead of the display, and then gray out the display to you your point. Yeah. Because the, this gets ignored. As long as there's a note or a warning, you know, even if someone does set it here, it's just ignored. If in line is enabled here, then it just gets ignored. Because the reason to then ignore the displays is because you kinda want the display itself to be editable at all times at that point. Like a checkbox, interface in the an inline checkbox interface would just be a toggle that's always active for you to click on. Because the comment that was just made in the chat too is like, you say you're loading a nested relational simple column in a table. You need simple editing. But in terms of toggling, you know, you can use the display by default. And then when you turn on an edit mode, maybe all of those in line ones are displayed so you still have displays. It gets tricky. So so the reason I'm saying that is we have things like the, formatted value display which is basically, a very configurable string. Right? You can make it bold, italic. You can make it, a different font if you wanted to. If you wanna go crazy with themes, you can make it Comic Sans. Would would highly recommend doing that. Ben's gonna kill me. Then, so those displays are and and you can have a text prefix. Right? That's where it gets a little tricky. So the display can show additional data that's not the, like, present in the value. So if we wanted to keep that level of flexibility, like, a rating display being stars. If you have an inline number input, now you kinda kill the usefulness of this rating display. Yeah. The the drawing drawing the line, what is considered simple, is also very hard. Like, for me, for example, like, a many to one relation, for example, I mean, that's basically a drop down. No. A drop down doesn't seem to me to be, like, a complicated change, so to speak, like, a complex update. Yeah. But from a user standpoint, not from the implementation detail standpoint, but from a, like, oh, I just want to change the user. That's like one, you know, one click, select the user, select another user, be done. That seems like a simple thing, technically, you know, but it's still a relational change. Yeah. Wait. What did the doer say? I mean, it's you kinda wanna what they're saying is you want the way that you're editing the value to to look the same after you're done editing it. So if you're looking at I think the obvious ones are, the toggle again. You wanna click it and you just edit it in the way it's presented. If you have a rating display, you wanna just click on the number of stars and that's the way you edit the value that you're seeing. When it comes to, like, a related values thing where it shows x number of items, it gets a little finicky. Right? If you're talking about the formatted value display where you might have, you know, a dollar sign prefix or something, Now it also gets tricky because now the moment you edit the value, it shows something completely different than you have displayed. Right? I think with dates, there's a different expectation, but if you think about the raw value underneath, it's just a string. It's an ISO 8601 string. So if you were to click a nicely formatted in your local language date, and you click it, and now all of a sudden it turns into a technical string, that'd be a bad experience. Right? Even though you could inline edit it as a string, which is not probably not what you want. But what's also funny about like the ISO strings is that, you know, often are like, usually they're stored in like UTC universal time. So, like, people Right. Yeah. In other time zones, might not even know what to actually put in there because, you know, they want to select, alright. This should happen every day at, you know, 8 in the morning or something like some some whatever date. And, then all all of a sudden, the UTC time is completely different. And then you're like, oh, no. This this field's not good. What is it? I don't know. And again, yeah, it it really depends on the time zone of the server itself of your database or whatever. And then I mean, at that point, it's it's game over. You really need to have some sort of proper data interface that handles that under the hood and then those presentational side of it. There is this is this is where the discussion is is interesting to me though, because it's like we're basically saying, do we have a small interface or do we have an editable display? And what's the difference? Right? Because when it comes to the date the date time specifically, the the basic of the date display is that it basically just takes the raw value and then shows it in whatever is appropriate for your locale. Right? So in the USA, it does the, objectively ridiculous thing. And I moved here by choice, mind you, of month slash day slash year. Right? And then elsewhere, it'll just do the proper thing of day, month, year. Right? Shot's fired. But I can imagine that if you have an inline editable date interface, you can just, you know, just like the system native one, basically, you can click on any of those parts and just type in what you want. Right? It doesn't have to be a whole selection, UI, and all that kind of stuff. So sorry for air format. Yeah. The the American people go to great, great, great lengths to not actually use some type of normal measurement. Like, how long is something? Yeah. I don't know. 2 2 and a half elbows or something. That's something how high how high is this building? I don't know. It's at 20 1,000 feet. I don't know how big is a feet. What? Oh, man. This derails very quickly though. Next session, we'll spend, it's a full hour on the Imperial system. Oh, no. Somebody's actually this relates to the discussion. Yeah. Great. Okay. Sure. Sure. Okay. Yeah. Yeah. Yeah. Yeah. This yeah. At least take a bit of context. Everything should be millimeters. He's Google. The Australians got it right there. There there's a good point in the chat though. Let's say you're storing a height value in millimeters or centimeters or meters or something, but then you wanna display it with a display, you know, in feet or inches or that kind of stuff. If you then inline edit it, what are you now inline editing? Because if it would be an interface where you're doing the value, you're now editing, I suppose, the millimeters, but you're showing it as foot. You know what I mean? Or as as inches. Oh, don't do it. Don't do it. Just do millimeters. Well, yeah, that's not always appropriate. We're we're not that dumb. We we figure it out. Mhmm. We're we're slowly being converted to metric by the by the global corporate infrastructure. We're getting there. I actually flip all my stuff. I use Metrc on everything now. Good boy. Good boy. From FCW comes in with the question, you know, what if we click on a cell, which is one of the displays, and then the field whatever that field's interface appears, just like it does in the form, and I could pop over and it will be prefocused or something. That is very close to basically where we started the discussion. So I'm glad that we're coming full circle, in in converging it back down. Because that would be, in terms of implementation, by far the simplest way for us to build this. Right? It's like, don't care about any of this stuff. You click it, you open a little pop over and then you change it and it's done. I also like simple things. Drop down, you get your whatever. You get effectively everything. Now there is. One major downside with that, that we've sort of hinted at, but not explicitly called out like this, Which is I believe that there's a lot of data types where you wanna edit it truly inline and not in a popover. So you have a checkbox, if you click it, you wanna have it change. You don't wanna have it open a popover with an inline toggle that you then click to change the other thing. I think when you have a small, text input Drop downs. Drop downs, same thing. Change the change the drop downs, same thing. Right? Both data entry gets frustrating in that model and I would agree. Like, I think for a drop down, you just wanna click it. It needs to show the drop down section. It'd be a bit of an annoying UX if it then opens a pop over with the same dropdown again that you then click to to have a nested popover down, I guess, which would also be a bit annoying. Very much agreed. I do think that for me, one of the requirements from a UX design perspective is that we have some sort of truly in line flavor for some of those, and then use the pop over for the interfaces where it doesn't make sense. Right? I like it. Picky stuff. But it's it's also hard to it's also difficult to decide which ones make sense and which ones don't. Because I'm thinking about our color display, which is just a tiny dot in its smallest form. If you click that, do we really have to show the full color interface? Because again, it's more like a a select. Right? It's more like a drop down. You could just click the tiny preview and then edit the drop down items directly. But how do we how do you control that, right? Which is, I think, what we're getting at is sort of the suggestion from the DIRF earlier, which kinda says, it's up to the interface to communicate somehow whether or not it is, inline editable. Yeah. So I think this is a good example, John. Jonathan. Exactly. It's like this whole drop down, we could just render that the moment you click on the little preview in line, right? It doesn't have to have this whole interface again because the only real thing that you care about for the interface is the part in the drop down, right? So from the chat, if interfaces have an inline variant those could be used inline and then fall back to popover if the interface doesn't have an inline variant. I think that is basically what I'm suggesting then. Yeah. Because then for the color in line variant, it can just render it, you know, nice and in line. For, a one to many interface where we know it's like there's there's no way to do the whole UI in a table row, it would use a pop over and just render whatever needs in there. I don't know though if interfaces should always have an inline variant, and it is then in charge of what goes in the popover because I can also imagine that the UX of how you wanna deal with an interface itself within the constraints of a pop over smaller window can be different. So if you think about the pagination for a one to many, for example, if you have that configured to, paginate at 50 and the individual rows of a once many are pretty big. You know, they're the regular size of an interface or, input height is what we call it. For a consistent view on the form, it looks nice. But if you cram that into a small popover, there's gonna be a lot of overflow scrolling now in that tiny little, in that tiny little pop over. We could go full modal. This is from the chat. Let me mind you. We could go full modal and make people suffer, which we could, but I I kinda to me, it's no longer in line editing then. Right? You just have a short cord to open a single field. But I could imagine that yeah. John, thanks for pulling this up. Like that left column section you're seeing there. I could imagine that the interface itself has an alternative rendering mode where it can just compress it down a hell of a lot more to be a better experience in a sort of pop over context. Popovers on mobile would be particularly a pain in the neck. Another one from the chat. Yeah. Yeah. Absolutely true. Which, in that case, you know, there is the opportunity to say for mobile, if we're rendering a popover, we're just rendering it as a dialogue or it might take over the full screen. There there's ways to responsibly handle that responsibly, responsibly. Okay. So just looking at the time, real quick since we are approaching the hour mark. I think yeah. But I I think we landed on a quite the nice, let's say, idea on how to tackle this because, you know, nothing is, you know, struck in stone, but I I do think I do think I like the approach of, you know, you can have interfaces, you can have displays, and you can have inline interfaces, which sounds very reasonable to me. But then, like you said, alright. Where do we control what pops in, what doesn't pop in? And I think it will have to be the interface, honestly. Because I could, an input interface, it knows that it could be handled in line. There's no way real way for us to to see that from the outside in. Right? I mean, we could always have, like, a lookup table somewhere, but it would only work for the stuff we the stuff we ship in core, not for extensions, which is a big part of this, of course. I I I think that the the question that I'm struggling with now is really what is the difference displays and interfaces in this paradigm. Right? Because now we're rendering interfaces in the place of a display, sometimes. And I'm I'm now just starting to think with this whole in line editing idea, maybe a display is just a read only inline version of the interface. It it does remove that flexibility that we talked about earlier where you could have a different display value for a input value. But to me, it would sort of solve for some of the complexity in configuration and some of these questions that when is it when is it a display? When is it an inline interface? How do you control between the 2? How do you toggle? Etcetera etcetera. Because that way we could say, well, in every interface needs an inline and a block version. The block version is what we use on forms and bigger pages. The inline version is what we use in title cards and table rows and that kinda stuff. And then it is read only or it's not. Like we currently already have. You know, we have read only forms, for permissions and all that kind of stuff. And a display is effectively just a read only inline version of the interface. And then if you have the editable table layout which is just a toggle. Maybe it's always on tbd. The inline version of the interface now controls if it's a pop over or not. So the inline version of a die, of a checkbox. Just click it. It immediately interactive. In line version of a text input. Click it. You can type in line version of a relational, one to many or something. By default, it'll just show 6 items. But then when you click it, the popover has the actual editable part. Right? But I think it could be the same the same interface. It's all interfaces at that point. Interface is all the way down. I mean, it would reduce it. So so one of the other parts is, like, there is a bit of confusion around the difference between interface and display. And I feel like a lot of people configure an interface by setting up a new field and then don't know that displays even exist. Cause if you configure a new field, it's very easy to skip over it and never know it's there. Right? So I also think there is a case to be made that it would improve the experience for a lot of the people that normally don't, really take the time to go over every single option that exists because it can be a bit overwhelming, you know, arguably. There's a lot of stuff you can configure. That sounds good to me. It'd be a gigantic rate and change, so don't worry about that. This is not something we can just in a little 10.1. Here you go. Bang. Looks good to me. Ship it. But I I think to me, that would sort of solve it because then for the table layout, you can have a toggle somewhere that says make it editable. Yes or no. For and for any of the layouts, really. For the tabular layout, we can make it editable by default. For the cards layout, we could say it's probably not a good idea to do it for some but for others because now the layout's in control. I think there's there's something to it. Very cool stuff. Good stuff, guys. Any last questions from the, audience? Your chance is now. Forever hold your peace. Winston. Final cue. Forever hold your peace. If you're if you're still awake. Yeah. Oh, let's see. Vincent. Someone type it. Well, then, thank you everybody. Thank you. Bored everybody to death. We've hard hard boiled a few eggs. Lovely. Thanks for tuning in. In case you enjoyed this, there's much more of this on directors.io/tv. If you want to go there, there's lots and lots of interesting shows for you. Lots of good, great entertainment. And, feel free to join us next time for another very interesting topic. Thank you for linking the show, Kevin. Oh, yeah. Fire emojis. Yes. Very good. Thank you everyone for tuning in. We hope you have a great day. Enjoy your week, folks. Have a good night. Good night. Strong feelings, please let us know. The discussion is open. The issues are open. That way.",[],[],{"id":133,"number":134,"show":122,"year":135,"episodes":273},[137,138,139,140,141,142,143,144,145,146,147,148,149],{"id":142,"slug":275,"vimeo_id":276,"description":277,"tile":278,"length":187,"resources":279,"people":8,"episode_number":283,"published":284,"title":285,"video_transcript_html":286,"video_transcript_text":287,"content":8,"seo":288,"status":130,"episode_people":289,"recommendations":293,"season":294},"public-forms","932168576","In this recording of our live event on April 4 2024, Rijk, Jonathan, and Daniel discuss sharable forms for adding content to collections.","5e3ff428-f8d8-49a9-9c0f-34d2f0b0c4ca",[280],{"name":281,"url":282},"Github Discussion","https://github.com/directus/directus/discussions/18807",6,"2024-04-11","Public Forms","\u003Cp>Speaker 0: Hello. Hello, everyone. Welcome to another exciting episode of, request review, where we go over your guys' hopes, wishes, and dreams, and potentially crush them because software is not easy. Joking aside though, we're here to give we're here to go over your discussions inside of our repository. So if you're interested in a few feature or future features, please let us know.\u003C/p>\n\u003Cp>We have an existing, discussion template that you can use inside of our, repository or, extend existing ones. We also love to see that. And, today's topic, as you might have guessed with the title, is public forms or in other words shareable forms. So just, judging by the amount of people that I hear, I assume that this is pretty exciting for you guys. So give us a sign of life in the chat, please.\u003C/p>\n\u003Cp>Oh, that's what I future.\u003C/p>\n\u003Cp>Speaker 1: Like the people at home applauding. That's that's\u003C/p>\n\u003Cp>Speaker 0: that's Yes. Totally. Oh, yeah. We gotta oh, Oh, it's not French, it's Spanish for Noah. Okay.\u003C/p>\n\u003Cp>Okay. Okay. It's nice nice to see some interaction going. So public forms, shareable forms. Let's do a quick let's do a quick poll.\u003C/p>\n\u003Cp>So, how many of you guys used the current already existing feature of sharing forms or entries or however you would like to call it, share items. Because, I guess, public forms are very, very similar to that. It's, Brian says, I do not like sharing my forms. I do not like them then. I am.\u003C/p>\n\u003Cp>Yeah. Isn't that the the author's name? What is his name? Like a children's book author? Oh my god.\u003C/p>\n\u003Cp>Like, I'm blanking so hard right now. Doctor Seuss. Yes. Yes. Yes.\u003C/p>\n\u003Cp>Okay. Okay. Okay. Anyway, let's, let's go over some examples. So public forums, I think everybody has a mental image of what public forums are in their mind.\u003C/p>\n\u003Cp>But, let's make a very, very The most simple example that you could think of is just a contact form for me, basically. So you have a text input, and you want to put it on your website, and people reach out, fill it out, you get an entry, and you have an item in your database. Alright. Fair enough. But as you might have guessed, this is Directus after all, so this is not as easy in every single case.\u003C/p>\n\u003Cp>So, I I would I would love to quote, let give me give me one second to quote the person who opened the discussion, because there's such an amazing quote in there. I hope I did not oh my god. I think I closed the tab. I'm very sorry. Because the quote in there is just too good.\u003C/p>\n\u003Cp>Yeah. Very, very professional. Oh, my god. Maybe in the meantime, you could also think of a couple other examples, while I search for the thing because we're we're doing a show up.\u003C/p>\n\u003Cp>Speaker 1: Yeah. For sure. I think I mean, one thing that is probably, a good bit of context to kick off this discussion is just to go through what the current sharing thing looks like and what it does, and some of the requirements that we know exist around sharing things in general. And then sort of take it from there and elevate. Okay.\u003C/p>\n\u003Cp>What do we do to then unlock, you know, create and update and delete access next to just read access. Right? Because there's a reason we just started with reads and not the other ones. And that's that's sort of the complexity that I like to extract in in this session.\u003C/p>\n\u003Cp>Speaker 0: Speaking of complexity, I found the quote that I was looking for. And the quote is in the discussion itself is, the feature itself could start very small, but it could be very complicated if we wanted to cover more use cases. That's, like, literally every single every single feature that we could ever do.\u003C/p>\n\u003Cp>Speaker 1: That's the request review format for you, isn't it? So for those who are new in this session, one on good bit of context for what these live streams are all about. We just wanna take, you know, the discussion as it exists. Divergently think about, okay, what are all of the edge cases? Find sort of the use case, find all of the unknowns, and then take it back down.\u003C/p>\n\u003Cp>So, like, what is that MVP? What is the minimum viable product that we wanna ship for this to be a success? Right? What are the must haves? What could we add in the future?\u003C/p>\n\u003Cp>Where do we wanna start with this? Right? It's easy to say, oh, the the forms that you're sharing, just make them create access. Right? Done.\u003C/p>\n\u003Cp>But there's a lot more stuff going on into the hood as per usual. And also for the first time in days, we're getting some sun in here. So excuse my exposure.\u003C/p>\n\u003Cp>Speaker 0: Oh, we got some interaction. But, let me let me give let me give another example because there's many, many different use cases for public forms. So it's not just about, like, let's say, you put an email in there and a text box or something. It could also be more involved, for example, inside of your organization because directors is often used as a, like, enterprise tool inside of your company, for example, in the Internet even. So you could build a support ticket system in Directus, and we know that people do that.\u003C/p>\n\u003Cp>So, a public forum could be you visit a site inside of your Internet with an extensive, like, public forum describing what issue do I have, what department is this in, when did this happen, is this critical or not, other descriptions, related persons, or whatever. I mean there's also like very often for marketplaces or adding data to a validation queue because this is, like, very, very often the case. For example, if you have a marketplace and you want to open it up to new, merchants, they have to apply somewhere. Right? They they have to they have to ask, hey.\u003C/p>\n\u003Cp>I am this merchant. Can you please add me to your, shop? Or there was another example inside of the discussion itself regarding, let's say you have, like, a lunch app or whatever where you can off order food. So you want to get more restaurants or or bistros or whatever, and they can apply at your place. So you give them a public form.\u003C/p>\n\u003Cp>They can enter their information, and then you have, like, inside of your validation queue, all of the people or entries that you could go over and then, make sure that they get applied to your public to your service. Alright. Sounds like one of\u003C/p>\n\u003Cp>Speaker 1: the the initial requirements that you're sort of sneaking in with these examples is that this form can live both as a public website page in your direct instance or as an embedded form somewhere on\u003C/p>\n\u003Cp>Speaker 0: your website. Exactly. This is We're\u003C/p>\n\u003Cp>Speaker 1: we're immediately diving in, and we're off.\u003C/p>\n\u003Cp>Speaker 0: That that is that is literally I I wrote this down. This is exactly what I was, coming up with now because, like, the first the first requirement that kinda diverges, like you said, is, okay, so I have this public form. Where is it? Where where where can I find it? Because, like, it really depends.\u003C/p>\n\u003Cp>If I send somebody a link via email for example, it could be sufficient if the link is directly to your directors instance and you get served up like a complete page. And, there's the whole thing with the logo or whatever. And then you have an entire dedicated page for it. But very often also, you would like to embed your form into your existing website. Let's say with the with the, contact form example.\u003C/p>\n\u003Cp>Right? You just want to have a little contact form and on the bottom of your website. But, yeah, then then it starts then it starts. Okay. So you can have 2 different ways.\u003C/p>\n\u003Cp>Speaker 1: Yeah. I was gonna say, let's start let's start with what we have today. Right? So we don't have, writable forms. Let's call it that forms you can change stuff in.\u003C/p>\n\u003Cp>But we do have sort of the shared form where if you open a single item in a collection, you can share share that item. And what that does for the folk who've never tried it, which I believe is most, is that it will create sort of a temporary role, so to speak, a temporary access token that has access to just that one item with the role permissions that you associate to the share. So that sounds a little confusing, but that basically means you can give away a link that contains, you know, basically a long obfuscated URL that gives read access to just that one item and the relations that it has based on the rule that you associate for read permissions, Then that public link, it's, a directus page. So you will be navigated to your directus instance slash admin or slash shares, what we call it then for the public ones. And then, if you open that up, you basically get a read only state of the form that you just shared.\u003C/p>\n\u003Cp>Right? And there's some additional options on that share. You have you can set a password on it. You can set a maximum time, start, and end date that it's available to the public. Those those are the main ones.\u003C/p>\n\u003Cp>I think there's some other options. But long story short, the first step there is, like, if we were to just just enable a share on, the collection level, we can use that as a starting point, but that is only for forms that are then within that sort of share context of directors itself. Right? So you'd be able to use it as an alternative to something like Google forms or, type form or something where you create a form, you share it, you have a public page that you can share it, that you can, link people to. To me, the the fun complexity of this is really when it comes to, a, spam protection, and b, embedding it elsewhere.\u003C/p>\n\u003Cp>Right? Because somebody in the chat, our very own team just now, just half joking said just iframe it into your front end, which, sure, you can do that. But at the same time, somebody else in the chat also mentioned, you know, it would be great if there's a contact form on each of the products in my sort of web shop or or, renting, vending vending thing. At which point, you need to be able to dynamically inject some sort of default value into this form before you submit it. Now if we're talking about embeddable forms, it's almost like a different feature request.\u003C/p>\n\u003Cp>Because if you think about it, you could open up, write access to the public role and just build a form. Right? You can build a query you can build a form in your website and just post a request that straight out to, you know, your direct this instance. So, I think we wanna split this discussion up in, a, the shareable form, which is more sort of the Google form alternative versus embeddable forms, which is, like, what can we do to sort of make it easier to request or build a form indirect and then request it and display it just like that on your website?\u003C/p>\n\u003Cp>Speaker 0: Because, also, how much control do you want to have regarding the styling, for example, with, like, branding? Do your inputs look different? Because, you know, it looks out of place. It could look out of place if, you use our design guidelines, but your brand uses, like, way smaller inputs. It just looks very weird then.\u003C/p>\n\u003Cp>So we also had a nice, suggestion for, by Tim that I like. Where is it? Oh, no. No. By by by Brian.\u003C/p>\n\u003Cp>By a nice, by Brian. Pre filling fields by query parameters could be very cool. And hidden fields, of course. Like, there are many, many, there are so many things that you could do because there's so many different use cases. Like you said, for example, if you want to embed it, do we want to a do we want to be able to also restrict, like, how many different links there are to that form, for example?\u003C/p>\n\u003Cp>So, if I have a email list and I want to contact all of my contacts and I I give them each a personalized input field because I want to avoid the spam issue that you just mentioned, you know? So let's, say, okay, I only want people to be able to answer the form once, at least, you know, on that link, for example. But can they be different? Should they be the same all the time?\u003C/p>\n\u003Cp>Speaker 1: So using the form once, that's the part that we do currently support with the read only share. Right? Where there is a setting for how many times can this item be opened. And every time somebody opens that that item, it just, you know, it decreases the number by 1. And then once the number hit 0s, the link, you know, goes goes this disabled.\u003C/p>\n\u003Cp>Now for creates, how do you confirm that it was done by 1 person? Right? If you associate it to an email address or something, are we gonna do email validation? Do do does there have to be a confirm step? Which is sort of like I'm I'm thinking about other forms I've seen in the wild.\u003C/p>\n\u003Cp>Right? Where it's like you wanna sign up to a raffle or something and you leave an email address and that's your that's your ticket, so to speak. But you can only use it once. Yeah. Somebody in the chat rightfully now at that point, aren't you just logged in to the app anyways?\u003C/p>\n\u003Cp>Because now you have some sort of an account or a verified account within that direct to this instance. Maybe. Maybe. Right? Hard to tell.\u003C/p>\n\u003Cp>Well, I think the other the the question that closely ties into this as well around things like CAPTCHA. How do you prevent robots? How do you prevent AI from just pulling up the form and spamming it to death? Right? Of course, an obvious one for a lot of folks like, oh, just smack a a Google recap on that and you're done.\u003C/p>\n\u003Cp>But, of course, this wouldn't be a direct this request review chat if it was that simple. Because there's a lot of sort of like wrecking and accessibility concerns around, CAPTCHA as a whole When it comes to Google CAPTCHA specifically, I I I'm a little fuzzy on the details, but I'm pretty sure there were some GDPR concerns around embedding Google services as a whole, that already requiring, you know, cookie notices and whatnot because almost every Google service will track you to bits, if you embed stuff on your page. So that's a concern. It also relies on a third party service, which is something that historically we have to be a little bit careful with, because we wanna support multiple different options. Right?\u003C/p>\n\u003Cp>But now here we go. This is the point where now we need to think about how do we have a standardized CAPTCHA system that can work with providers that works across form, right, for both shared forms and into and, like, in internal forms. Another question from the chat. To add some more complexity, who creates the public form? Is it an administrator or a nontechnical CMS user for whom setting up a form with the data model interface might be overwhelmed?\u003C/p>\n\u003Cp>Another great question. Right? So in in the direct to this model form is basically tied to your data model. So if you share an item, you share the item that you're seeing with somebody else. Right?\u003C/p>\n\u003Cp>So in its simplest form, you would share the form that you're currently seeing with the world. Is that what you want? Maybe not. Probably not. In Daniel's example from earlier, if you wanna do a simple tech form with just an email and some text, it's very likely that in your data model, you end up with a status field that says has been responded yes or no or metadata that you wanna have in your system.\u003C/p>\n\u003Cp>But how do you differentiate between the 2? Are we gonna ask the user who is sharing the form to then pick and choose fields to share specifically? Are we gonna attach it to another role soon to be policy? Or are we gonna, or or plan c is, are we gonna strip public forms from the regular content model altogether and just have a whole different section somewhere that says, here is public forms. And then perform, you just have to configure where the responses are saved.\u003C/p>\n\u003Cp>Speaker 0: Yeah. Regarding your point of configuring specific fields like the status, for example. Like, if somebody submits the form, should it be, you know, active, reviewed, tool review, draft, or whatever? So that that really sounds to me like a field preset sign type of thing, but that exact same vein. Okay?\u003C/p>\n\u003Cp>Let's say you have a form with a user created field that automatically adds the user that created that row. Okay. What do we put in there? Who who who created that? I mean, the user could, you know, make their own public user, so to speak, and link them via a field preset, but then also kind of fields just not quite thought through.\u003C/p>\n\u003Cp>Like, to me at least, like, just thinking about it right now, like, it feels, like, so hacky that people would need to do that themselves, that it feels like this is not really thought through. But on the other hand, like, do we want to have, like, a global invisible user that we could reference? Maybe.\u003C/p>\n\u003Cp>Speaker 1: I mean, we do have the concept of a public role. So with the user created example, it would be null because there's no user indirect because that created the thing. So if we if we zoom back out just a little bit, I think the first question that we sort of had this session hey, Jonathan. Welcome to join you, Just to catch you up. The first question was, shareable forms versus embeddable forms.\u003C/p>\n\u003Cp>Right? Which is a shared form is basically the way I see it now as a page within Directus that you'll to, and they just get, you know, a nice looking Directus connected to stuff. It's safe. Done. Little you know, think about Google Forms sort of mentally, that style.\u003C/p>\n\u003Cp>Right? The second thing is some sort of UI component or some sort of auto generated API endpoint or maybe just a public post could be, to render a configured form and direct us on your own app or website in whatever way is appropriate for your tool. Right? To me, those are 2 separate discussions. I think we start with the shareable forms because then the embeddable forms could use the same permission system and shared, configuration from the shareable form to then embed one of the shared forms.\u003C/p>\n\u003Cp>Right? That's kind of what I think that that would be a 2 step 2 step approach.\u003C/p>\n\u003Cp>Speaker 2: Nope. I like that. So that's what you're seeing here. Right? So this is the current it's read only at the moment.\u003C/p>\n\u003Cp>Hard coded is read only. Even though we allow we've kind of plumbed this for role support in the future, it's currently read only. It's hard coded read only. So you get a read only form that looks like this, and it is to a degree, there are some permissionings. So the role does give access to the fields that are available and the relational content that's technically available and visible in the form.\u003C/p>\n\u003Cp>So you can see here my image isn't showing because I don't allow I haven't allowed the permissions correctly on that particular role. So you could have that kind of capability, And I believe we should I haven't tested this, actually. I because I'm logged in as an admin right now, but I think we can restrict the role list here based on the so the the allowed roles and permissions for the user.\u003C/p>\n\u003Cp>Speaker 1: Permissions again? Yep. Exactly.\u003C/p>\n\u003Cp>Speaker 2: So permissioning should control what's available in this list. So I think, again, I think the general plumbing is there for a shareable, editable form? The question becomes, what is it that we're sharing? You know, are you allowing them to create a an item from the form? What does that look like?\u003C/p>\n\u003Cp>Because right now, we are sharing an existing record. So there'd be work to be done around that, I think. Absolutely. As an embeddable I like the embeddable idea. Technically, you can kinda do that already.\u003C/p>\n\u003Cp>You know, we we see examples of that in the structures that, our good friend, Bryant, has set up where, you know, he set up these kinds of forms where\u003C/p>\n\u003Cp>Speaker 1: Right.\u003C/p>\n\u003Cp>Speaker 2: He's almost replicating our schema management capabilities of being able to create an editable form. So he's made it so that you can create a schema field, add whatever, you know, value type. This is a And as we're\u003C/p>\n\u003Cp>Speaker 1: talking segue into, the second question I wanted to bring up, which is for shareable forms, are we sharing an existing form and you will still limit it down. Limit it down. Or is it effectively a separate form builder where you can create one of forms that you then connect the dots between that and your actual data model?\u003C/p>\n\u003Cp>Speaker 2: Yeah. Similar to I think our our CRM has that kind of capability where you can build a form. Right? And then behind the scenes, the data gets stored wherever you direct those fields to store. Exactly.\u003C/p>\n\u003Cp>But you've got an and it's embeddable as a you know, you can get it as a link or you can direct them straight to the form or you can embed it as an embeddable link underneath the hood.\u003C/p>\n\u003Cp>Speaker 1: Because the one thing I do recognize about the current share system is that it's a little bit a little very opaque. What's the right word? It's a little opaque to to know what you're sharing. I mean, by default, you're sharing what you're seeing. Right?\u003C/p>\n\u003Cp>It's like you're sharing the item that you're currently seeing. Yep. But what's actually gonna\u003C/p>\n\u003Cp>Speaker 2: be shown to the user is different. Right? So you have to go check the link and see what it's gonna\u003C/p>\n\u003Cp>Speaker 1: look\u003C/p>\n\u003Cp>Speaker 2: like versus\u003C/p>\n\u003Cp>Speaker 1: It's because it's based on the role that you then associate with the share. So if you use your own role, it's what you see is what you get. But other than that, it's a bit of a, you know, to your point, you have to create the share, pull it up, double check. If you're creating a dedicated form to share, be it read or write, that confusion is taken away immediately because it's the form that you created. It's the form that you're seeing.\u003C/p>\n\u003Cp>Right? I think the big question then becomes, how do we handle permissions if at all? Do we auto generate the permissions based on the stuff you put in the form? And therefore, you make it very explicit. Like, you put, an email address field, so therefore, you can see an email address.\u003C/p>\n\u003Cp>Or do we make it a little more opaque again by associating a role or multiple policies to TM to control the permissions for that shared item. Right? That's that's where it's a little finicky. So when when I meant that permissions, for example, if, where permissions become really important is for nested relationships. Right?\u003C/p>\n\u003Cp>So if you have a read item with a many to one field to a related category or something, what part of the category are you also supposed to be able to read from this entry point of the top level item? So having some sort of permission set there is gonna be required. Because otherwise, theoretically, if your relationships are a little complicated, you could pose a hell of a lot of data. Right? Because if we were to say, auto generate all of them, if you have a user created field because you just wanna show somebody's name, avatar, you could now theoretically go to that user record and you go to a direct to files record because you now have that connection through the user.\u003C/p>\n\u003Cp>Right? So that also, makes me wonder, there's another feature request that is completely unrelated to this, but it might actually directly be related now. One that I opened, I feel like 20 years. It's configuring access control permissions based on a parent child. So instead of saying, you have access to direct these files, you have access to direct these users.\u003C/p>\n\u003Cp>It's saying the permission, you can read a file if it's attached to a user if you're coming through the user and only then.\u003C/p>\n\u003Cp>Speaker 0: Oh. Oh, yeah. Yeah. Yeah. Yeah.\u003C/p>\n\u003Cp>Yeah. That's, that would be very cool. That would be very cool.\u003C/p>\n\u003Cp>Speaker 1: Top the clock. I think we need to need to start a new game. It's like, at what point do we get Jonathan to do that?\u003C/p>\n\u003Cp>Speaker 2: It doesn't take much.\u003C/p>\n\u003Cp>Speaker 1: It doesn't take much. Because because that would that would also potentially solve for this. Because then you could say, okay. If you have many to 1 on the record that you're sharing, you now have access to read just that one record from the related table, but nothing else from the related. Right?\u003C/p>\n\u003Cp>And for the record, that is how the current share system works actually under the hood. It is a hell of a lot more complicated, because what it does is it looks at the item that you're sharing and it checks what items are related, and then it makes a new permission set that says you can read just that one item from the related table. Right? But all of the other API ends work the same, which is interesting. But that's that's the way it does it right now.\u003C/p>\n\u003Cp>So it does actually, you know, specifically look up which items are related, which items are shared as per the role, but then lock it down to only allow you to ex that one particular item that is associated to the shared thing to make sure that we don't overexpose data in your system. Food for thought. But it it, you know, we're getting real quick into the weeds here again. Just from the question, is it sharing the existing form from your data model or are we sharing new one off forms? It sounds like and I've I've it it sounds like we probably wanna look into some sort of system.\u003C/p>\n\u003Cp>You can create individual forms and associate them back to your data model. Just in those cases where you wanna have multiple different forms with different fields that go to the same item.\u003C/p>\n\u003Cp>Speaker 2: Commonly the case. Right? So if I was setting up a, you know, a a newsletter subscription, I might have very simple, but I still wanna register the contact. I still wanna be able to, you know, track their compliance or other things that I may wanna track or need to track versus the same contact information I would collect for a you know, you're signing up for a meeting or a webinar or something else. So the the forms can be storing data to the same places or to additional places.\u003C/p>\n\u003Cp>Speaker 1: Follow-up question. What is that? One of these public forms, and I'll I'll get to Tim's question in the chat very soon because that's another level of complexity. But should we allow one of custom forms to save to multiple tables at the same time?\u003C/p>\n\u003Cp>Speaker 2: Yes. Technically, yes.\u003C/p>\n\u003Cp>Speaker 1: Form can one form create 5 different records in 5 different tables?\u003C/p>\n\u003Cp>Speaker 0: Oh, I think it must. Right? Because of relations?\u003C/p>\n\u003Cp>Speaker 2: Well, not even relations.\u003C/p>\n\u003Cp>Speaker 1: Go Independent of relations. Right? Yeah.\u003C/p>\n\u003Cp>Speaker 2: So if I'm if I'm setting up a form to collect, medical data, you know, to sign you up or set you up or do something or I'm collecting a survey, I might have survey information that I'm storing in the survey table, contact information I'm storing in the contact table. Just simple example. Right? Just 2 tables. But the contact information is in one place, the survey data is somewhere else.\u003C/p>\n\u003Cp>And I may from a from a compliance perspective, I may not be associating the user. I'm just tracking that the user responded, but the survey data has to be independent. Right? No relation at all.\u003C/p>\n\u003Cp>Speaker 1: Here's one quick question.\u003C/p>\n\u003Cp>Speaker 0: Good point, but Tim, wait beef before we go further further down the rabbit hole, there's another good point by Tim. It it it really sounds like a job for a flow or hook. And I think I agree, actually, because, like, the complexity then of setting it up and then the UI that has to be added for that and, stuff that could go wrong and stuff. Like, maybe, you know, just as a as a simple example. Okay.\u003C/p>\n\u003Cp>You have you just make one row in one table. That would that could be the cutoff that we decide on, maybe. I don't know. But it it really sounds like maybe a hook or a flow would then should be responsible for, you know, taking the the depending on the status, it takes the user's email and puts them also into the contacts table or the whatever table. I think I agree with that take.\u003C/p>\n\u003Cp>How do you guys feel about that?\u003C/p>\n\u003Cp>Speaker 1: It's both ways because you could say you'd save all the data to a table and then run the flow based on that change or you save the form to a flow and then handle it yourself. I and I think there's a case to be made for both because for a simple contact us form that is always going through the same table in the same format and it matches your data model, it feels like flows could be a lot of, you know, complexity to configure just for that simple use case. But for everything else, I fully agree. Once you go, I wanna touch 5 different tables and I wanna submit to a different web, and all that kind of stuff. Yeah.\u003C/p>\n\u003Cp>Form to a flow, makes a lot of sense. Right?\u003C/p>\n\u003Cp>Speaker 0: Right. So let's blow up this, let's blow up this discussion further because Tim also said, alright. How about, should public forms be able to save to a specific content version as well.\u003C/p>\n\u003Cp>Speaker 1: If you call the first deal with the safety of a specific content version. Well, the nice thing is if we're going with this whole form safe to flow as idea, then sure do whatever you want. Right? That's that's kind of the beauty of the escape hatch that could be flows as the back end forms. Because at that point, if you wanna save it to a conversion, go for it.\u003C/p>\n\u003Cp>Right? What do we care? What when how when would you use that, though? Let's think about that for a second. So you have draft state basis for an item.\u003C/p>\n\u003Cp>Speaker 2: I guess if you were updating existing content, you may wanna do that as a version, possibly. Typically, in shareable forms, I don't see it as a version necessarily. But if you were allowing someone, say, to update but even then revisions would track the the content changes over time if you were inclined.\u003C/p>\n\u003Cp>Speaker 1: I I think yeah. What I was just about to say is what Tim again just put in the chat. Let's say you want to review and approve the changes that were made in pub. Right? So if you're running a sort of Wikipedia style, Wiki style, page Mhmm.\u003C/p>\n\u003Cp>And you wanna allow people to suggest edits, you could have a public form to update that one particular page, and then those updates go into a version that then can be reviewed and approved by the old person in charter, which is an interesting an\u003C/p>\n\u003Cp>Speaker 0: interesting use\u003C/p>\n\u003Cp>Speaker 2: case. That's a cool that's a cool freaking use case.\u003C/p>\n\u003Cp>Speaker 1: Which actually would be very convenient for our own docs for that record.\u003C/p>\n\u003Cp>Speaker 0: For example, that's what I was thinking about. I have the little button on the bottom here. Edit this page. Edit\u003C/p>\n\u003Cp>Speaker 1: this line. That would be very cool.\u003C/p>\n\u003Cp>Speaker 0: Hang on.\u003C/p>\n\u003Cp>Speaker 1: Another use case from the audience in, in that updating existing thing from, Jay Shue says, another use case is a business directory and the users being able to suggest changes. Agreed. And the Durb saying we could actually use that fairly well as well. That's it. It could be implemented in flows.\u003C/p>\n\u003Cp>Right? Which is where it gets interesting again. Right? Because flows really become that sort of escape hatch for this type of stuff that, like, oh, you wanna save it to a version instead of to a table? You wanna save it to a different whatever you wanna do.\u003C/p>\n\u003Cp>Just use a flow. It it does also answer the question, is this just for create or is this also for update? And I think we've just concluded that also updates are important. Click updates. That's when you can do you can update an existing submission that you've already done, or you could, you know, the Wiki example or the business directory example or some of those.\u003C/p>\n\u003Cp>Speaker 2: Yep. I think about, in particular, things like, you know, some of these online forms could be fairly complex. Right? I've I've done this. I've I've got you know, you're filling out something for a financial thing and you, you know, it's gonna take you an hour to do the form while you may be saving and coming back later.\u003C/p>\n\u003Cp>You can come and go from it. We do a lot with secured online security forms, you know, where we're filling out answers to complex questions that take hours or days to finish. And so, essentially, saving state and coming back and making updates and, oh, I mean, I I wanna fix that answer that I did, you know, 3 pages back in the form, and I wanna go make that adjustment.\u003C/p>\n\u003Cp>Speaker 1: I think we found another use case for the saving it to a version.\u003C/p>\n\u003Cp>Speaker 0: Mhmm.\u003C/p>\n\u003Cp>Speaker 1: Because if you save it to a version, the validation of the database doesn't have yet because it only needs the saves to the database rather than to your stage to changes. Right? So the, what would you call it, plausible forms where you can enter a bunch of stuff, hit save as draft basically, and then come back later. That would be relying on content versioning.\u003C/p>\n\u003Cp>Speaker 2: Good. Yep. Good very well. Doesn't have to, but it could. Right?\u003C/p>\n\u003Cp>You can manage that via state or status or other things as well. But,\u003C/p>\n\u003Cp>Speaker 1: yeah. Unless you're thinking about validation in that case. Right? If you have data integrity rules that say the column cannot be So in your form, it has to be filled out. But you don't want the force to use the whole form once, you need to have an in been safe, which would be, you know, a version conversion version.\u003C/p>\n\u003Cp>Speaker 2: I like it.\u003C/p>\n\u003Cp>Speaker 0: It's Okay. Let's\u003C/p>\n\u003Cp>Speaker 1: I need to switch to a slightly simpler question. Otherwise, my brain is gonna go What about deletes? Is Is that a thing you do publicly?\u003C/p>\n\u003Cp>Speaker 0: My first gut reaction was no. Hell no. But, let's give it a little more thought.\u003C/p>\n\u003Cp>Speaker 2: But I guess if it's user data, I don't know. I could see a use case for it. I don't I don't think from our side of things, if depending on how it's implemented, If you got compliance issues, GDPR, other kinds of things where the user has the right and choice to do that, that's that's gonna it's gonna be very use case specific.\u003C/p>\n\u003Cp>Speaker 1: Because for the case\u003C/p>\n\u003Cp>Speaker 2: we we try not to delete data in general. We put it in the soft archival state. You know, we use status or other things to handle that. But where you have compliance requirements where you must delete, But I don't know if that's a form. That that could be flows driven.\u003C/p>\n\u003Cp>That can be log business logic driven at that point as opposed to something to do with the form itself. I think you'd have to have a form that says I wanna I want my data to later. I wanna unsubscribe. And by doing that behind the scenes, the flows and data data management happen the way that you need them to happen.\u003C/p>\n\u003Cp>Speaker 1: Right. Because I I could imagine that the because because deletes blank at least sound kind of insane. Because you would have what? You would show the user, here's all the records and go whichever delete whichever one you want. It that that feels like not something that you'd realistically want.\u003C/p>\n\u003Cp>But I could imagine that if we connect it to an account again, not not so much a a direct as app account, but, like, the moment you create a form submission, I could imagine that you maybe wanna do a public read of a layout. Here's a new question that we're gonna discuss in 5 minutes. Where you can just as a user as a temporary user all the submissions that you've done in the past and then delete a previous submission.\u003C/p>\n\u003Cp>Speaker 2: To me, again, business logic. Right? That that tends to be not so much I I think you'd I think someone suggested it here. I think you'd do it as a delete request. You'd submit a request to delete and then confirm whatever mechanisms.\u003C/p>\n\u003Cp>Your your business logic, your flows, your your any additional code processing that you're doing on top of that would handle those things and send notifications accordingly. Feels very much like you would submit that as a specific form request to remove data, not the ability to delete data from the form. I think I agree in general that that shouldn't be allowed. You'd have to submit that as a separate form, maybe. I don't know.\u003C/p>\n\u003Cp>I'm sure there's a use case that I'm not thinking of. But\u003C/p>\n\u003Cp>Speaker 1: Yeah. But to your point, if you create a new form that triggers a flow rather than saves to a table, that flow then just deletes it, whatever, based on your business logic, then prop solved. Right? You you don't necessarily go the mile to\u003C/p>\n\u003Cp>Speaker 2: Yep.\u003C/p>\n\u003Cp>Speaker 1: Have native victim delete support for that specific of a use case. Okay. Interesting. Interesting. Interesting.\u003C/p>\n\u003Cp>Interesting. Tricky. Tricky. Tricky questions. Tricky questions.\u003C/p>\n\u003Cp>Another another question in the chat here from user. So what about editable forms or relational data where items can be deleted after it's been saved and the user edits the data?\u003C/p>\n\u003Cp>Speaker 0: We got it. Ladies and gentlemen, we got it.\u003C/p>\n\u003Cp>Speaker 2: That's the real goal. If we can get right to do it, then we're then we're successful.\u003C/p>\n\u003Cp>Speaker 1: What about editable foreign situational data where items can be deleted as it's been saved and use it as the data? I mean, I guess that kinda goes for any editable forms that it's like, user creates it, admin changes it, user tries to edit it, and that looks different. Which, yes, it will look different because you changed it. You changed somebody's submission. Right?\u003C/p>\n\u003Cp>I think that becomes becomes more of a workflow or a business process, thing where tell your staff don't touch, you know, don't go changing somebody submission. That's bad mojo. But I guess yes.\u003C/p>\n\u003Cp>Speaker 0: What about resubmitting of shareable forms? We're kind of in the midst of thinking this through because, in the beginning, we said, okay. If you have a fixed link that you can send somebody and then they submit the thing, we could restrict that you can only submit once with that link. Or you can have a general link where, like, every single submission results in a new row every time. But then it's very use case dependent, I think.\u003C/p>\n\u003Cp>No. Like, that should be just configurable. Okay. Is this, will this result then in a on on my second visit to that link, will it show me the actual item, or is the form empty again, and can I resubmit it? I mean, that's, like, very dependent on on on the configuration, I think.\u003C/p>\n\u003Cp>Speaker 2: Yeah. I think it should be doable, though. Some additional configurations here, potential validation checks. So, again, if it's an embeddable form or it's a shareable, editable form from our side, then this is gonna need some updating as well. Right?\u003C/p>\n\u003Cp>We'll need some additional parameters and things here. You'd have to potentially check the data, validate the data on save. Flows, again, can handle some of that, but to give the user feedback of you've already submitted or disabling the form because they've already made a submission. How do we check that? What does what does that look like?\u003C/p>\n\u003Cp>Because now you actually have to have something, you know, activity wise that says your device or whatever has been registered. We know that it was you, and you've already submitted the form. Yeah. That gets that's where I I don't know. It almost feels like that should just be front end dev work and get managed from that side of things.\u003C/p>\n\u003Cp>But Oh, here's here's\u003C/p>\n\u003Cp>Speaker 1: the problem though, Jonathan, when it comes to the form that we're sharing, who's the front end dev doing the work?\u003C/p>\n\u003Cp>Speaker 2: It's it's us.\u003C/p>\n\u003Cp>Speaker 1: It's us.\u003C/p>\n\u003Cp>Speaker 2: It's us. I know. So this needs more complex kinds of things because now max 5 uses, well, is that 5 users, or is that 5 you know, one person could submit all 5 or use all 5\u003C/p>\n\u003Cp>Speaker 1: values. Right? Is a user?\u003C/p>\n\u003Cp>Speaker 2: What is a user? Right? What is the\u003C/p>\n\u003Cp>Speaker 0: Are we getting deep? What am I I mean,\u003C/p>\n\u003Cp>Speaker 1: that's that's kinda the question\u003C/p>\n\u003Cp>Speaker 2: right now. I think about like same thing. We we track this on, you know, AppSight anyway, but now we've got this floating thing out there that would also have to track an activity record of who the IP and device and things are and be able to validate against that as part of this form configuration or this shareable form configuration. Now it's, you know, one time per user or per IP or, you know, whatever we consider that to be. There'd be something here, you know, max uses.\u003C/p>\n\u003Cp>So I want a 1,000 submissions, but then I wanna be able to also say per something.\u003C/p>\n\u003Cp>Speaker 1: The the problem of the the how do you confirm the per something? Because you could say you could you could I mean, you could get away with it by just having a unique column. Right? That it's like you can only have one submission with this email address, and that's it. Done.\u003C/p>\n\u003Cp>It could be unique. Already exists. Can save it. Done. Right?\u003C/p>\n\u003Cp>But how do you prevent somebody, you know, with a Gmail account, for example, you can do the plus something something and it will come back to you anyways. You prevent somebody from submitting times with the same, you know, plus 1, plus 2, plus 3, that will work. And I can use all information still. Because there's no way for us to validate that. And then, you know, for email specifically, you can start thinking about, maybe we have some sort of email validation or we send an email and you have to click confirm or all that kind of stuff.\u003C/p>\n\u003Cp>But then what happens if you wanna use something else as the unique identifier? What if you're doing some of the phone numbers? Right? Where it's like, enter your phone number, we'll send you a text when it's your turn to to for for like reservations. Right?\u003C/p>\n\u003Cp>If you're doing a reservation at and it's it's that's that's very common around here. I don't know. Over in your parts of the world. But, you know, if you go to a restaurant here and it's full and it's like, oh, your your table's gonna be about 40 minutes and you your phone number, they'll send you a text when it's ready. Right?\u003C/p>\n\u003Cp>Mhmm. Or about 10 minutes before it's ready. So in that case, you wanna duplicate it on the phone number, but how can you confirm that? Right? You you can't really, there's no way for us to know that.\u003C/p>\n\u003Cp>Speaker 0: A simpler a simple example would be if if you have first sorry, the delay delay is giving us. No, but but a simple example for, limiting that kind of, use would be, let's say you have a form that you can resubmit with, let's say, you have an online shop and then you want to use this for functionality for giving out promotion codes, and you only want to give out a 100 promotion codes, okay, Then it's just a matter of counting the rows, you know, so so we don't have to have a unique field or whatever. We just say, okay. This form can be submitted 100 times. That's it.\u003C/p>\n\u003Cp>I think there's like, it's a little different to your guys' use case, what you just described with the email and and phone and whatever. But, I mean, this is also a valid use case, I think. You know? I I want this form to just be usable for 100 submissions. Okay?\u003C/p>\n\u003Cp>Then it's just a matter of counting.\u003C/p>\n\u003Cp>Speaker 1: Mhmm.\u003C/p>\n\u003Cp>Speaker 2: Well, that's our that's already built in. Right? So we already support that max five uses. So and we keep track. Similarly, if we want this to be 1 per or 2 per source, right, then we have to actually track from a and, I guess, because it's an embeddable form or it's a, you know, we we have information and knowledge about the browser.\u003C/p>\n\u003Cp>Right? We we can track that. It just requires that we store the activity information and utilize that as part of the additional values here in a sense. There's still ways around. Right?\u003C/p>\n\u003Cp>There's always a way around. I've got 5 devices, and I wanna submit 5 submissions. You know, I can I can do that, but and and, you know, we can do things like enforcement of uniqueness on the values coming in and those things? That's already there. It's more about can I at least track to know that this user has already submitted a form because of their IP address slash device ID, that we track anyway from the browser cookie side of things?\u003C/p>\n\u003Cp>Speaker 1: I think, I think I'm reaching the same conclusion as Tim. It's like we're going down the bot detection rabbit hole, which is like, can we fingerprint an individual user? No. There's no way. There's there's no way because IP address is shared with the location.\u003C/p>\n\u003Cp>So, therefore, everybody in the same household or the same business is gonna have a similar bound IP address. So that that doesn't work. I mean, this this fingerprint in question has been a cat and mouse between browser makers and, you know, back end implementers. It doesn't exist. The only way to do that is to require a sign through some sort of secondary authentication method, like send you an email with a magic link.\u003C/p>\n\u003Cp>So therefore, you prove you have access to the email, and that's it. Right? Before it submits or text with a phone number, that kind of stuff. Or log in through an SSO provide to confirm your, you know, your identity there, which actually is a different question I didn't even think about. But it would be kinda nice if you could sort of, like, connect the dots between what is your GitHub account click here to to o auth your way in to confirm, but that's not gonna be a 5 minute conversation, I don't think.\u003C/p>\n\u003Cp>Another question from the chat here, from from user and I'm gonna butcher your name. Sorry about that. Mama. That's what I'm gonna go with. How about the ability to show already submitted values to the user when filling out a form?\u003C/p>\n\u003Cp>Thinking about a sign up form for a party, and showing what food others already bring with them. Which is so this is an interesting question, which I think is not so much, the shareable, writable form. This is the question of readable lists of items. So right now, the share that we offer is just for a single item. You share that one.\u003C/p>\n\u003Cp>Right? What we don't allow you to do yet though, you can go to a layout and share the whole in a simple fashion. I could imagine that for this particular use case, what you would do is you would basically make a public share for your record of foodstuffs people bring to the party, long collection name, and then you can give people that link. Right? And then when they go there, they just see a layout like you would expect from directives with all of the stuff that has been previously entered with a click to to open an individual, I imagine, and then a, you know, a plug or something to go to the create page if you have create permissions through that public share.\u003C/p>\n\u003Cp>Speaker 2: I think this is actually related to Hannes' question as well. More so because the food items being brought can be a many to many or a relational junction that's already there. So we'd show that in the current form. Right? Just like we did, you know, I only have translations in here right now, but equivalent kinds of things where you've got a a relational structure.\u003C/p>\n\u003Cp>The real question becomes when you're adding or removing relational items, this is considered potentially a delete operation under the hood. Right? So there there's there's a little bit of a tie between the delete conversation we were having and this ability to show or allow or not allow you to you know, you might be able to see what other people have brought, but you can't remove their food item. You can only add your own food item. Right?\u003C/p>\n\u003Cp>And or remove your own food item. I think role permissions generally work correctly for that, but it becomes a question of making sure that you test and set those things correctly. But is that considered a delete? Right? If you've got a cascade operation on, you know, removing a a relational item, well, that's potentially gonna cascade and cause a delete down the line.\u003C/p>\n\u003Cp>Speaker 1: I think that would always be a deselect from the relational perspective. The\u003C/p>\n\u003Cp>Speaker 2: Well, that depends on what you set your permissions for. Right?\u003C/p>\n\u003Cp>Speaker 1: Oh, it's what you do. It's not permissions. The field\u003C/p>\n\u003Cp>Speaker 2: oh, I guess it's what you set your field settings for. Right? If you set by default, yes, we set it to nullify so we don't actually delete any data. But if they've got cascade delete permissions, you know, if the cascade delete is turned on, that's going to actually delete data or contact.\u003C/p>\n\u003Cp>Speaker 1: Point. Yeah. So the that's here's the security vulnerability way to happen. If you have an edit access to a simple item with a many the one many the one is configured to delete on select. If the user edit the field and they deselect, they now can theoretically delete stuff in your database, which is fun.\u003C/p>\n\u003Cp>Alright. Oh, jeez. It's already we're very we're already on on the dot here almost at 11. Oh, yeah. 11 for me.\u003C/p>\n\u003Cp>Times for everybody else. Just to to summarize all of this, because we went very much like this, but not a lot like that yet. We're running out of time. I think some some initial conclusions as far as I sort of take it now from this session. Right?\u003C/p>\n\u003Cp>It's like there's definitely a difference between shareable forms and embeddable forms. Shareable forms is part 1. Embeddable forms can then reuse whatever configuration that has for embedding stuff. I think that's conclusion number 1. I think to me, conclusion number 2, it's ideally you can create forms separately from the data model.\u003C/p>\n\u003Cp>Model. Although, that is quite a bit, you know, more involved to build and experiment with and etcetera etcetera. I think starting with create access is the most straightforward as you don't have problems with who can read what, how do you update previous submissions, how do people know what submissions they've previously done, etcetera. So in order of operations, shareable pages create first, then, read access for a listing would be very useful because then you have a way to click into an update item there. And then I think as a sort of your v 2, we should think about what do we form creation to look like in the first place and how does that tie into sharing?\u003C/p>\n\u003Cp>And a different question is, should sharing even be tied to collections and items, or is it just pages in the app altogether? Because I can also imagine that there's other places, like, folder in your file library that you might wanna share. Don't know. Like, another feature request for a different day, because I got skipped is, what about shareable dashboards from Insights? That'd be cool.\u003C/p>\n\u003Cp>But let's not do that right now. We'll save that for a different session. For now, Daniel, back to you to close it out.\u003C/p>\n\u003Cp>Speaker 0: Thanks everybody for coming. If you enjoyed this discussion or are interested in other discussions, you can head over to directors. Iotv where you can find lots of other interesting shows and also this one. And, we hope to have you to see you again.\u003C/p>","Hello. Hello, everyone. Welcome to another exciting episode of, request review, where we go over your guys' hopes, wishes, and dreams, and potentially crush them because software is not easy. Joking aside though, we're here to give we're here to go over your discussions inside of our repository. So if you're interested in a few feature or future features, please let us know. We have an existing, discussion template that you can use inside of our, repository or, extend existing ones. We also love to see that. And, today's topic, as you might have guessed with the title, is public forms or in other words shareable forms. So just, judging by the amount of people that I hear, I assume that this is pretty exciting for you guys. So give us a sign of life in the chat, please. Oh, that's what I future. Like the people at home applauding. That's that's that's Yes. Totally. Oh, yeah. We gotta oh, Oh, it's not French, it's Spanish for Noah. Okay. Okay. Okay. It's nice nice to see some interaction going. So public forms, shareable forms. Let's do a quick let's do a quick poll. So, how many of you guys used the current already existing feature of sharing forms or entries or however you would like to call it, share items. Because, I guess, public forms are very, very similar to that. It's, Brian says, I do not like sharing my forms. I do not like them then. I am. Yeah. Isn't that the the author's name? What is his name? Like a children's book author? Oh my god. Like, I'm blanking so hard right now. Doctor Seuss. Yes. Yes. Yes. Okay. Okay. Okay. Anyway, let's, let's go over some examples. So public forums, I think everybody has a mental image of what public forums are in their mind. But, let's make a very, very The most simple example that you could think of is just a contact form for me, basically. So you have a text input, and you want to put it on your website, and people reach out, fill it out, you get an entry, and you have an item in your database. Alright. Fair enough. But as you might have guessed, this is Directus after all, so this is not as easy in every single case. So, I I would I would love to quote, let give me give me one second to quote the person who opened the discussion, because there's such an amazing quote in there. I hope I did not oh my god. I think I closed the tab. I'm very sorry. Because the quote in there is just too good. Yeah. Very, very professional. Oh, my god. Maybe in the meantime, you could also think of a couple other examples, while I search for the thing because we're we're doing a show up. Yeah. For sure. I think I mean, one thing that is probably, a good bit of context to kick off this discussion is just to go through what the current sharing thing looks like and what it does, and some of the requirements that we know exist around sharing things in general. And then sort of take it from there and elevate. Okay. What do we do to then unlock, you know, create and update and delete access next to just read access. Right? Because there's a reason we just started with reads and not the other ones. And that's that's sort of the complexity that I like to extract in in this session. Speaking of complexity, I found the quote that I was looking for. And the quote is in the discussion itself is, the feature itself could start very small, but it could be very complicated if we wanted to cover more use cases. That's, like, literally every single every single feature that we could ever do. That's the request review format for you, isn't it? So for those who are new in this session, one on good bit of context for what these live streams are all about. We just wanna take, you know, the discussion as it exists. Divergently think about, okay, what are all of the edge cases? Find sort of the use case, find all of the unknowns, and then take it back down. So, like, what is that MVP? What is the minimum viable product that we wanna ship for this to be a success? Right? What are the must haves? What could we add in the future? Where do we wanna start with this? Right? It's easy to say, oh, the the forms that you're sharing, just make them create access. Right? Done. But there's a lot more stuff going on into the hood as per usual. And also for the first time in days, we're getting some sun in here. So excuse my exposure. Oh, we got some interaction. But, let me let me give let me give another example because there's many, many different use cases for public forms. So it's not just about, like, let's say, you put an email in there and a text box or something. It could also be more involved, for example, inside of your organization because directors is often used as a, like, enterprise tool inside of your company, for example, in the Internet even. So you could build a support ticket system in Directus, and we know that people do that. So, a public forum could be you visit a site inside of your Internet with an extensive, like, public forum describing what issue do I have, what department is this in, when did this happen, is this critical or not, other descriptions, related persons, or whatever. I mean there's also like very often for marketplaces or adding data to a validation queue because this is, like, very, very often the case. For example, if you have a marketplace and you want to open it up to new, merchants, they have to apply somewhere. Right? They they have to they have to ask, hey. I am this merchant. Can you please add me to your, shop? Or there was another example inside of the discussion itself regarding, let's say you have, like, a lunch app or whatever where you can off order food. So you want to get more restaurants or or bistros or whatever, and they can apply at your place. So you give them a public form. They can enter their information, and then you have, like, inside of your validation queue, all of the people or entries that you could go over and then, make sure that they get applied to your public to your service. Alright. Sounds like one of the the initial requirements that you're sort of sneaking in with these examples is that this form can live both as a public website page in your direct instance or as an embedded form somewhere on your website. Exactly. This is We're we're immediately diving in, and we're off. That that is that is literally I I wrote this down. This is exactly what I was, coming up with now because, like, the first the first requirement that kinda diverges, like you said, is, okay, so I have this public form. Where is it? Where where where can I find it? Because, like, it really depends. If I send somebody a link via email for example, it could be sufficient if the link is directly to your directors instance and you get served up like a complete page. And, there's the whole thing with the logo or whatever. And then you have an entire dedicated page for it. But very often also, you would like to embed your form into your existing website. Let's say with the with the, contact form example. Right? You just want to have a little contact form and on the bottom of your website. But, yeah, then then it starts then it starts. Okay. So you can have 2 different ways. Yeah. I was gonna say, let's start let's start with what we have today. Right? So we don't have, writable forms. Let's call it that forms you can change stuff in. But we do have sort of the shared form where if you open a single item in a collection, you can share share that item. And what that does for the folk who've never tried it, which I believe is most, is that it will create sort of a temporary role, so to speak, a temporary access token that has access to just that one item with the role permissions that you associate to the share. So that sounds a little confusing, but that basically means you can give away a link that contains, you know, basically a long obfuscated URL that gives read access to just that one item and the relations that it has based on the rule that you associate for read permissions, Then that public link, it's, a directus page. So you will be navigated to your directus instance slash admin or slash shares, what we call it then for the public ones. And then, if you open that up, you basically get a read only state of the form that you just shared. Right? And there's some additional options on that share. You have you can set a password on it. You can set a maximum time, start, and end date that it's available to the public. Those those are the main ones. I think there's some other options. But long story short, the first step there is, like, if we were to just just enable a share on, the collection level, we can use that as a starting point, but that is only for forms that are then within that sort of share context of directors itself. Right? So you'd be able to use it as an alternative to something like Google forms or, type form or something where you create a form, you share it, you have a public page that you can share it, that you can, link people to. To me, the the fun complexity of this is really when it comes to, a, spam protection, and b, embedding it elsewhere. Right? Because somebody in the chat, our very own team just now, just half joking said just iframe it into your front end, which, sure, you can do that. But at the same time, somebody else in the chat also mentioned, you know, it would be great if there's a contact form on each of the products in my sort of web shop or or, renting, vending vending thing. At which point, you need to be able to dynamically inject some sort of default value into this form before you submit it. Now if we're talking about embeddable forms, it's almost like a different feature request. Because if you think about it, you could open up, write access to the public role and just build a form. Right? You can build a query you can build a form in your website and just post a request that straight out to, you know, your direct this instance. So, I think we wanna split this discussion up in, a, the shareable form, which is more sort of the Google form alternative versus embeddable forms, which is, like, what can we do to sort of make it easier to request or build a form indirect and then request it and display it just like that on your website? Because, also, how much control do you want to have regarding the styling, for example, with, like, branding? Do your inputs look different? Because, you know, it looks out of place. It could look out of place if, you use our design guidelines, but your brand uses, like, way smaller inputs. It just looks very weird then. So we also had a nice, suggestion for, by Tim that I like. Where is it? Oh, no. No. By by by Brian. By a nice, by Brian. Pre filling fields by query parameters could be very cool. And hidden fields, of course. Like, there are many, many, there are so many things that you could do because there's so many different use cases. Like you said, for example, if you want to embed it, do we want to a do we want to be able to also restrict, like, how many different links there are to that form, for example? So, if I have a email list and I want to contact all of my contacts and I I give them each a personalized input field because I want to avoid the spam issue that you just mentioned, you know? So let's, say, okay, I only want people to be able to answer the form once, at least, you know, on that link, for example. But can they be different? Should they be the same all the time? So using the form once, that's the part that we do currently support with the read only share. Right? Where there is a setting for how many times can this item be opened. And every time somebody opens that that item, it just, you know, it decreases the number by 1. And then once the number hit 0s, the link, you know, goes goes this disabled. Now for creates, how do you confirm that it was done by 1 person? Right? If you associate it to an email address or something, are we gonna do email validation? Do do does there have to be a confirm step? Which is sort of like I'm I'm thinking about other forms I've seen in the wild. Right? Where it's like you wanna sign up to a raffle or something and you leave an email address and that's your that's your ticket, so to speak. But you can only use it once. Yeah. Somebody in the chat rightfully now at that point, aren't you just logged in to the app anyways? Because now you have some sort of an account or a verified account within that direct to this instance. Maybe. Maybe. Right? Hard to tell. Well, I think the other the the question that closely ties into this as well around things like CAPTCHA. How do you prevent robots? How do you prevent AI from just pulling up the form and spamming it to death? Right? Of course, an obvious one for a lot of folks like, oh, just smack a a Google recap on that and you're done. But, of course, this wouldn't be a direct this request review chat if it was that simple. Because there's a lot of sort of like wrecking and accessibility concerns around, CAPTCHA as a whole When it comes to Google CAPTCHA specifically, I I I'm a little fuzzy on the details, but I'm pretty sure there were some GDPR concerns around embedding Google services as a whole, that already requiring, you know, cookie notices and whatnot because almost every Google service will track you to bits, if you embed stuff on your page. So that's a concern. It also relies on a third party service, which is something that historically we have to be a little bit careful with, because we wanna support multiple different options. Right? But now here we go. This is the point where now we need to think about how do we have a standardized CAPTCHA system that can work with providers that works across form, right, for both shared forms and into and, like, in internal forms. Another question from the chat. To add some more complexity, who creates the public form? Is it an administrator or a nontechnical CMS user for whom setting up a form with the data model interface might be overwhelmed? Another great question. Right? So in in the direct to this model form is basically tied to your data model. So if you share an item, you share the item that you're seeing with somebody else. Right? So in its simplest form, you would share the form that you're currently seeing with the world. Is that what you want? Maybe not. Probably not. In Daniel's example from earlier, if you wanna do a simple tech form with just an email and some text, it's very likely that in your data model, you end up with a status field that says has been responded yes or no or metadata that you wanna have in your system. But how do you differentiate between the 2? Are we gonna ask the user who is sharing the form to then pick and choose fields to share specifically? Are we gonna attach it to another role soon to be policy? Or are we gonna, or or plan c is, are we gonna strip public forms from the regular content model altogether and just have a whole different section somewhere that says, here is public forms. And then perform, you just have to configure where the responses are saved. Yeah. Regarding your point of configuring specific fields like the status, for example. Like, if somebody submits the form, should it be, you know, active, reviewed, tool review, draft, or whatever? So that that really sounds to me like a field preset sign type of thing, but that exact same vein. Okay? Let's say you have a form with a user created field that automatically adds the user that created that row. Okay. What do we put in there? Who who who created that? I mean, the user could, you know, make their own public user, so to speak, and link them via a field preset, but then also kind of fields just not quite thought through. Like, to me at least, like, just thinking about it right now, like, it feels, like, so hacky that people would need to do that themselves, that it feels like this is not really thought through. But on the other hand, like, do we want to have, like, a global invisible user that we could reference? Maybe. I mean, we do have the concept of a public role. So with the user created example, it would be null because there's no user indirect because that created the thing. So if we if we zoom back out just a little bit, I think the first question that we sort of had this session hey, Jonathan. Welcome to join you, Just to catch you up. The first question was, shareable forms versus embeddable forms. Right? Which is a shared form is basically the way I see it now as a page within Directus that you'll to, and they just get, you know, a nice looking Directus connected to stuff. It's safe. Done. Little you know, think about Google Forms sort of mentally, that style. Right? The second thing is some sort of UI component or some sort of auto generated API endpoint or maybe just a public post could be, to render a configured form and direct us on your own app or website in whatever way is appropriate for your tool. Right? To me, those are 2 separate discussions. I think we start with the shareable forms because then the embeddable forms could use the same permission system and shared, configuration from the shareable form to then embed one of the shared forms. Right? That's kind of what I think that that would be a 2 step 2 step approach. Nope. I like that. So that's what you're seeing here. Right? So this is the current it's read only at the moment. Hard coded is read only. Even though we allow we've kind of plumbed this for role support in the future, it's currently read only. It's hard coded read only. So you get a read only form that looks like this, and it is to a degree, there are some permissionings. So the role does give access to the fields that are available and the relational content that's technically available and visible in the form. So you can see here my image isn't showing because I don't allow I haven't allowed the permissions correctly on that particular role. So you could have that kind of capability, And I believe we should I haven't tested this, actually. I because I'm logged in as an admin right now, but I think we can restrict the role list here based on the so the the allowed roles and permissions for the user. Permissions again? Yep. Exactly. So permissioning should control what's available in this list. So I think, again, I think the general plumbing is there for a shareable, editable form? The question becomes, what is it that we're sharing? You know, are you allowing them to create a an item from the form? What does that look like? Because right now, we are sharing an existing record. So there'd be work to be done around that, I think. Absolutely. As an embeddable I like the embeddable idea. Technically, you can kinda do that already. You know, we we see examples of that in the structures that, our good friend, Bryant, has set up where, you know, he set up these kinds of forms where Right. He's almost replicating our schema management capabilities of being able to create an editable form. So he's made it so that you can create a schema field, add whatever, you know, value type. This is a And as we're talking segue into, the second question I wanted to bring up, which is for shareable forms, are we sharing an existing form and you will still limit it down. Limit it down. Or is it effectively a separate form builder where you can create one of forms that you then connect the dots between that and your actual data model? Yeah. Similar to I think our our CRM has that kind of capability where you can build a form. Right? And then behind the scenes, the data gets stored wherever you direct those fields to store. Exactly. But you've got an and it's embeddable as a you know, you can get it as a link or you can direct them straight to the form or you can embed it as an embeddable link underneath the hood. Because the one thing I do recognize about the current share system is that it's a little bit a little very opaque. What's the right word? It's a little opaque to to know what you're sharing. I mean, by default, you're sharing what you're seeing. Right? It's like you're sharing the item that you're currently seeing. Yep. But what's actually gonna be shown to the user is different. Right? So you have to go check the link and see what it's gonna look like versus It's because it's based on the role that you then associate with the share. So if you use your own role, it's what you see is what you get. But other than that, it's a bit of a, you know, to your point, you have to create the share, pull it up, double check. If you're creating a dedicated form to share, be it read or write, that confusion is taken away immediately because it's the form that you created. It's the form that you're seeing. Right? I think the big question then becomes, how do we handle permissions if at all? Do we auto generate the permissions based on the stuff you put in the form? And therefore, you make it very explicit. Like, you put, an email address field, so therefore, you can see an email address. Or do we make it a little more opaque again by associating a role or multiple policies to TM to control the permissions for that shared item. Right? That's that's where it's a little finicky. So when when I meant that permissions, for example, if, where permissions become really important is for nested relationships. Right? So if you have a read item with a many to one field to a related category or something, what part of the category are you also supposed to be able to read from this entry point of the top level item? So having some sort of permission set there is gonna be required. Because otherwise, theoretically, if your relationships are a little complicated, you could pose a hell of a lot of data. Right? Because if we were to say, auto generate all of them, if you have a user created field because you just wanna show somebody's name, avatar, you could now theoretically go to that user record and you go to a direct to files record because you now have that connection through the user. Right? So that also, makes me wonder, there's another feature request that is completely unrelated to this, but it might actually directly be related now. One that I opened, I feel like 20 years. It's configuring access control permissions based on a parent child. So instead of saying, you have access to direct these files, you have access to direct these users. It's saying the permission, you can read a file if it's attached to a user if you're coming through the user and only then. Oh. Oh, yeah. Yeah. Yeah. Yeah. Yeah. That's, that would be very cool. That would be very cool. Top the clock. I think we need to need to start a new game. It's like, at what point do we get Jonathan to do that? It doesn't take much. It doesn't take much. Because because that would that would also potentially solve for this. Because then you could say, okay. If you have many to 1 on the record that you're sharing, you now have access to read just that one record from the related table, but nothing else from the related. Right? And for the record, that is how the current share system works actually under the hood. It is a hell of a lot more complicated, because what it does is it looks at the item that you're sharing and it checks what items are related, and then it makes a new permission set that says you can read just that one item from the related table. Right? But all of the other API ends work the same, which is interesting. But that's that's the way it does it right now. So it does actually, you know, specifically look up which items are related, which items are shared as per the role, but then lock it down to only allow you to ex that one particular item that is associated to the shared thing to make sure that we don't overexpose data in your system. Food for thought. But it it, you know, we're getting real quick into the weeds here again. Just from the question, is it sharing the existing form from your data model or are we sharing new one off forms? It sounds like and I've I've it it sounds like we probably wanna look into some sort of system. You can create individual forms and associate them back to your data model. Just in those cases where you wanna have multiple different forms with different fields that go to the same item. Commonly the case. Right? So if I was setting up a, you know, a a newsletter subscription, I might have very simple, but I still wanna register the contact. I still wanna be able to, you know, track their compliance or other things that I may wanna track or need to track versus the same contact information I would collect for a you know, you're signing up for a meeting or a webinar or something else. So the the forms can be storing data to the same places or to additional places. Follow-up question. What is that? One of these public forms, and I'll I'll get to Tim's question in the chat very soon because that's another level of complexity. But should we allow one of custom forms to save to multiple tables at the same time? Yes. Technically, yes. Form can one form create 5 different records in 5 different tables? Oh, I think it must. Right? Because of relations? Well, not even relations. Go Independent of relations. Right? Yeah. So if I'm if I'm setting up a form to collect, medical data, you know, to sign you up or set you up or do something or I'm collecting a survey, I might have survey information that I'm storing in the survey table, contact information I'm storing in the contact table. Just simple example. Right? Just 2 tables. But the contact information is in one place, the survey data is somewhere else. And I may from a from a compliance perspective, I may not be associating the user. I'm just tracking that the user responded, but the survey data has to be independent. Right? No relation at all. Here's one quick question. Good point, but Tim, wait beef before we go further further down the rabbit hole, there's another good point by Tim. It it it really sounds like a job for a flow or hook. And I think I agree, actually, because, like, the complexity then of setting it up and then the UI that has to be added for that and, stuff that could go wrong and stuff. Like, maybe, you know, just as a as a simple example. Okay. You have you just make one row in one table. That would that could be the cutoff that we decide on, maybe. I don't know. But it it really sounds like maybe a hook or a flow would then should be responsible for, you know, taking the the depending on the status, it takes the user's email and puts them also into the contacts table or the whatever table. I think I agree with that take. How do you guys feel about that? It's both ways because you could say you'd save all the data to a table and then run the flow based on that change or you save the form to a flow and then handle it yourself. I and I think there's a case to be made for both because for a simple contact us form that is always going through the same table in the same format and it matches your data model, it feels like flows could be a lot of, you know, complexity to configure just for that simple use case. But for everything else, I fully agree. Once you go, I wanna touch 5 different tables and I wanna submit to a different web, and all that kind of stuff. Yeah. Form to a flow, makes a lot of sense. Right? Right. So let's blow up this, let's blow up this discussion further because Tim also said, alright. How about, should public forms be able to save to a specific content version as well. If you call the first deal with the safety of a specific content version. Well, the nice thing is if we're going with this whole form safe to flow as idea, then sure do whatever you want. Right? That's that's kind of the beauty of the escape hatch that could be flows as the back end forms. Because at that point, if you wanna save it to a conversion, go for it. Right? What do we care? What when how when would you use that, though? Let's think about that for a second. So you have draft state basis for an item. I guess if you were updating existing content, you may wanna do that as a version, possibly. Typically, in shareable forms, I don't see it as a version necessarily. But if you were allowing someone, say, to update but even then revisions would track the the content changes over time if you were inclined. I I think yeah. What I was just about to say is what Tim again just put in the chat. Let's say you want to review and approve the changes that were made in pub. Right? So if you're running a sort of Wikipedia style, Wiki style, page Mhmm. And you wanna allow people to suggest edits, you could have a public form to update that one particular page, and then those updates go into a version that then can be reviewed and approved by the old person in charter, which is an interesting an interesting use case. That's a cool that's a cool freaking use case. Which actually would be very convenient for our own docs for that record. For example, that's what I was thinking about. I have the little button on the bottom here. Edit this page. Edit this line. That would be very cool. Hang on. Another use case from the audience in, in that updating existing thing from, Jay Shue says, another use case is a business directory and the users being able to suggest changes. Agreed. And the Durb saying we could actually use that fairly well as well. That's it. It could be implemented in flows. Right? Which is where it gets interesting again. Right? Because flows really become that sort of escape hatch for this type of stuff that, like, oh, you wanna save it to a version instead of to a table? You wanna save it to a different whatever you wanna do. Just use a flow. It it does also answer the question, is this just for create or is this also for update? And I think we've just concluded that also updates are important. Click updates. That's when you can do you can update an existing submission that you've already done, or you could, you know, the Wiki example or the business directory example or some of those. Yep. I think about, in particular, things like, you know, some of these online forms could be fairly complex. Right? I've I've done this. I've I've got you know, you're filling out something for a financial thing and you, you know, it's gonna take you an hour to do the form while you may be saving and coming back later. You can come and go from it. We do a lot with secured online security forms, you know, where we're filling out answers to complex questions that take hours or days to finish. And so, essentially, saving state and coming back and making updates and, oh, I mean, I I wanna fix that answer that I did, you know, 3 pages back in the form, and I wanna go make that adjustment. I think we found another use case for the saving it to a version. Mhmm. Because if you save it to a version, the validation of the database doesn't have yet because it only needs the saves to the database rather than to your stage to changes. Right? So the, what would you call it, plausible forms where you can enter a bunch of stuff, hit save as draft basically, and then come back later. That would be relying on content versioning. Good. Yep. Good very well. Doesn't have to, but it could. Right? You can manage that via state or status or other things as well. But, yeah. Unless you're thinking about validation in that case. Right? If you have data integrity rules that say the column cannot be So in your form, it has to be filled out. But you don't want the force to use the whole form once, you need to have an in been safe, which would be, you know, a version conversion version. I like it. It's Okay. Let's I need to switch to a slightly simpler question. Otherwise, my brain is gonna go What about deletes? Is Is that a thing you do publicly? My first gut reaction was no. Hell no. But, let's give it a little more thought. But I guess if it's user data, I don't know. I could see a use case for it. I don't I don't think from our side of things, if depending on how it's implemented, If you got compliance issues, GDPR, other kinds of things where the user has the right and choice to do that, that's that's gonna it's gonna be very use case specific. Because for the case we we try not to delete data in general. We put it in the soft archival state. You know, we use status or other things to handle that. But where you have compliance requirements where you must delete, But I don't know if that's a form. That that could be flows driven. That can be log business logic driven at that point as opposed to something to do with the form itself. I think you'd have to have a form that says I wanna I want my data to later. I wanna unsubscribe. And by doing that behind the scenes, the flows and data data management happen the way that you need them to happen. Right. Because I I could imagine that the because because deletes blank at least sound kind of insane. Because you would have what? You would show the user, here's all the records and go whichever delete whichever one you want. It that that feels like not something that you'd realistically want. But I could imagine that if we connect it to an account again, not not so much a a direct as app account, but, like, the moment you create a form submission, I could imagine that you maybe wanna do a public read of a layout. Here's a new question that we're gonna discuss in 5 minutes. Where you can just as a user as a temporary user all the submissions that you've done in the past and then delete a previous submission. To me, again, business logic. Right? That that tends to be not so much I I think you'd I think someone suggested it here. I think you'd do it as a delete request. You'd submit a request to delete and then confirm whatever mechanisms. Your your business logic, your flows, your your any additional code processing that you're doing on top of that would handle those things and send notifications accordingly. Feels very much like you would submit that as a specific form request to remove data, not the ability to delete data from the form. I think I agree in general that that shouldn't be allowed. You'd have to submit that as a separate form, maybe. I don't know. I'm sure there's a use case that I'm not thinking of. But Yeah. But to your point, if you create a new form that triggers a flow rather than saves to a table, that flow then just deletes it, whatever, based on your business logic, then prop solved. Right? You you don't necessarily go the mile to Yep. Have native victim delete support for that specific of a use case. Okay. Interesting. Interesting. Interesting. Interesting. Tricky. Tricky. Tricky questions. Tricky questions. Another another question in the chat here from user. So what about editable forms or relational data where items can be deleted after it's been saved and the user edits the data? We got it. Ladies and gentlemen, we got it. That's the real goal. If we can get right to do it, then we're then we're successful. What about editable foreign situational data where items can be deleted as it's been saved and use it as the data? I mean, I guess that kinda goes for any editable forms that it's like, user creates it, admin changes it, user tries to edit it, and that looks different. Which, yes, it will look different because you changed it. You changed somebody's submission. Right? I think that becomes becomes more of a workflow or a business process, thing where tell your staff don't touch, you know, don't go changing somebody submission. That's bad mojo. But I guess yes. What about resubmitting of shareable forms? We're kind of in the midst of thinking this through because, in the beginning, we said, okay. If you have a fixed link that you can send somebody and then they submit the thing, we could restrict that you can only submit once with that link. Or you can have a general link where, like, every single submission results in a new row every time. But then it's very use case dependent, I think. No. Like, that should be just configurable. Okay. Is this, will this result then in a on on my second visit to that link, will it show me the actual item, or is the form empty again, and can I resubmit it? I mean, that's, like, very dependent on on on the configuration, I think. Yeah. I think it should be doable, though. Some additional configurations here, potential validation checks. So, again, if it's an embeddable form or it's a shareable, editable form from our side, then this is gonna need some updating as well. Right? We'll need some additional parameters and things here. You'd have to potentially check the data, validate the data on save. Flows, again, can handle some of that, but to give the user feedback of you've already submitted or disabling the form because they've already made a submission. How do we check that? What does what does that look like? Because now you actually have to have something, you know, activity wise that says your device or whatever has been registered. We know that it was you, and you've already submitted the form. Yeah. That gets that's where I I don't know. It almost feels like that should just be front end dev work and get managed from that side of things. But Oh, here's here's the problem though, Jonathan, when it comes to the form that we're sharing, who's the front end dev doing the work? It's it's us. It's us. It's us. I know. So this needs more complex kinds of things because now max 5 uses, well, is that 5 users, or is that 5 you know, one person could submit all 5 or use all 5 values. Right? Is a user? What is a user? Right? What is the Are we getting deep? What am I I mean, that's that's kinda the question right now. I think about like same thing. We we track this on, you know, AppSight anyway, but now we've got this floating thing out there that would also have to track an activity record of who the IP and device and things are and be able to validate against that as part of this form configuration or this shareable form configuration. Now it's, you know, one time per user or per IP or, you know, whatever we consider that to be. There'd be something here, you know, max uses. So I want a 1,000 submissions, but then I wanna be able to also say per something. The the problem of the the how do you confirm the per something? Because you could say you could you could I mean, you could get away with it by just having a unique column. Right? That it's like you can only have one submission with this email address, and that's it. Done. It could be unique. Already exists. Can save it. Done. Right? But how do you prevent somebody, you know, with a Gmail account, for example, you can do the plus something something and it will come back to you anyways. You prevent somebody from submitting times with the same, you know, plus 1, plus 2, plus 3, that will work. And I can use all information still. Because there's no way for us to validate that. And then, you know, for email specifically, you can start thinking about, maybe we have some sort of email validation or we send an email and you have to click confirm or all that kind of stuff. But then what happens if you wanna use something else as the unique identifier? What if you're doing some of the phone numbers? Right? Where it's like, enter your phone number, we'll send you a text when it's your turn to to for for like reservations. Right? If you're doing a reservation at and it's it's that's that's very common around here. I don't know. Over in your parts of the world. But, you know, if you go to a restaurant here and it's full and it's like, oh, your your table's gonna be about 40 minutes and you your phone number, they'll send you a text when it's ready. Right? Mhmm. Or about 10 minutes before it's ready. So in that case, you wanna duplicate it on the phone number, but how can you confirm that? Right? You you can't really, there's no way for us to know that. A simpler a simple example would be if if you have first sorry, the delay delay is giving us. No, but but a simple example for, limiting that kind of, use would be, let's say you have a form that you can resubmit with, let's say, you have an online shop and then you want to use this for functionality for giving out promotion codes, and you only want to give out a 100 promotion codes, okay, Then it's just a matter of counting the rows, you know, so so we don't have to have a unique field or whatever. We just say, okay. This form can be submitted 100 times. That's it. I think there's like, it's a little different to your guys' use case, what you just described with the email and and phone and whatever. But, I mean, this is also a valid use case, I think. You know? I I want this form to just be usable for 100 submissions. Okay? Then it's just a matter of counting. Mhmm. Well, that's our that's already built in. Right? So we already support that max five uses. So and we keep track. Similarly, if we want this to be 1 per or 2 per source, right, then we have to actually track from a and, I guess, because it's an embeddable form or it's a, you know, we we have information and knowledge about the browser. Right? We we can track that. It just requires that we store the activity information and utilize that as part of the additional values here in a sense. There's still ways around. Right? There's always a way around. I've got 5 devices, and I wanna submit 5 submissions. You know, I can I can do that, but and and, you know, we can do things like enforcement of uniqueness on the values coming in and those things? That's already there. It's more about can I at least track to know that this user has already submitted a form because of their IP address slash device ID, that we track anyway from the browser cookie side of things? I think, I think I'm reaching the same conclusion as Tim. It's like we're going down the bot detection rabbit hole, which is like, can we fingerprint an individual user? No. There's no way. There's there's no way because IP address is shared with the location. So, therefore, everybody in the same household or the same business is gonna have a similar bound IP address. So that that doesn't work. I mean, this this fingerprint in question has been a cat and mouse between browser makers and, you know, back end implementers. It doesn't exist. The only way to do that is to require a sign through some sort of secondary authentication method, like send you an email with a magic link. So therefore, you prove you have access to the email, and that's it. Right? Before it submits or text with a phone number, that kind of stuff. Or log in through an SSO provide to confirm your, you know, your identity there, which actually is a different question I didn't even think about. But it would be kinda nice if you could sort of, like, connect the dots between what is your GitHub account click here to to o auth your way in to confirm, but that's not gonna be a 5 minute conversation, I don't think. Another question from the chat here, from from user and I'm gonna butcher your name. Sorry about that. Mama. That's what I'm gonna go with. How about the ability to show already submitted values to the user when filling out a form? Thinking about a sign up form for a party, and showing what food others already bring with them. Which is so this is an interesting question, which I think is not so much, the shareable, writable form. This is the question of readable lists of items. So right now, the share that we offer is just for a single item. You share that one. Right? What we don't allow you to do yet though, you can go to a layout and share the whole in a simple fashion. I could imagine that for this particular use case, what you would do is you would basically make a public share for your record of foodstuffs people bring to the party, long collection name, and then you can give people that link. Right? And then when they go there, they just see a layout like you would expect from directives with all of the stuff that has been previously entered with a click to to open an individual, I imagine, and then a, you know, a plug or something to go to the create page if you have create permissions through that public share. I think this is actually related to Hannes' question as well. More so because the food items being brought can be a many to many or a relational junction that's already there. So we'd show that in the current form. Right? Just like we did, you know, I only have translations in here right now, but equivalent kinds of things where you've got a a relational structure. The real question becomes when you're adding or removing relational items, this is considered potentially a delete operation under the hood. Right? So there there's there's a little bit of a tie between the delete conversation we were having and this ability to show or allow or not allow you to you know, you might be able to see what other people have brought, but you can't remove their food item. You can only add your own food item. Right? And or remove your own food item. I think role permissions generally work correctly for that, but it becomes a question of making sure that you test and set those things correctly. But is that considered a delete? Right? If you've got a cascade operation on, you know, removing a a relational item, well, that's potentially gonna cascade and cause a delete down the line. I think that would always be a deselect from the relational perspective. The Well, that depends on what you set your permissions for. Right? Oh, it's what you do. It's not permissions. The field oh, I guess it's what you set your field settings for. Right? If you set by default, yes, we set it to nullify so we don't actually delete any data. But if they've got cascade delete permissions, you know, if the cascade delete is turned on, that's going to actually delete data or contact. Point. Yeah. So the that's here's the security vulnerability way to happen. If you have an edit access to a simple item with a many the one many the one is configured to delete on select. If the user edit the field and they deselect, they now can theoretically delete stuff in your database, which is fun. Alright. Oh, jeez. It's already we're very we're already on on the dot here almost at 11. Oh, yeah. 11 for me. Times for everybody else. Just to to summarize all of this, because we went very much like this, but not a lot like that yet. We're running out of time. I think some some initial conclusions as far as I sort of take it now from this session. Right? It's like there's definitely a difference between shareable forms and embeddable forms. Shareable forms is part 1. Embeddable forms can then reuse whatever configuration that has for embedding stuff. I think that's conclusion number 1. I think to me, conclusion number 2, it's ideally you can create forms separately from the data model. Model. Although, that is quite a bit, you know, more involved to build and experiment with and etcetera etcetera. I think starting with create access is the most straightforward as you don't have problems with who can read what, how do you update previous submissions, how do people know what submissions they've previously done, etcetera. So in order of operations, shareable pages create first, then, read access for a listing would be very useful because then you have a way to click into an update item there. And then I think as a sort of your v 2, we should think about what do we form creation to look like in the first place and how does that tie into sharing? And a different question is, should sharing even be tied to collections and items, or is it just pages in the app altogether? Because I can also imagine that there's other places, like, folder in your file library that you might wanna share. Don't know. Like, another feature request for a different day, because I got skipped is, what about shareable dashboards from Insights? That'd be cool. But let's not do that right now. We'll save that for a different session. For now, Daniel, back to you to close it out. Thanks everybody for coming. If you enjoyed this discussion or are interested in other discussions, you can head over to directors. Iotv where you can find lots of other interesting shows and also this one. And, we hope to have you to see you again.","51185b87-e60a-4d5d-bf15-e09c4755ddd1",[290,291,292],"3eb120ac-4151-41d7-912b-e93b6568e197","93e88d6a-6f8d-4006-8efe-b1297a350658","901b7577-4fbf-48e6-84bd-f18438989693",[],{"id":133,"number":134,"show":122,"year":135,"episodes":295},[137,138,139,140,141,142,143,144,145,146,147,148,149],{"id":143,"slug":297,"vimeo_id":298,"description":299,"tile":300,"length":301,"resources":302,"people":8,"episode_number":306,"published":307,"title":308,"video_transcript_html":309,"video_transcript_text":310,"content":8,"seo":311,"status":130,"episode_people":312,"recommendations":316,"season":317},"email-translations","944604881","In this recording of our live event on May 9 2024, Daniel, Jonathan, and Kevin discuss making email templates translatable","cf94e330-0c7e-4998-a002-a8df236def76",47,[303],{"name":304,"url":305},"Discussion","https://github.com/directus/directus/discussions/8239",7,"2024-05-16","Email Translations","\u003Cp>Speaker 0: Talk about what this feature is.\u003C/p>\u003Cp>Speaker 1: I'll I'll I'll in I'll intro because Daniel's gonna have to do all the hard hard work to do.\u003C/p>\u003Cp>Speaker 2: Oh, no.\u003C/p>\u003Cp>Speaker 1: So, we initially I think this was initially flagged as the make email templates translatable. So currently, especially for the system templates, not support translations on those. So things like your invite email, those are kind of hard coded as English only. You can do some things with the liquid templates, but even those are without some work are not really translatable. Mhmm.\u003C/p>\u003Cp>So the content, you have to do some variableization. Now with flows, I think with the advent of flows, you can do some things where you look up the data, pull your you know, based on content or other things, but be nice to make some modifications to the way that this platform is working to use either, the current translation strings or other capabilities, the translation solutions, interfaces on the platform itself, find a way to solve this problem so that emails can be multilingual more easily. So that's our goal. But I also saw that there I I found this that actually has an RFC spec. This was our our lovely CTO, mister Reich, creating this one liner, back in the day before we hardenforced RFCs.\u003C/p>\u003Cp>But then someone actually did a nice write up, and they referenced this particular ticket along with some other things. But they had some other capabilities on some event hooks and user invites and some things to actually extend the capabilities of the email solutions a little better. So we thought we'd use this as our our driving factor since it actually has RFC and it references the email translations. So that's the goal today, talk about how do we make the emails, the the platform emails, as well as other email things more easily translatable and easier to use and extend on the platform. Miss anything, Daniel?\u003C/p>\u003Cp>Anything here?\u003C/p>\u003Cp>Speaker 2: That's a nice, initial summary because, the pain of actually having a multilingual app, comes up quite quickly. As as soon as you got a couple different users from a couple different countries, you're you will run into this. So, this is largely only a problem for multilingual apps right now because, as of right now, you do have the ability to override our system email templates. So, technically, if you only have one language, you could just go into the, email template folder. And I even have looked up a link beforehand that I can share with the chat because I'm so organized, apparently, at least today.\u003C/p>\u003Cp>Speaker 1: Alright.\u003C/p>\u003Cp>Speaker 2: You may head on over to our docs under self hosted email templates, which will help you get started with how to do that. It's very, very simple. You have a template folder where you can put in the, the liquid template file, and you're basically done. Depending on what you want to do, of course, you know, you can make it more complicated. You can expand and expand on it, or add other functionality with your instance.\u003C/p>\u003Cp>But, technically, if you only have one language that you would like to serve, you can very easily do this. It's no problem. And even for the very, very, very brand new feature that was released this week, not sure how many of you guys have seen this because, I did a little thing with the help of the others, of course, because public registration also uses, an email template that you can override yourself. So that's the thing. You can expand on it, but as Jonathan said in the beginning, yeah, multi multilingual apps have a problem.\u003C/p>\u003Cp>Right? Like, how how do you do that as of right now? There's different, routes that you could go down on. Maybe just the the most most naive way would be to have a template per language that you just prefix with the ISO code of the language, for example. This would be the most naive way that I would not recommend, but, technically, we could do that just as a you know, to throw it in the room for discussion right now.\u003C/p>\u003Cp>So we could do that. I wouldn't do it that way, but, technically, we could.\u003C/p>\u003Cp>Speaker 0: One thing you mentioned, Jonathan, is you can kinda hack around with, if you build custom templates with, like, liquid tags. Do you have any more information about that? I'm not saying it would be an ideal approach, but how might that be approached now?\u003C/p>\u003Cp>Speaker 1: So liquid is just a, you know, a templating language, and you can you can grab templates in the flows as part of the email, service, that email notification service operation. And I believe if you supply variables, you can actually swap in the variables. So you could in in your Are you\u003C/p>\u003Cp>Speaker 0: using translation strings?\u003C/p>\u003Cp>Speaker 1: Look up the look up the multilingual contents, you know, store your your template data as a record using the current translations interface. So if we were to box here. I think in this particular demo, mail, settings, email templates. So if you were to set up, like, an email template like this. Right?\u003C/p>\u003Cp>So you can you could make this data driven, where instead of having this body here and the subject here and the name here, you could actually put those into a translation's interface, using the existing translations capabilities, then you manage your content. Now at this point, I can use a flow to grab this data. Now it doesn't work, I think, as Daniel's kind of referring to user invites. You'd have to do your own custom user invite and handle the, you know, on authentication or allow public registration kinds of things to do that. So to send a nonce you know, those are kind of system emails.\u003C/p>\u003Cp>Now we can override those with a liquid template. I'd have to play around. I think if we created a liquid template with variables in it, I think you could potentially use a flow to inject into that and swap in the multilingual from something like this, where I have the content lingually translated. But I don't have any testing.\u003C/p>\u003Cp>Speaker 0: I mean, you're talking about a naive way of doing this to be to have a template for each language, but why would we not simply store the contents of the email as a string in our translation files and then use that dynamic value? Surely, that's the the optimal way to do this. No?\u003C/p>\u003Cp>Speaker 1: That's That\u003C/p>\u003Cp>Speaker 2: would have been the better way that I wanted to to get into now.\u003C/p>\u003Cp>Speaker 0: Good.\u003C/p>\u003Cp>Speaker 2: So the like, in the beginning, I meant, like, the most naive way just to prefix every, email template with, like, enus.template. Liquid or whatever and then called it in every single language. Like, this is the most naive way that I could think of. But, as you might have guessed, by me emphasizing naive is it's very naive. It's not good because we have a very, very nice, crowd and integration for all of our translations for the app.\u003C/p>\u003Cp>So it would be very cool if we, instead of making every single template, store the languages directly, we would store like you suggested now, we would store every string inside that we want to translate very similar to our app translations. So we everybody from the community can what what's the what's the Crowded. Everybody can profit off of the, yeah, of the community's breadth and and width. Like, we have people coming from everywhere, every language. So it would be nice if we can do that.\u003C/p>\u003Cp>It's also for anyone that does not know this, head on over to no. I haven't. Oh, I have I have actually,\u003C/p>\u003Cp>Speaker 0: Locales. What what we're doing? Locales dot directors. Yeah.\u003C/p>\u003Cp>Speaker 2: Yes. If in case anybody did not know this, you can head over to locales.directors.io, and you'll see our app translations. You can contribute, can add your own. Take a look. Yeah.\u003C/p>\u003Cp>This would be a better solution to the email problem. So we can, automatically generate and pull in those, from user contributions. That would be very nice.\u003C/p>\u003Cp>Speaker 0: But there is something, you know, digging below the surface. That'd be fine for system emails. Like, for system emails, that's totally fine. Just use these. But scratching one level below the surface is the ability to act is to use translation strings maybe in custom templates.\u003C/p>\u003Cp>That's the one level on because I feel like the solution to make email tran make email templates translatable is fine for system emails. Like, that we have an approach. We have a you know, we have something. We just need to not hard code the values in English. But there's more than that, I suppose.\u003C/p>\u003Cp>Speaker 1: So I think that was one of the comments that was in the one of these tickets already. I think that was in here somewhere. Somebody mentioned that using the translation strings. I think it was the right somewhere along the way. But that is an option.\u003C/p>\u003Cp>Right? So to me, either something like this. Right? So you can do this yourself with flows for for anything non system email, whether we do the system emails in the translation strings here or whether it's in the actual crowd in files, because it's a system email, you could technically actually have that in all of the languages. I guess, technical question, how do I know what language to send the email in?\u003C/p>\u003Cp>So when I'm using a user invite, I guess, you set the language for the user, the default language for the user. Is that how you would manage that?\u003C/p>\u003Cp>Speaker 2: Yeah. For invites, I think it's a special case because you don't know the person. You could, under specific circumstances, not know what the person is speaking technically. But, like, for other system emails, we have the user. It's they are already registered, so you can just pick the language from the user or the default language of the instance.\u003C/p>\u003Cp>But for invites, I think we should fall back to the, default language of the instance Yeah. But also provide the opportunity to set a specific language inside of the, pop up. Yeah. Yeah. Exactly.\u003C/p>\u003Cp>Exactly. Yeah.\u003C/p>\u003Cp>Speaker 1: We'd add we'd add language here as well. Right? So not just the you know, you'd choose choose your role or whatever you're inviting this user to, but also have a language and set it to the default for the project as the initial. If If they wanna change it, they can choose from one of the languages. And, therefore, those things exist in the crowd inside, but that's part of the you don't have to do any translations inside the app for that.\u003C/p>\u003Cp>That's not a dynamic kind of thing necessarily. Although, if I'm overriding, then I still want. So that's something that we have to think about as well. Right? So where does this get managed, and how does this get managed?\u003C/p>\u003Cp>Crowdin is awesome for system, but the reality is I may want to customize the actual liquid tablet for this. And as soon as I do that, I'm now I now fall back outside of how do I manage the translations.\u003C/p>\u003Cp>Speaker 0: You know what would be really cool actually is if in settings, there was a a section called email templates, and our default ones were there and not deletable, and you could create new ones, and then use the built in director's translation interface to enable that. Like, that feels like a really nice flexible way to also potentially stop people needing to build their own liquid templates, like, as separate files and then load them into a directory. For many use cases, just being a just having a WYSIWYG with, well, a WYSIWYG would be plenty. Maybe with, like, a yield or, you know So\u003C/p>\u003Cp>Speaker 1: it it's this. This is fundamentally what you need is a subject and a body. That's all you really have to have for email. For the text, put this in as a, you know I I think again, the the trouble with making it a system side is I I also kind of want content users to be able to do this. So I'd I'd want my marketing teams or my whoever's to be able to manage the content in these.\u003C/p>\u003Cp>So in a sense, it would be a system user table, possibly, that would show up that you could make accessible to the content side. You could optionally make it as accessible maybe. We don't really we don't really do that with anything today. We don't we don't create anything here other than the languages table gets created if you haven't created it yet, for translations interface. I\u003C/p>\u003Cp>Speaker 0: I question that notion to a degree, though, because if you look at things like creating and editing flows, you can make exactly the same argument there. You wanna expose flows to more people in your organization, and we don't do that. I don't see why like, I think that that would be a bigger conversation about what is exposed versus what isn't and to what degree. So I I would be at peace with the idea that that is an admin setting, but I do get it. It feels a little more editorial perhaps.\u003C/p>\u003Cp>Speaker 1: Okay. That's a separate discussion then, really, I think. So one of because this actually came up this week. Somebody noted that if I make you know, I I'd like to be able to make some role editing capabilities accessible to a user, but not give them data model access or flow access or other things. So potentially being able to enable subsets of the settings for non admin users.\u003C/p>\u003Cp>So that's a separate discussion. But I do agree. I think email templates would be really awesome in here, so that I don't have to create liquid files or other things behind the scenes.\u003C/p>\u003Cp>Speaker 0: And you don't have access to the directory on professional cloud. That's the other big thing in my mind is, like, to really be a solution that works anywhere Directus is is hosted. It can't rely on dropping files in a persistent directory. It needs to be accessible via the data studio.\u003C/p>\u003Cp>Speaker 2: Some action in the chat. I envision being able to create custom email templates and sending it to a mailing service, specifically something something from directors. Could be separate thing, but would be good if it wasn't limited to settings page and flexible enough to support this.\u003C/p>\u003Cp>Speaker 1: The reality is, though, if I do want my own email templates, I could still create the user stuff for that, and I could mimic whatever was in the system. So, hopefully, over time, maybe there's additional system emails or things that we want for the platform. So we'd wanna be able to have those, and they could be manageable in the setting side if you wanted to replicate. Because Flows already supports, you know, grabbing things, you know, pull your variables, pull your data, pull your content. So, again, in this, like, agent c OS here, we have flows for, you know, sending the email.\u003C/p>\u003Cp>Right? So when you send the email, we're actually getting data from the trigger hooks and creates and posts and whatever, so we can pull in data from wherever. Right? So if there's data in a template or places that we wanna get it, we could do that. We can grab that ahead of the email.\u003C/p>\u003Cp>Speaker 0: Could you, show the drop down\u003C/p>\u003Cp>Speaker 2: link? Sorry.\u003C/p>\u003Cp>Speaker 0: Could you show the drop down again where it was marked down? What was the other option is attempt just in send email here. The other option is WYSIWYG or a template. Interesting. Because still in my mind, like, to be really flexible, you want templates to be able to have exactly data that is popped in there.\u003C/p>\u003Cp>So, yeah, I don't see why why you couldn't be authoring those indirectors.\u003C/p>\u003Cp>Speaker 2: You know?\u003C/p>\u003Cp>Speaker 1: I I think we should. I I think it would be awesome because having to go to liquid templates and have to have custom extension deployment capabilities or access to the server. Yeah. Not ideal. Right?\u003C/p>\u003Cp>So again, part of what I think this overall system flows discussion was about, in general. So moving away from the the simple thing that Raich put in here, this was a little bit more of handling this with some system flows and setups and management, being able to manage this from the front end as opposed to back end. So making it data driven. Right? The the things we enable for everyone else, let's enable this for ourselves and make this data driven.\u003C/p>\u003Cp>I love it.\u003C/p>\u003Cp>Speaker 2: Yeah. I I really want to go into that, issue as well, the system flows for, for the system actions. But, first, I wanna finish the other, message from the chat that was with the mailing service. Like, I'm not sure if I understand correctly because, like, this should be possible, right, with just the environment variables. You just define which SMTP server you want to use as an email service so you can actually connect to something else.\u003C/p>\u003Cp>And if you override the template, that is doing what you just said. Or maybe maybe am I missing something?\u003C/p>\u003Cp>Speaker 0: Maybe the ability to send them to custom places per run. Like, there's a few it depends what level of flexibility or abstraction you want to build in, but at its core, that's what happens with the email service In flows, at least.\u003C/p>\u003Cp>Speaker 1: In flows? I don't play with it much, but I don't think you get to choose your mail service here. Right?\u003C/p>\u003Cp>Speaker 0: No. No. But you configure that for the project. And then when emails are sent using this, that's how they get\u003C/p>\u003Cp>Speaker 1: sent. But they get sent with 1 service, not multiple services. Right? Single services.\u003C/p>\u003Cp>Speaker 0: I'm not I'm not sure I see I mean, maybe I'm missing it, but I'm not sure I see the value in being able to set set up multiple. I don't even think you can. I'm not sure you can. It'll be in config options.\u003C/p>\u003Cp>Speaker 2: I mean, technically, because, like, most email services have specific rest APIs that you can just call. So you can probably just set up a webhook event Use a web. Operation thingy. Yep. Send over the the specific payload, and then the email service should take over.\u003C/p>\u003Cp>So, yeah, technically, should be doable.\u003C/p>\u003Cp>Speaker 1: Nice. But I think we're single email service Yeah. On the scenes or\u003C/p>\u003Cp>Speaker 2: Yes.\u003C/p>\u003Cp>Speaker 1: And I I don't actually know.\u003C/p>\u003Cp>Speaker 0: Hello. The hello. Hello. Hello, Duff. We could should talk because I also built my wedding website with, with Directus and built a set of automations around that.\u003C/p>\u003Cp>So how funny is that? I wrote a whole blog post about this. It's one of the earliest blog posts on the developer blog. If you wanna go take a look in our docs. Yeah.\u003C/p>\u003Cp>That's fun. Gosh. Nerds really do like to overcomplicate weddings. Then don't they slash we.\u003C/p>\u003Cp>Speaker 1: Developers are as bad as some of our I\u003C/p>\u003Cp>Speaker 0: mean, I have to deal with\u003C/p>\u003Cp>Speaker 1: complicating things. Right?\u003C/p>\u003Cp>Speaker 0: That's amazing. Yeah. That's so funny. Why should\u003C/p>\u003Cp>Speaker 2: I spend 15 minutes to do the thing that I need to do when I could spend 3 hours to automate the thing.\u003C/p>\u003Cp>Speaker 0: Oh, no. No. It was good. We used it for I mean, a quick aside, but I will explain. So weddings have, like, quite a lot of variability to them.\u003C/p>\u003Cp>So we had if you consider a ticket. Right? A ticket. Right? An RSVP.\u003C/p>\u003Cp>So the first thing is you don't generally send, a ticket per person. You'll send it a group and the group will RSVP for individuals and they might not RSVP the same way, then we, at least, our ceremony could only hold like 80 people, but our reception had like 200 people at it. So, we had variable ticket types and then some ticket types allowed a plus one, some didn't, so all this variability. So backing that with data was really useful. So you had people, then you had invites of multiple people, and then you had RSVPs against the invite.\u003C/p>\u003Cp>And then we also used it for comms, so like blasting out emails or texts to everyone. That's how we did it. And we also used it to manage the shopping list as, because we DIY'd the wedding as people RSVP. So that's that's why it needed hours and hours and hours of, of time.\u003C/p>\u003Cp>Speaker 2: Just like Benny said, you just have to get married a couple times, then the effort was totally worse.\u003C/p>\u003Cp>Speaker 1: I mean, I'm never doing that again. One time was enough.\u003C/p>\u003Cp>Speaker 2: So, yeah, I think it's it's regarding the This is\u003C/p>\u003Cp>Speaker 1: year 30 for us.\u003C/p>\u003Cp>Speaker 2: Oh, damn. Nice.\u003C/p>\u003Cp>Speaker 1: My partner's been a long time. Congratulations.\u003C/p>\u003Cp>Speaker 2: So, Alright. Let's summarize a little bit because we have, you know, 2 issues. So the first one with the general email translatability is not that complex in itself, but should be doable also. And with Kevin's mentioned, like, translation strings, if we could use those, that would be very cool, very nice. With for the system emails, if we could reuse the crowd in, stuff or, like, the static hosting of the string so we can reuse, you know, services and stuff, that would also be very nice.\u003C/p>\u003Cp>And now I think like, if nobody has anything else regarding that\u003C/p>\u003Cp>Speaker 0: Could I just add could I could I add a question? Very interesting. Which is simply Sure. Of course. Can you not use translation strings in custom templates and custom liquid templates today?\u003C/p>\u003Cp>It feels like you should be able to. No. You can't. Okay. Fine.\u003C/p>\u003Cp>Speaker 2: I don't think you can.\u003C/p>\u003Cp>Speaker 1: That's not what I know of.\u003C/p>\u003Cp>Speaker 0: No. No. No. I I defer to you. I've not tried to do it.\u003C/p>\u003Cp>I made an assumption that it was supported. So, yeah, good to know.\u003C/p>\u003Cp>Speaker 2: As far as I know, like, the the only thing that you can do in there is, like, use data that's get passed in, you know, with the keys. So, you could do that with flows. Right? Like, if you would send if you could fetch some data or decide in a flow, like, what that specific e will hold. So, like, for an English user, it will hold hello, and for a German user, it would say, like, or something.\u003C/p>\u003Cp>Then you could reuse the same key, and it works, you know, for multiple languages. But you can't actually use the language thingies, the other thingies. Oh, yeah. And and another nice point from Tim. What about right to left languages?\u003C/p>\u003Cp>Speaker 0: Oh, they don't exist. We're gonna forget about right to left lang I mean, sure. But, you know, that that is a nuance in an implementation, I think. I think don't you set it on the HTML attributes? So you would just set it in the email.\u003C/p>\u003Cp>Speaker 2: I mean, it it look. I'm I'm really not sure because I don't speak or read languages that go from right to left.\u003C/p>\u003Cp>Speaker 0: But more but more than anything, we need to think about that.\u003C/p>\u003Cp>Speaker 2: Yeah. Like like a button, like like a, verification button or something. Should it also be on the other side, for example, in the email template? So, like, not only text, but also, like, buttons. Do the does the language affect those as well?\u003C/p>\u003Cp>I think so. Right?\u003C/p>\u003Cp>Speaker 0: I think my my very limp with pleading complete ignorance here, I'm pretty sure basically whole UIs flip accordingly. But, yes, I think Tim Tim makes a good point though in that it would not simply be a translation string, but you would intrinsically need to know is this email a right to left or left to right email. And, you know, change the I think I genuinely think it's just an attribute in the HTML tag, but, you know, change that\u003C/p>\u003Cp>Speaker 2: accordingly. Yeah. But but in the HTML tag, for example, like, it would need to with, like, c s like, CSS in emails is always very tricky. Like, it's very nitpicky. Something works in an email client, something doesn't, and that's, like, super archaic.\u003C/p>\u003Cp>If if anybody had to deal with this, I'm sorry for you.\u003C/p>\u003Cp>Speaker 0: We support some right to left languages though. Right? Like, in the data studio.\u003C/p>\u003Cp>Speaker 2: I believe so. I have never used them, to be honest. So please don't look at me for further info in the context.\u003C/p>\u003Cp>Speaker 0: Given given that the default language collection gets created with We do.\u003C/p>\u003Cp>Speaker 1: We do.\u003C/p>\u003Cp>Speaker 2: Yep. Definitely.\u003C/p>\u003Cp>Speaker 1: So if you look, we have Arabic Yeah. For 1. So if you scroll where's my language Uh-oh. I don't know what\u003C/p>\u003Cp>Speaker 2: Don't lose the button.\u003C/p>\u003Cp>Speaker 1: I'm good enough navigating around. Worst case, I have DirecTV access to this guy. Fix it. But it's all good. So you get your Arabic.\u003C/p>\u003Cp>So we do have the translations for it.\u003C/p>\u003Cp>Speaker 0: It's individual strings, though. Yeah. Yeah. Exactly. Exactly.\u003C/p>\u003Cp>As Tim said here in the chat, I'm not convinced this is a true right to left implementation for languages. It likely will do, but will do is not necessarily the best or optimal. But in any case, that's just worth noticing too.\u003C/p>\u003Cp>Speaker 1: Would the reality actually be that this this should flip over here in the right to left? Like, the module bar, like, the whole screen would, like, invert? Oh, that makes my head hurt.\u003C/p>\u003Cp>Speaker 0: I I am not sure that's correct. So I I feel the need to add, I believe, the 3 of us here, plus Tim and the child Oh, Benny said, yes. Okay. Someone had a degree of confidence because I was like, if we've not done it, we don't know and there are degrees of implementation. Right?\u003C/p>\u003Cp>But, at the very least, consider the way people read left to right in terms of priority and flow. They would wanna be flipped.\u003C/p>\u003Cp>Speaker 2: Yeah. But we also have to keep in mind that, Benny is from Australia, so his layout is also different. His navigation is on the bottom, and everything appears on the top. It's flipped.\u003C/p>\u003Cp>Speaker 0: You know what would be so funny if, yeah, everything was upside down or, like, even subtle things like like the the spinner stand in the other direction like the toilet water.\u003C/p>\u003Cp>Speaker 2: Yeah. Oh, that would be good. Alrighty. I think I think that's for for now, enough about emails because the other issues are also very interesting, and I think we should we should look into them.\u003C/p>\u003Cp>Speaker 1: Definitely. So sounds like we have a couple of solutions to think through on how we'd wanna implement this. I was looking, Kevin, with regards to your question. It does look like if you use a custom template, so so my custom template so if you have a custom liquid template, you can define variables inside that template. So first name, you then pass that as data from a flow.\u003C/p>\u003Cp>Now this is flow implementation of that template. But, technically\u003C/p>\u003Cp>Speaker 0: Yeah. I mean, technically, being able to and it being in any way optimal. There's a very, very wide chasm between the 2, and I think this is up on one end. Right?\u003C/p>\u003Cp>Speaker 1: Yeah. So once again, what you would do is you would have a body and a subject here that you were looking up from that translation user side content translation. So you'd have a user table with a translations interface, that has your subject and your body and just simply translate the whole thing. You could variabilize or anything that you wanted inside that template itself. Flows would have to handle these, you know, use a run script.\u003C/p>\u003Cp>I did something like this recently for page templates. So defining a page template, content gets built in the user tables, and then when the user's ready to say, you know, for my my location page template, generate the location page, substitute in. I've got a flow that looks for those variables, substitutes them in, generates the page instance for that location, and I'm standing for that. So you could do those kinds of things. But again, it's a lot of work upfront, for the developers and the, you know, the administrators.\u003C/p>\u003Cp>So Yeah. Figuring out a way to make this I think, again, the system making it accessible via the admin in some way, shape, or form, I think is the ideal solution. Like it. Agreed. Cool.\u003C/p>\u003Cp>Speaker 2: And check.\u003C/p>\u003Cp>Speaker 1: Alright. System flows. What do you wanna talk about there, mister Daniel?\u003C/p>\u003Cp>Speaker 2: Oh, this this one is very cool. This is very interesting. It's, the idea and I'm I'm I I'm always very in favor of dogfooding, like, our application. So if we could use like, integrate flows deeper into our app itself, it would, like, in a way, force us to actually improve flows a little bit for ourselves. And so we got it's not I mean, really like them.\u003C/p>\u003Cp>Speaker 1: I know. We we we talked about flows 2.0 a little while back. Right? But yes. Go ahead.\u003C/p>\u003Cp>Speaker 2: Yeah. And, yeah. So this one is pretty interesting. So, the idea is that you replace our current, like, internal behavior of, like, what even happens if somebody presses, forgot password. You know, like like, for example, maybe I would like to send a couple emails.\u003C/p>\u003Cp>I would like to send one email to the to the admin and say, like, oh, warning. This user has, requested a password request or something, you know, just as a random example. You can also do, like,\u003C/p>\u003Cp>Speaker 1: more product updates. Record above and beyond what's in the system already. Maybe you've got soft compliance or ISO compliance things where you get that logged to a system somewhere. Yeah. That's not our app.\u003C/p>\u003Cp>Interesting.\u003C/p>\u003Cp>Speaker 2: Exactly. So maybe you want to customize this. And, I think, I haven't read the entire issue yet, but I think the idea was just to start with, like, invites and password, resets. But we can expand on this a little bit. And, you know, like, depending on how we structure this, how the user experience is, like, how do you override that?\u003C/p>\u003Cp>We have to have a fallback. What happens in the UI? And and you're not allowed to delete the thing. What happens if somebody deletes the thing? You know, like, there's there's a couple things that can go wrong, but, technically, I think this is very exciting and a very smart idea.\u003C/p>\u003Cp>I I really like this.\u003C/p>\u003Cp>Speaker 1: Clever. Well written too. Well defined. Well thought through. Linking to related concepts and tickets.\u003C/p>\u003Cp>David David Zacharias. Excellent. Excellent work. I love the\u003C/p>\u003Cp>Speaker 0: Yeah. Read only read only flows. Must have read only flows AKA system flows. Additional which kinda makes sense here. You have system collections and you can extend system collections as well.\u003C/p>\u003Cp>So it could be that thing where it's like, hey, you know what? These first two steps or the first and last, you can't change those. You can either put stuff in the middle or stuff at the end, kind of like you can do with fields today in collections. So Mhmm. The core behavior stays exactly the same that you can tack on.\u003C/p>\u003Cp>I would be more inclined then to just have an event, though, that an event based hook can hook into.\u003C/p>\u003Cp>Speaker 2: I don't know. No. That's a good point, actually.\u003C/p>\u003Cp>Speaker 0: Because if you have read only flows and you have these new additional scopes, then they kind of negate the need for one another, I think.\u003C/p>\u003Cp>Speaker 2: Now that that's a good point. Yeah. That is a good point.\u003C/p>\u003Cp>Speaker 0: And our paradigm today is\u003C/p>\u003Cp>Speaker 2: because, like, oh, let me based. Even if somebody wants to just break the flow, for example, maybe somebody doesn't want the, like, even the functionality to to be there. You know? Like, maybe you want to forbid actually password requests, like, reset requests.\u003C/p>\u003Cp>Speaker 0: Yeah. Or you just want it to come to the internal team and never go back out to them automatically. Like, that is a a managed process. Yeah. Interesting.\u003C/p>\u003Cp>Yep.\u003C/p>\u003Cp>Speaker 2: Yeah. Also Disabling your Reasonable to me.\u003C/p>\u003Cp>Speaker 1: Disabling a password reset? Interesting.\u003C/p>\u003Cp>Speaker 2: Yeah. I mean, for you know, it's it's always such a, you know, contrived example and stuff, but take like, there's so many different environments and and regulations and\u003C/p>\u003Cp>Speaker 0: Get in touch with your system administrator. Managers and Your IT team\u003C/p>\u003Cp>Speaker 2: or whatever. For example. Yeah. So I can definitely see the use case there. And and this is, like like, super interesting to me.\u003C/p>\u003Cp>Speaker 0: The the the lowest\u003C/p>\u003Cp>Speaker 2: Like, I have not thought about this.\u003C/p>\u003Cp>Speaker 0: Neither have I. The lowest hanging fruit version of this is additional scopes that allow you to execute additional logic on top of the core logic for things like inviting and password resets. These I I almost feel like that is a separate thing, which is smaller and much easier to to implement. Pop that to the side. The system flows is is diff is the thing here.\u003C/p>\u003Cp>I just find that in that addition interesting.\u003C/p>\u003Cp>Speaker 1: Yep. Nope. And so, again, it was extensible, you know, in the sense of it'd be nice to have the translation capability, but also, again, move. We're gonna touch some of these things, potentially moving some of that logic to where it's more accessible or modifiable.\u003C/p>\u003Cp>Speaker 0: Oh, to modify the business logic, users can duplicate the flow and adapt to their needs. The system flow would then be inactive, but could be activated anytime to restore the default functionality. That UX, for me, does not feel good, but it is an interesting way to think about it.\u003C/p>\u003Cp>Speaker 2: Yeah. I I think\u003C/p>\u003Cp>Speaker 1: Well, the system side scope\u003C/p>\u003Cp>Speaker 2: in the event yeah. If you can just, like, have a filter hook, and that would do the thing. Like, you can then cancel. Like, if you throw, the hook will be canceled, and then the email won't be sent out. And if you just pass it through, the normal behavior will take place, which is just sending an email.\u003C/p>\u003Cp>Right? Like, and you can do stuff in between. Yeah. I feel like this would be a way better solution than having, like, read only flows and copying and then, you know, fallbacks and something is missing and whatever. Like, maybe just\u003C/p>\u003Cp>Speaker 0: And the And the critical thing is it matches the paradigms we have today. We have event based, event based triggers, and then we have actions and filters which run before or after the the operation happens, the the database operation happens. And yeah. So that feels that feels kinda better to me. And, yeah, you can always find a way to break it out of completing.\u003C/p>\u003Cp>And if you're if it's blocking, then the end part never happens.\u003C/p>\u003Cp>Speaker 2: Yeah. Oh, this is cool. If somebody could work on this, that would be nice. This is pretty cool.\u003C/p>\u003Cp>Speaker 1: Well, that's why we're reviewing so we can Could we determine, does it make sense and what additional things do we need to think through. Right?\u003C/p>\u003Cp>Speaker 0: Can we split this into 2 feature requests? Because that core nugget we've discussed is feeling very viable. Also, it feels like not a huge lift. And it is not system. It is not system flows.\u003C/p>\u003Cp>It is the introduction of new events, and then system flows is is something in and of its own. Right. I suppose.\u003C/p>\u003Cp>Speaker 2: But, like, if we have that event, like, do we even need system flows then?\u003C/p>\u003Cp>Speaker 0: I I I would argue not. I I would argue not. But that isn't what this. It's hard because I don't feel inclined to change people's feature requests into the 10% one liner that they've introduced, in it. But that nugget can be dealt with in isolation.\u003C/p>\u003Cp>Speaker 1: Yeah.\u003C/p>\u003Cp>Speaker 0: Yeah. Saw that.\u003C/p>\u003Cp>Speaker 2: Okay. So so that that's that's pretty neat. That would be nice. Yeah. Very cool.\u003C/p>\u003Cp>Yeah. Then okay. So for the events, then there would be a password request reset request. I always\u003C/p>\u003Cp>Speaker 0: It's a reset it's a reset request and then a reset.\u003C/p>\u003Cp>Speaker 2: Yeah. And a oh, oh, right. Those are 2 things. Okay. The the request and the actual reset.\u003C/p>\u003Cp>Maybe you want to act on that too. Okay. Those 2. The invite would be the 3rd.\u003C/p>\u003Cp>Speaker 0: Oh, I'm hang on. So I can just tell you because I've just written this section of our new documentation. So there is invite request and invite accept. Right, actually creating a user off the back of an invite. Then there is, password reset request and password reset.\u003C/p>\u003Cp>And then there's a set maybe around SSO specifically, but maybe not. They are that out. And then if we're talking about if we're thinking about the whole breadth of kind of off, there is also 2fa on off. Like, they are the that is the set of kind of operations that exist beyond just logging in, locking out, logging out, refreshing.\u003C/p>\u003Cp>Speaker 2: And since this week, there will be maybe coming then, register request and register request accepted, maybe?\u003C/p>\u003Cp>Speaker 0: Yes.\u003C/p>\u003Cp>Speaker 2: Something. Ah, and the email verification might also be interesting. Somebody might need that.\u003C/p>\u003Cp>Speaker 0: I would sooner add a a a, you know, like, a bundle of new events and go, well, there's the bit the biggest degree of flexibility for\u003C/p>\u003Cp>Speaker 2: That would be neat. Okay. Yeah. This this this sounds very exciting. This sounds actually very cool to me.\u003C/p>\u003Cp>Because we introduced to also new events for the content versioning. There was the promotion Promotion. Or promote or promotion, which is also useful. So this doesn't sound that far and unreasonable. This sounds very reasonable, actually.\u003C/p>\u003Cp>Speaker 0: So, Jonathan, so while you're typing, there's a there's a couple more. So there is invite, and then there's invite accept. There's password reset request and password reset, And there is 2 FA on and off. And they are the only 2 in my mind that I'm not sure how what like, I'm not sure what the impact of adding those in particular are, but they are there as well. And then I don't I don't have enough knowledge around single sign on to be confident in in listing events around that.\u003C/p>\u003Cp>Speaker 2: Cool.\u003C/p>\u003Cp>Speaker 1: Yep.\u003C/p>\u003Cp>Speaker 2: Yeah.\u003C/p>\u003Cp>Speaker 1: Yeah. And, again, being able to extend being able to extend these would be really powerful. Right? Because if we've got a lot of clients that run us as a SaaS, we operate as a SaaS. There are system and service emails that, again, we do it through user templates and other things today, the way that we define and the way we've talked about.\u003C/p>\u003Cp>But making this kind of built in where you can create and manage your own system emails and service emails, would love it.\u003C/p>\u003Cp>Speaker 0: Yeah. And the the thing is we already because we this only were basically, taking this feature request around or the other feature request rather, which is, oh, sorry. I see you're in this issue. Sorry. We're in the wrong one.\u003C/p>\u003Cp>Sorry. So emails that go out are not all of those. Sorry. Emails are just the, the yes. The password reset request and the invite.\u003C/p>\u003Cp>They are the only 2 system emails. Sorry. They are the auth events, though. Or the the potential auth you know, they are the points at which we could implement events. The fact that we already have filters and actions as blocking and non blocking, you know, code, you know, logic business logic means immediately you can effectively extend Directus' core functionality without needing to do anything else but expose these new events, which is really cool.\u003C/p>\u003Cp>Speaker 2: Yes. Agreed.\u003C/p>\u003Cp>Speaker 0: It's nice when you have a system that kind of already has the building blocks. Right? There's no new building blocks that need to be built for this one.\u003C/p>\u003Cp>Speaker 2: Yes. Only the integration and making sure that we can actually, like, cancel, for example, like, what happens if if the thing canceled and stuff. But other than that, you're completely right. Yes. So just as a reminder for everybody else in the chat because there's still a couple people here, the show will be over very soon.\u003C/p>\u003Cp>So if you have any questions that you would like to ask, now is the time. Now is the time.\u003C/p>\u003Cp>Speaker 1: Quiet group today.\u003C/p>\u003Cp>Speaker 0: Nothing wrong with that at all.\u003C/p>\u003Cp>Speaker 2: Alright. Yeah.\u003C/p>\u003Cp>Speaker 1: Means maybe we did our job right.\u003C/p>\u003Cp>Speaker 0: And and not right any other\u003C/p>\u003Cp>Speaker 1: time.\u003C/p>\u003Cp>Speaker 0: Yeah. That's really cool. I like the idea of system system flows. I, ultimately, like the idea of that, of exposing a set of functionality as flows in a UI that could be extended on the end. But I I, personally believe it's just simply unnecessary.\u003C/p>\u003Cp>It's just exposing the new events. And with actions and filters, it facilitates, I think, the goals of this.\u003C/p>\u003Cp>Speaker 2: Yep. Yeah. Exactly. I fully agree. So people let your let your questions out in last minute.\u003C/p>\u003Cp>1, 2. Yeah. If you have enjoyed this, or want to partake in the next one, you take a look in Discord in the events. You will see that we will be doing another episode on the 23rd May Yeah. Will be about configurable API errors.\u003C/p>\u003Cp>So errors are always very important. You might wanna let your voice be heard there. So please join in. Tune in if you like. And if you enjoyed this and want to revisit this or other episodes, head on over to directors.iotv.\u003C/p>\u003Cp>And, there will be lots of other shows as well, which are quite interesting and fun. So please check it out. Let's say it again, directors.io/tv.\u003C/p>\u003Cp>Speaker 0: Yep. We hope\u003C/p>\u003Cp>Speaker 2: you enjoyed. Oh, there's the link.\u003C/p>\u003Cp>Speaker 0: Thank you. And all other episodes of request review bar the last one because I messed up the recording, you can find right there.\u003C/p>","Talk about what this feature is. I'll I'll I'll in I'll intro because Daniel's gonna have to do all the hard hard work to do. Oh, no. So, we initially I think this was initially flagged as the make email templates translatable. So currently, especially for the system templates, not support translations on those. So things like your invite email, those are kind of hard coded as English only. You can do some things with the liquid templates, but even those are without some work are not really translatable. Mhmm. So the content, you have to do some variableization. Now with flows, I think with the advent of flows, you can do some things where you look up the data, pull your you know, based on content or other things, but be nice to make some modifications to the way that this platform is working to use either, the current translation strings or other capabilities, the translation solutions, interfaces on the platform itself, find a way to solve this problem so that emails can be multilingual more easily. So that's our goal. But I also saw that there I I found this that actually has an RFC spec. This was our our lovely CTO, mister Reich, creating this one liner, back in the day before we hardenforced RFCs. But then someone actually did a nice write up, and they referenced this particular ticket along with some other things. But they had some other capabilities on some event hooks and user invites and some things to actually extend the capabilities of the email solutions a little better. So we thought we'd use this as our our driving factor since it actually has RFC and it references the email translations. So that's the goal today, talk about how do we make the emails, the the platform emails, as well as other email things more easily translatable and easier to use and extend on the platform. Miss anything, Daniel? Anything here? That's a nice, initial summary because, the pain of actually having a multilingual app, comes up quite quickly. As as soon as you got a couple different users from a couple different countries, you're you will run into this. So, this is largely only a problem for multilingual apps right now because, as of right now, you do have the ability to override our system email templates. So, technically, if you only have one language, you could just go into the, email template folder. And I even have looked up a link beforehand that I can share with the chat because I'm so organized, apparently, at least today. Alright. You may head on over to our docs under self hosted email templates, which will help you get started with how to do that. It's very, very simple. You have a template folder where you can put in the, the liquid template file, and you're basically done. Depending on what you want to do, of course, you know, you can make it more complicated. You can expand and expand on it, or add other functionality with your instance. But, technically, if you only have one language that you would like to serve, you can very easily do this. It's no problem. And even for the very, very, very brand new feature that was released this week, not sure how many of you guys have seen this because, I did a little thing with the help of the others, of course, because public registration also uses, an email template that you can override yourself. So that's the thing. You can expand on it, but as Jonathan said in the beginning, yeah, multi multilingual apps have a problem. Right? Like, how how do you do that as of right now? There's different, routes that you could go down on. Maybe just the the most most naive way would be to have a template per language that you just prefix with the ISO code of the language, for example. This would be the most naive way that I would not recommend, but, technically, we could do that just as a you know, to throw it in the room for discussion right now. So we could do that. I wouldn't do it that way, but, technically, we could. One thing you mentioned, Jonathan, is you can kinda hack around with, if you build custom templates with, like, liquid tags. Do you have any more information about that? I'm not saying it would be an ideal approach, but how might that be approached now? So liquid is just a, you know, a templating language, and you can you can grab templates in the flows as part of the email, service, that email notification service operation. And I believe if you supply variables, you can actually swap in the variables. So you could in in your Are you using translation strings? Look up the look up the multilingual contents, you know, store your your template data as a record using the current translations interface. So if we were to box here. I think in this particular demo, mail, settings, email templates. So if you were to set up, like, an email template like this. Right? So you can you could make this data driven, where instead of having this body here and the subject here and the name here, you could actually put those into a translation's interface, using the existing translations capabilities, then you manage your content. Now at this point, I can use a flow to grab this data. Now it doesn't work, I think, as Daniel's kind of referring to user invites. You'd have to do your own custom user invite and handle the, you know, on authentication or allow public registration kinds of things to do that. So to send a nonce you know, those are kind of system emails. Now we can override those with a liquid template. I'd have to play around. I think if we created a liquid template with variables in it, I think you could potentially use a flow to inject into that and swap in the multilingual from something like this, where I have the content lingually translated. But I don't have any testing. I mean, you're talking about a naive way of doing this to be to have a template for each language, but why would we not simply store the contents of the email as a string in our translation files and then use that dynamic value? Surely, that's the the optimal way to do this. No? That's That would have been the better way that I wanted to to get into now. Good. So the like, in the beginning, I meant, like, the most naive way just to prefix every, email template with, like, enus.template. Liquid or whatever and then called it in every single language. Like, this is the most naive way that I could think of. But, as you might have guessed, by me emphasizing naive is it's very naive. It's not good because we have a very, very nice, crowd and integration for all of our translations for the app. So it would be very cool if we, instead of making every single template, store the languages directly, we would store like you suggested now, we would store every string inside that we want to translate very similar to our app translations. So we everybody from the community can what what's the what's the Crowded. Everybody can profit off of the, yeah, of the community's breadth and and width. Like, we have people coming from everywhere, every language. So it would be nice if we can do that. It's also for anyone that does not know this, head on over to no. I haven't. Oh, I have I have actually, Locales. What what we're doing? Locales dot directors. Yeah. Yes. If in case anybody did not know this, you can head over to locales.directors.io, and you'll see our app translations. You can contribute, can add your own. Take a look. Yeah. This would be a better solution to the email problem. So we can, automatically generate and pull in those, from user contributions. That would be very nice. But there is something, you know, digging below the surface. That'd be fine for system emails. Like, for system emails, that's totally fine. Just use these. But scratching one level below the surface is the ability to act is to use translation strings maybe in custom templates. That's the one level on because I feel like the solution to make email tran make email templates translatable is fine for system emails. Like, that we have an approach. We have a you know, we have something. We just need to not hard code the values in English. But there's more than that, I suppose. So I think that was one of the comments that was in the one of these tickets already. I think that was in here somewhere. Somebody mentioned that using the translation strings. I think it was the right somewhere along the way. But that is an option. Right? So to me, either something like this. Right? So you can do this yourself with flows for for anything non system email, whether we do the system emails in the translation strings here or whether it's in the actual crowd in files, because it's a system email, you could technically actually have that in all of the languages. I guess, technical question, how do I know what language to send the email in? So when I'm using a user invite, I guess, you set the language for the user, the default language for the user. Is that how you would manage that? Yeah. For invites, I think it's a special case because you don't know the person. You could, under specific circumstances, not know what the person is speaking technically. But, like, for other system emails, we have the user. It's they are already registered, so you can just pick the language from the user or the default language of the instance. But for invites, I think we should fall back to the, default language of the instance Yeah. But also provide the opportunity to set a specific language inside of the, pop up. Yeah. Yeah. Exactly. Exactly. Yeah. We'd add we'd add language here as well. Right? So not just the you know, you'd choose choose your role or whatever you're inviting this user to, but also have a language and set it to the default for the project as the initial. If If they wanna change it, they can choose from one of the languages. And, therefore, those things exist in the crowd inside, but that's part of the you don't have to do any translations inside the app for that. That's not a dynamic kind of thing necessarily. Although, if I'm overriding, then I still want. So that's something that we have to think about as well. Right? So where does this get managed, and how does this get managed? Crowdin is awesome for system, but the reality is I may want to customize the actual liquid tablet for this. And as soon as I do that, I'm now I now fall back outside of how do I manage the translations. You know what would be really cool actually is if in settings, there was a a section called email templates, and our default ones were there and not deletable, and you could create new ones, and then use the built in director's translation interface to enable that. Like, that feels like a really nice flexible way to also potentially stop people needing to build their own liquid templates, like, as separate files and then load them into a directory. For many use cases, just being a just having a WYSIWYG with, well, a WYSIWYG would be plenty. Maybe with, like, a yield or, you know So it it's this. This is fundamentally what you need is a subject and a body. That's all you really have to have for email. For the text, put this in as a, you know I I think again, the the trouble with making it a system side is I I also kind of want content users to be able to do this. So I'd I'd want my marketing teams or my whoever's to be able to manage the content in these. So in a sense, it would be a system user table, possibly, that would show up that you could make accessible to the content side. You could optionally make it as accessible maybe. We don't really we don't really do that with anything today. We don't we don't create anything here other than the languages table gets created if you haven't created it yet, for translations interface. I I question that notion to a degree, though, because if you look at things like creating and editing flows, you can make exactly the same argument there. You wanna expose flows to more people in your organization, and we don't do that. I don't see why like, I think that that would be a bigger conversation about what is exposed versus what isn't and to what degree. So I I would be at peace with the idea that that is an admin setting, but I do get it. It feels a little more editorial perhaps. Okay. That's a separate discussion then, really, I think. So one of because this actually came up this week. Somebody noted that if I make you know, I I'd like to be able to make some role editing capabilities accessible to a user, but not give them data model access or flow access or other things. So potentially being able to enable subsets of the settings for non admin users. So that's a separate discussion. But I do agree. I think email templates would be really awesome in here, so that I don't have to create liquid files or other things behind the scenes. And you don't have access to the directory on professional cloud. That's the other big thing in my mind is, like, to really be a solution that works anywhere Directus is is hosted. It can't rely on dropping files in a persistent directory. It needs to be accessible via the data studio. Some action in the chat. I envision being able to create custom email templates and sending it to a mailing service, specifically something something from directors. Could be separate thing, but would be good if it wasn't limited to settings page and flexible enough to support this. The reality is, though, if I do want my own email templates, I could still create the user stuff for that, and I could mimic whatever was in the system. So, hopefully, over time, maybe there's additional system emails or things that we want for the platform. So we'd wanna be able to have those, and they could be manageable in the setting side if you wanted to replicate. Because Flows already supports, you know, grabbing things, you know, pull your variables, pull your data, pull your content. So, again, in this, like, agent c OS here, we have flows for, you know, sending the email. Right? So when you send the email, we're actually getting data from the trigger hooks and creates and posts and whatever, so we can pull in data from wherever. Right? So if there's data in a template or places that we wanna get it, we could do that. We can grab that ahead of the email. Could you, show the drop down link? Sorry. Could you show the drop down again where it was marked down? What was the other option is attempt just in send email here. The other option is WYSIWYG or a template. Interesting. Because still in my mind, like, to be really flexible, you want templates to be able to have exactly data that is popped in there. So, yeah, I don't see why why you couldn't be authoring those indirectors. You know? I I think we should. I I think it would be awesome because having to go to liquid templates and have to have custom extension deployment capabilities or access to the server. Yeah. Not ideal. Right? So again, part of what I think this overall system flows discussion was about, in general. So moving away from the the simple thing that Raich put in here, this was a little bit more of handling this with some system flows and setups and management, being able to manage this from the front end as opposed to back end. So making it data driven. Right? The the things we enable for everyone else, let's enable this for ourselves and make this data driven. I love it. Yeah. I I really want to go into that, issue as well, the system flows for, for the system actions. But, first, I wanna finish the other, message from the chat that was with the mailing service. Like, I'm not sure if I understand correctly because, like, this should be possible, right, with just the environment variables. You just define which SMTP server you want to use as an email service so you can actually connect to something else. And if you override the template, that is doing what you just said. Or maybe maybe am I missing something? Maybe the ability to send them to custom places per run. Like, there's a few it depends what level of flexibility or abstraction you want to build in, but at its core, that's what happens with the email service In flows, at least. In flows? I don't play with it much, but I don't think you get to choose your mail service here. Right? No. No. But you configure that for the project. And then when emails are sent using this, that's how they get sent. But they get sent with 1 service, not multiple services. Right? Single services. I'm not I'm not sure I see I mean, maybe I'm missing it, but I'm not sure I see the value in being able to set set up multiple. I don't even think you can. I'm not sure you can. It'll be in config options. I mean, technically, because, like, most email services have specific rest APIs that you can just call. So you can probably just set up a webhook event Use a web. Operation thingy. Yep. Send over the the specific payload, and then the email service should take over. So, yeah, technically, should be doable. Nice. But I think we're single email service Yeah. On the scenes or Yes. And I I don't actually know. Hello. The hello. Hello. Hello, Duff. We could should talk because I also built my wedding website with, with Directus and built a set of automations around that. So how funny is that? I wrote a whole blog post about this. It's one of the earliest blog posts on the developer blog. If you wanna go take a look in our docs. Yeah. That's fun. Gosh. Nerds really do like to overcomplicate weddings. Then don't they slash we. Developers are as bad as some of our I mean, I have to deal with complicating things. Right? That's amazing. Yeah. That's so funny. Why should I spend 15 minutes to do the thing that I need to do when I could spend 3 hours to automate the thing. Oh, no. No. It was good. We used it for I mean, a quick aside, but I will explain. So weddings have, like, quite a lot of variability to them. So we had if you consider a ticket. Right? A ticket. Right? An RSVP. So the first thing is you don't generally send, a ticket per person. You'll send it a group and the group will RSVP for individuals and they might not RSVP the same way, then we, at least, our ceremony could only hold like 80 people, but our reception had like 200 people at it. So, we had variable ticket types and then some ticket types allowed a plus one, some didn't, so all this variability. So backing that with data was really useful. So you had people, then you had invites of multiple people, and then you had RSVPs against the invite. And then we also used it for comms, so like blasting out emails or texts to everyone. That's how we did it. And we also used it to manage the shopping list as, because we DIY'd the wedding as people RSVP. So that's that's why it needed hours and hours and hours of, of time. Just like Benny said, you just have to get married a couple times, then the effort was totally worse. I mean, I'm never doing that again. One time was enough. So, yeah, I think it's it's regarding the This is year 30 for us. Oh, damn. Nice. My partner's been a long time. Congratulations. So, Alright. Let's summarize a little bit because we have, you know, 2 issues. So the first one with the general email translatability is not that complex in itself, but should be doable also. And with Kevin's mentioned, like, translation strings, if we could use those, that would be very cool, very nice. With for the system emails, if we could reuse the crowd in, stuff or, like, the static hosting of the string so we can reuse, you know, services and stuff, that would also be very nice. And now I think like, if nobody has anything else regarding that Could I just add could I could I add a question? Very interesting. Which is simply Sure. Of course. Can you not use translation strings in custom templates and custom liquid templates today? It feels like you should be able to. No. You can't. Okay. Fine. I don't think you can. That's not what I know of. No. No. No. I I defer to you. I've not tried to do it. I made an assumption that it was supported. So, yeah, good to know. As far as I know, like, the the only thing that you can do in there is, like, use data that's get passed in, you know, with the keys. So, you could do that with flows. Right? Like, if you would send if you could fetch some data or decide in a flow, like, what that specific e will hold. So, like, for an English user, it will hold hello, and for a German user, it would say, like, or something. Then you could reuse the same key, and it works, you know, for multiple languages. But you can't actually use the language thingies, the other thingies. Oh, yeah. And and another nice point from Tim. What about right to left languages? Oh, they don't exist. We're gonna forget about right to left lang I mean, sure. But, you know, that that is a nuance in an implementation, I think. I think don't you set it on the HTML attributes? So you would just set it in the email. I mean, it it look. I'm I'm really not sure because I don't speak or read languages that go from right to left. But more but more than anything, we need to think about that. Yeah. Like like a button, like like a, verification button or something. Should it also be on the other side, for example, in the email template? So, like, not only text, but also, like, buttons. Do the does the language affect those as well? I think so. Right? I think my my very limp with pleading complete ignorance here, I'm pretty sure basically whole UIs flip accordingly. But, yes, I think Tim Tim makes a good point though in that it would not simply be a translation string, but you would intrinsically need to know is this email a right to left or left to right email. And, you know, change the I think I genuinely think it's just an attribute in the HTML tag, but, you know, change that accordingly. Yeah. But but in the HTML tag, for example, like, it would need to with, like, c s like, CSS in emails is always very tricky. Like, it's very nitpicky. Something works in an email client, something doesn't, and that's, like, super archaic. If if anybody had to deal with this, I'm sorry for you. We support some right to left languages though. Right? Like, in the data studio. I believe so. I have never used them, to be honest. So please don't look at me for further info in the context. Given given that the default language collection gets created with We do. We do. Yep. Definitely. So if you look, we have Arabic Yeah. For 1. So if you scroll where's my language Uh-oh. I don't know what Don't lose the button. I'm good enough navigating around. Worst case, I have DirecTV access to this guy. Fix it. But it's all good. So you get your Arabic. So we do have the translations for it. It's individual strings, though. Yeah. Yeah. Exactly. Exactly. As Tim said here in the chat, I'm not convinced this is a true right to left implementation for languages. It likely will do, but will do is not necessarily the best or optimal. But in any case, that's just worth noticing too. Would the reality actually be that this this should flip over here in the right to left? Like, the module bar, like, the whole screen would, like, invert? Oh, that makes my head hurt. I I am not sure that's correct. So I I feel the need to add, I believe, the 3 of us here, plus Tim and the child Oh, Benny said, yes. Okay. Someone had a degree of confidence because I was like, if we've not done it, we don't know and there are degrees of implementation. Right? But, at the very least, consider the way people read left to right in terms of priority and flow. They would wanna be flipped. Yeah. But we also have to keep in mind that, Benny is from Australia, so his layout is also different. His navigation is on the bottom, and everything appears on the top. It's flipped. You know what would be so funny if, yeah, everything was upside down or, like, even subtle things like like the the spinner stand in the other direction like the toilet water. Yeah. Oh, that would be good. Alrighty. I think I think that's for for now, enough about emails because the other issues are also very interesting, and I think we should we should look into them. Definitely. So sounds like we have a couple of solutions to think through on how we'd wanna implement this. I was looking, Kevin, with regards to your question. It does look like if you use a custom template, so so my custom template so if you have a custom liquid template, you can define variables inside that template. So first name, you then pass that as data from a flow. Now this is flow implementation of that template. But, technically Yeah. I mean, technically, being able to and it being in any way optimal. There's a very, very wide chasm between the 2, and I think this is up on one end. Right? Yeah. So once again, what you would do is you would have a body and a subject here that you were looking up from that translation user side content translation. So you'd have a user table with a translations interface, that has your subject and your body and just simply translate the whole thing. You could variabilize or anything that you wanted inside that template itself. Flows would have to handle these, you know, use a run script. I did something like this recently for page templates. So defining a page template, content gets built in the user tables, and then when the user's ready to say, you know, for my my location page template, generate the location page, substitute in. I've got a flow that looks for those variables, substitutes them in, generates the page instance for that location, and I'm standing for that. So you could do those kinds of things. But again, it's a lot of work upfront, for the developers and the, you know, the administrators. So Yeah. Figuring out a way to make this I think, again, the system making it accessible via the admin in some way, shape, or form, I think is the ideal solution. Like it. Agreed. Cool. And check. Alright. System flows. What do you wanna talk about there, mister Daniel? Oh, this this one is very cool. This is very interesting. It's, the idea and I'm I'm I I'm always very in favor of dogfooding, like, our application. So if we could use like, integrate flows deeper into our app itself, it would, like, in a way, force us to actually improve flows a little bit for ourselves. And so we got it's not I mean, really like them. I know. We we we talked about flows 2.0 a little while back. Right? But yes. Go ahead. Yeah. And, yeah. So this one is pretty interesting. So, the idea is that you replace our current, like, internal behavior of, like, what even happens if somebody presses, forgot password. You know, like like, for example, maybe I would like to send a couple emails. I would like to send one email to the to the admin and say, like, oh, warning. This user has, requested a password request or something, you know, just as a random example. You can also do, like, more product updates. Record above and beyond what's in the system already. Maybe you've got soft compliance or ISO compliance things where you get that logged to a system somewhere. Yeah. That's not our app. Interesting. Exactly. So maybe you want to customize this. And, I think, I haven't read the entire issue yet, but I think the idea was just to start with, like, invites and password, resets. But we can expand on this a little bit. And, you know, like, depending on how we structure this, how the user experience is, like, how do you override that? We have to have a fallback. What happens in the UI? And and you're not allowed to delete the thing. What happens if somebody deletes the thing? You know, like, there's there's a couple things that can go wrong, but, technically, I think this is very exciting and a very smart idea. I I really like this. Clever. Well written too. Well defined. Well thought through. Linking to related concepts and tickets. David David Zacharias. Excellent. Excellent work. I love the Yeah. Read only read only flows. Must have read only flows AKA system flows. Additional which kinda makes sense here. You have system collections and you can extend system collections as well. So it could be that thing where it's like, hey, you know what? These first two steps or the first and last, you can't change those. You can either put stuff in the middle or stuff at the end, kind of like you can do with fields today in collections. So Mhmm. The core behavior stays exactly the same that you can tack on. I would be more inclined then to just have an event, though, that an event based hook can hook into. I don't know. No. That's a good point, actually. Because if you have read only flows and you have these new additional scopes, then they kind of negate the need for one another, I think. Now that that's a good point. Yeah. That is a good point. And our paradigm today is because, like, oh, let me based. Even if somebody wants to just break the flow, for example, maybe somebody doesn't want the, like, even the functionality to to be there. You know? Like, maybe you want to forbid actually password requests, like, reset requests. Yeah. Or you just want it to come to the internal team and never go back out to them automatically. Like, that is a a managed process. Yeah. Interesting. Yep. Yeah. Also Disabling your Reasonable to me. Disabling a password reset? Interesting. Yeah. I mean, for you know, it's it's always such a, you know, contrived example and stuff, but take like, there's so many different environments and and regulations and Get in touch with your system administrator. Managers and Your IT team or whatever. For example. Yeah. So I can definitely see the use case there. And and this is, like like, super interesting to me. The the the lowest Like, I have not thought about this. Neither have I. The lowest hanging fruit version of this is additional scopes that allow you to execute additional logic on top of the core logic for things like inviting and password resets. These I I almost feel like that is a separate thing, which is smaller and much easier to to implement. Pop that to the side. The system flows is is diff is the thing here. I just find that in that addition interesting. Yep. Nope. And so, again, it was extensible, you know, in the sense of it'd be nice to have the translation capability, but also, again, move. We're gonna touch some of these things, potentially moving some of that logic to where it's more accessible or modifiable. Oh, to modify the business logic, users can duplicate the flow and adapt to their needs. The system flow would then be inactive, but could be activated anytime to restore the default functionality. That UX, for me, does not feel good, but it is an interesting way to think about it. Yeah. I I think Well, the system side scope in the event yeah. If you can just, like, have a filter hook, and that would do the thing. Like, you can then cancel. Like, if you throw, the hook will be canceled, and then the email won't be sent out. And if you just pass it through, the normal behavior will take place, which is just sending an email. Right? Like, and you can do stuff in between. Yeah. I feel like this would be a way better solution than having, like, read only flows and copying and then, you know, fallbacks and something is missing and whatever. Like, maybe just And the And the critical thing is it matches the paradigms we have today. We have event based, event based triggers, and then we have actions and filters which run before or after the the operation happens, the the database operation happens. And yeah. So that feels that feels kinda better to me. And, yeah, you can always find a way to break it out of completing. And if you're if it's blocking, then the end part never happens. Yeah. Oh, this is cool. If somebody could work on this, that would be nice. This is pretty cool. Well, that's why we're reviewing so we can Could we determine, does it make sense and what additional things do we need to think through. Right? Can we split this into 2 feature requests? Because that core nugget we've discussed is feeling very viable. Also, it feels like not a huge lift. And it is not system. It is not system flows. It is the introduction of new events, and then system flows is is something in and of its own. Right. I suppose. But, like, if we have that event, like, do we even need system flows then? I I I would argue not. I I would argue not. But that isn't what this. It's hard because I don't feel inclined to change people's feature requests into the 10% one liner that they've introduced, in it. But that nugget can be dealt with in isolation. Yeah. Yeah. Saw that. Okay. So so that that's that's pretty neat. That would be nice. Yeah. Very cool. Yeah. Then okay. So for the events, then there would be a password request reset request. I always It's a reset it's a reset request and then a reset. Yeah. And a oh, oh, right. Those are 2 things. Okay. The the request and the actual reset. Maybe you want to act on that too. Okay. Those 2. The invite would be the 3rd. Oh, I'm hang on. So I can just tell you because I've just written this section of our new documentation. So there is invite request and invite accept. Right, actually creating a user off the back of an invite. Then there is, password reset request and password reset. And then there's a set maybe around SSO specifically, but maybe not. They are that out. And then if we're talking about if we're thinking about the whole breadth of kind of off, there is also 2fa on off. Like, they are the that is the set of kind of operations that exist beyond just logging in, locking out, logging out, refreshing. And since this week, there will be maybe coming then, register request and register request accepted, maybe? Yes. Something. Ah, and the email verification might also be interesting. Somebody might need that. I would sooner add a a a, you know, like, a bundle of new events and go, well, there's the bit the biggest degree of flexibility for That would be neat. Okay. Yeah. This this this sounds very exciting. This sounds actually very cool to me. Because we introduced to also new events for the content versioning. There was the promotion Promotion. Or promote or promotion, which is also useful. So this doesn't sound that far and unreasonable. This sounds very reasonable, actually. So, Jonathan, so while you're typing, there's a there's a couple more. So there is invite, and then there's invite accept. There's password reset request and password reset, And there is 2 FA on and off. And they are the only 2 in my mind that I'm not sure how what like, I'm not sure what the impact of adding those in particular are, but they are there as well. And then I don't I don't have enough knowledge around single sign on to be confident in in listing events around that. Cool. Yep. Yeah. Yeah. And, again, being able to extend being able to extend these would be really powerful. Right? Because if we've got a lot of clients that run us as a SaaS, we operate as a SaaS. There are system and service emails that, again, we do it through user templates and other things today, the way that we define and the way we've talked about. But making this kind of built in where you can create and manage your own system emails and service emails, would love it. Yeah. And the the thing is we already because we this only were basically, taking this feature request around or the other feature request rather, which is, oh, sorry. I see you're in this issue. Sorry. We're in the wrong one. Sorry. So emails that go out are not all of those. Sorry. Emails are just the, the yes. The password reset request and the invite. They are the only 2 system emails. Sorry. They are the auth events, though. Or the the potential auth you know, they are the points at which we could implement events. The fact that we already have filters and actions as blocking and non blocking, you know, code, you know, logic business logic means immediately you can effectively extend Directus' core functionality without needing to do anything else but expose these new events, which is really cool. Yes. Agreed. It's nice when you have a system that kind of already has the building blocks. Right? There's no new building blocks that need to be built for this one. Yes. Only the integration and making sure that we can actually, like, cancel, for example, like, what happens if if the thing canceled and stuff. But other than that, you're completely right. Yes. So just as a reminder for everybody else in the chat because there's still a couple people here, the show will be over very soon. So if you have any questions that you would like to ask, now is the time. Now is the time. Quiet group today. Nothing wrong with that at all. Alright. Yeah. Means maybe we did our job right. And and not right any other time. Yeah. That's really cool. I like the idea of system system flows. I, ultimately, like the idea of that, of exposing a set of functionality as flows in a UI that could be extended on the end. But I I, personally believe it's just simply unnecessary. It's just exposing the new events. And with actions and filters, it facilitates, I think, the goals of this. Yep. Yeah. Exactly. I fully agree. So people let your let your questions out in last minute. 1, 2. Yeah. If you have enjoyed this, or want to partake in the next one, you take a look in Discord in the events. You will see that we will be doing another episode on the 23rd May Yeah. Will be about configurable API errors. So errors are always very important. You might wanna let your voice be heard there. So please join in. Tune in if you like. And if you enjoyed this and want to revisit this or other episodes, head on over to directors.iotv. And, there will be lots of other shows as well, which are quite interesting and fun. So please check it out. Let's say it again, directors.io/tv. Yep. We hope you enjoyed. Oh, there's the link. Thank you. And all other episodes of request review bar the last one because I messed up the recording, you can find right there.","8fb596c2-af4e-4a21-b22b-b5da736ee51a",[313,314,315],"c7f329c8-1566-48d9-bdd5-5dbd9238c097","6c66580b-883c-4b84-9825-7111ec9dcd42","01c1e460-1c3b-49ee-84b0-b6366cbe81ad",[],{"id":133,"number":134,"show":122,"year":135,"episodes":318},[137,138,139,140,141,142,143,144,145,146,147,148,149],{"id":144,"slug":320,"vimeo_id":321,"description":322,"tile":323,"length":324,"resources":325,"people":8,"episode_number":328,"published":329,"title":330,"video_transcript_html":331,"video_transcript_text":332,"content":8,"seo":333,"status":130,"episode_people":334,"recommendations":338,"season":339},"strictness-of-api-errors","950779919","In this recording of our live event on May 23 2024, Daniel, Jonathan, and Rick discuss making the strictness of API errors","6d44c6a0-aaa7-4ad2-bbcb-d6e0f1de2829",54,[326],{"name":304,"url":327},"https://github.com/directus/directus/discussions/4368",8,"2024-05-30","Strictness of API errors","\u003Cp>Speaker 0: Thank you for joining for this week's, session of request review. We have a fascinating topic for you, which is a little deeper than you think from the from the title. But thanks for joining. We hope you like it. This week's topic is about the strictness of API errors.\u003C/p>\u003Cp>So what does that even mean? Let's kick off with that. Everybody knows software doesn't work always quite how you want it to work, so sometimes you will receive errors in your application, and Directus is no exception. So as you might have noticed, we are very strict as of right now. So if you do something wrong, chances are high that you're just gonna see the message forbidden.\u003C/p>\u003Cp>Like, even when the message, even when the error isn't actually that type of error. So why do we even do that? Throw throwing the, throwing the conversation ball to mister Reich over there, please.\u003C/p>\u003Cp>Speaker 1: To me? Oh, man. Why do we do that? Well, it stems from a security report back in those days in that if you, let's let's use let's use a, a a 4 zero four as an example because it's it's an easy one to think about. So let's say you're fetching a collection that doesn't exist.\u003C/p>\u003Cp>Right? So you should get a 404 because the thing doesn't exist, so there's no route for it. No endpoint. If we would return a 404 for those, you could theoretically extract what the data model looks like by brute forcing your way through the whole API and checking which things return a 404 and which things return a 403, which, you know, to some security minded folks or setups, that's an issue because you don't wanna expose what type of data that you're managing in this system for security reasons. Now this is immediately where we're kicking off with opinions.\u003C/p>\u003Cp>Speaker 0: Let's go.\u003C/p>\u003Cp>Speaker 1: Because you can definitely, you know, you you can see it from both sides. You can easily say, well, that just makes the developer experience very annoying. And that's also why I created this feature request the moment I built it in this way. But it makes sense from a security perspective. Right?\u003C/p>\u003Cp>It's a similar reason why, during login, it'll say wrong email password or account doesn't exist, but you never exposed which of the 2 it is just to make sure that people can't slate, you know, what users exist. And the same goes for, you know, individual items in records. It's like you wanna, you wanna make sure that you can't just say, okay, slash item slash xyz and just keep scraping all of the different numbers, and now you know exactly what records exist, etcetera, etcetera. Somebody rightfully called out, you know, nobody does that in this trustworthy world, which I think sort of concludes this discussion then. Just ignore it.\u003C/p>\u003Cp>Speaker 0: Lying on the Internet? What? Who does that? No. What?\u003C/p>\u003Cp>No. No. No. We don't do that. And a perfect example.\u003C/p>\u003Cp>So leaking of information is a very, very big thing. You don't want to expose stuff that you don't have to expose, but as you just said, it would be nice, for example, like the most basic, setup when you're just developing locally, it would be nice if you could actually see what went wrong. Because currently, it's just okay, forbidden. Nope. No information for you.\u003C/p>\u003Cp>So then the question comes. Oh, La Prima asked, can we go on stage? Sure thing. I think so. But let's let's first, summarize a little bit.\u003C/p>\u003Cp>So There should be\u003C/p>\u003Cp>Speaker 1: a button somewhere.\u003C/p>\u003Cp>Speaker 0: The question is. Yeah. Yeah. Exactly. So, immediately the question comes to mind.\u003C/p>\u003Cp>Okay. So if you would have multiple errors in that case, a strict one which just says forbidden and another one that has more information, Okay. How many different errors would you even like to have? So are we happy with just 2? Because, I guess this is opinion alert or something, or maybe even a useful thing for many other people.\u003C/p>\u003Cp>Like, what what do you guys think about this? Like, how many error, different error, messages would be nice, would be good. Useful.\u003C/p>\u003Cp>Speaker 1: I mean, that is very much a sliding scale, isn't it? Because you really go from, from like, just give me every single thing. It's like, oh, I was trying to read the articles collection that I don't have access to. So I'm gonna get a forbidden error that says, well, articles exist, but you can't read it. And that's because of this permission that you don't have.\u003C/p>\u003Cp>For development purposes, that's really nice. But if you go to production with that, it's tricky because now you're just exposing a bunch of information about, you know, your setup. So, yeah, I'd I'd say it it there's a large range there's a large range in in that. And even within that forbidden error, you know, we can, think about how we wanna return stuff. So one thing I've been working on recently as part of this the the rules and permissions sprint that we'll we'll ship in soon is the, is that forbidden errors now include a little bit more information as in, you know, the field x that you were trying to query, you know, you don't have access to it or it doesn't exist, but at least it's a little bit more explicit while not necessarily exposing the schema, but just exposing what part of your query is wrong.\u003C/p>\u003Cp>Right? Which is not leaking any of that information but still being a little bit more useful.\u003C/p>\u003Cp>Speaker 0: Alright. That does sound exciting, to be honest. Like, it's such a developer thing, like, normal users. I don't know if how how many people care about this, but this is such a nice thing for developers. So I gather from your answer right now maybe 3 types of messages.\u003C/p>\u003Cp>At least from your answer, it sounded like 2 in the beginning, like, one strict one with a little bit of information, but that could be counted as 3, right? Like the very strict one with nothing, a strict one with a little bit, and another one with very much information. Are we happy with 3?\u003C/p>\u003Cp>Speaker 1: No? Yes. Asterisk. There's one more tricky thing in that the output type signature of the errors themselves change between those modes Right? So for example, if you're trying to fetch a thing that doesn't exist, we want to return a 404 status code with a not found error message.\u003C/p>\u003Cp>If you then program your app around that, you know, that it on your front end, it shows, you know, something because it checks 4 Oh, it was a 404 status. Therefore, do this logic. Right? The moment you now change that option to be strict when you go to production, that messes up again. Because now it's returning a 403 with a forbidden instead of a 404 with a not found.\u003C/p>\u003Cp>Cricky.\u003C/p>\u003Cp>Speaker 0: So Let's see. May maybe maybe after we dive in a little bit deeper, we have more clarity around this. But so far, like, I personally like would like, I think, 3 modes. Let let's call them levels. Do we call them levels, modes?\u003C/p>\u003Cp>I think levels. Right?\u003C/p>\u003Cp>Speaker 1: Yeah. It depends. As per usual, it's\u003C/p>\u003Cp>Speaker 0: great.\u003C/p>\u003Cp>Speaker 1: It it depends on, you know, are we considering multiple different flavors at the same time, or is it just an on and off? Because somebody in the chat just now rightfully mentioned, maybe it's just a single production versus development flag that changes that. Right? It could also be a setting within the app. Maybe it's even a setting on a per collection basis that you wanna say, well, this collection is not as, you know, private as the other ones.\u003C/p>\u003Cp>So for this one I wanna have, you know, nice and friendly, messages. And for the rest, we wanna keep private. There's options. It's tricky. It's it's when it comes to a single sort of Boolean flag that says production yes or no, I would be a little bit worried about getting into a point where undoubtedly 3 months later, somebody will show up and be like, well, we kinda need something in between.\u003C/p>\u003Cp>You know?\u003C/p>\u003Cp>Speaker 0: Exactly. You\u003C/p>\u003Cp>Speaker 1: can't really\u003C/p>\u003Cp>Speaker 2: Or more importantly, somebody develops in development mode thinking they've got those messages, then they move that code to production, and suddenly nothing works.\u003C/p>\u003Cp>Speaker 1: Right. Which is gonna be a bit of an issue no matter what because\u003C/p>\u003Cp>Speaker 0: Agreed.\u003C/p>\u003Cp>Speaker 1: We're not talking about, you know, changing the output errors. You could consider those, part of, the the what what would you call it? The public API contract of the APIs that you're building against. Right? Because because, you know, in your intro then, you said stuff sometimes crashes, and that's just part of part of software life.\u003C/p>\u003Cp>Stuff crashes on purpose. Right? In this case, like when validation fails, it's we're still throwing an error, but it's not an unexpected error or anything else. It's, you know, we stop you from doing something on purpose, so we throw an error, which is, you know, a bit of a difference there as well, of course. Because when it comes to exposing internal server errors, it's a whole different question.\u003C/p>\u003Cp>Because right now we do a similar thing, right, where we say you just get internal server error. That's it. Like regular users don't see anything else. If you're an admin user though, that's today, that's the difference. It'll show, you know, the stack trace of the actual JavaScript error, with where in the source codes it it it happened.\u003C/p>\u003Cp>So but exposing internal server errors to non authenticated users, that's gonna be that could easily become an issue. Right? Because now you find some sort of vulnerability path or whatever that's you don't wanna expose that.\u003C/p>\u003Cp>Speaker 0: Definitely.\u003C/p>\u003Cp>Speaker 1: From the chat, somebody has a suggestion here. It says, what about setting a trusted IP address? So you can just say, okay. When I am the one from my home to do this, I get all the pretty errors and otherwise, I can't. I think you're gonna have a similar issue with, you know, def versus prod, strict versus friendly error types, and how do you handle those in your app.\u003C/p>\u003Cp>It's gonna be a tricky tricky thing to figure out. And then somebody else said, the only thing where that really isn't enough is when there's a delete constraint. Users trying to delete items, and they can be deleted because they're still a referencing item. Admins already get a little oh, yeah. That's yeah.\u003C/p>\u003Cp>Because right now that is technically, a database error that bubbles up. So it comes out as an internal server error that for admins, it'll show the the SQL error underneath. But for regular users, they just get a whoops, you know, internal server error.\u003C/p>\u003Cp>Speaker 0: Also with the IP, since currently currently, IP access, is attributed to roles. Right? You you customize that on a role with that access. So we could use that, but it does, like, sound very, very, very likely to me that you wouldn't be interested in, like, giving this to every single user of that role. You would like to have something more granular than that.\u003C/p>\u003Cp>So how about this also comes from, someone from the community. How about we attach this to permissions themselves? So let's say this user can access this and that, and that user is authorized to receive better errors than other users. For example, like, the simplest example, like admin users. Right?\u003C/p>\u003Cp>Mhmm. Like, all admin users are allowed to get the best errors that you can, But users other users get strict errors. Okay? But that, yeah. That's that, like, I I I'm not really sure how exactly complicated that would be to do at every single point in the in the code base.\u003C/p>\u003Cp>Speaker 1: Well, I mean, in in terms of implementation, how like, they currently were throwing forbidden errors all over the place, but the way this would work in implementation is right at the end where we return the error in the APIs, that's where the sort of translation layer kicks in. Right? So all over the code base, it should just throw the actual errors or the actual error types and the correct ones. So if you're trying to hit something that doesn't exist, it should throw a not found error. And then all the way at the end in the middleware stack in the error response handler, it should say, oh, if your current, you know, e n v setting for errors or if the, which I'm gonna call it, if the the error permissions or whatever you wanna call it are set to a certain state, then it translates them into a different way.\u003C/p>\u003Cp>I think that's the way that that will be implemented realistically speaking.\u003C/p>\u003Cp>Speaker 0: Yeah. That does sound quite good. Adjust intercept as a middleware. Okay. You are allowed to see this or not.\u003C/p>\u003Cp>Okay.\u003C/p>\u003Cp>Speaker 1: Yeah. Because we're doing that on a case by case. It's gonna be insane. Just trying to do it every single time that we throw an error. That's that's too much.\u003C/p>\u003Cp>We currently already do a similar thing, right, where the the error handling stack, we check was this a direct as error type or any other error and that chooses between internal server error or, sort of the the expected error output.\u003C/p>\u003Cp>Speaker 0: Very reasonable. I think, if somebody from the chat also has another recommendation or anything, please let us know. There's quite a quite a bit of action today, which is pretty nice, actually. Like, seeing the chat scroll up and down is pretty nice. Somebody says, I can't explain it in the chat, but I'll try.\u003C/p>\u003Cp>That's lovely.\u003C/p>\u003Cp>Speaker 2: Well, well, La Prema can if if you you guys are okay with it, La Prema can join us on the stage.\u003C/p>\u003Cp>Speaker 1: Yeah. I'm down. There should be a button somewhere that just says, I\u003C/p>\u003Cp>Speaker 2: can invite them or they can add they can request, but we can also do an invite.\u003C/p>\u003Cp>Speaker 1: How is that often with these?\u003C/p>\u003Cp>Speaker 2: They asked to speak earlier, so I'm inviting. Or have they does Kevin have that blocked in this event?\u003C/p>\u003Cp>Speaker 1: Oh, boy. With this guy.\u003C/p>\u003Cp>Speaker 2: Nope. Nope. There we go.\u003C/p>\u003Cp>Speaker 1: I got the invite. I got Does it work? I got\u003C/p>\u003Cp>Speaker 2: him up here.\u003C/p>\u003Cp>Speaker 3: I'm trying to\u003C/p>\u003Cp>Speaker 0: see if I wait. Weekend.\u003C/p>\u003Cp>Speaker 3: Yeah. It works. Okay.\u003C/p>\u003Cp>Speaker 1: It works. Hello. Welcome. Hello.\u003C/p>\u003Cp>Speaker 3: As always, sorry for my accent. I'm I'm Frenchy. But, like, I Don't worry.\u003C/p>\u003Cp>Speaker 1: You're you're chatting with a Dutch and a German, so we we know you need to know the guy.\u003C/p>\u003Cp>Speaker 3: Oh, yeah. But your English is better than mine. I don't know if you remember, but we used to talk to Get A Rich for about the the error management system. And at that time, I was working for a company who uses directors, but I leave them. So after, what I haven't the time to to follow the the the case of the the server management system.\u003C/p>\u003Cp>But, I think the the main problem, we had is is, dealing with the the the, yeah, the, like, the granular system of a thing. And what I proposed at the that time was, like, adding in the the collection a a new, column, like, you already have, edit and all that stuff. And, in permission, column where you will have, like, 1 or 2 level no. Mostly 2, but 2 or 3 level of, strictness of the error. Like, do do do I wanna send them all on that collection or not?\u003C/p>\u003Cp>Because, yeah, I I think that would be the I'm sorry. But because it's user related, it would be better for the companies. Because, if you if you, like, have only one private, instance of directors, I think it's not a problem to throw error to people because they are part of the company. So if they don't, respect them, their permissions, you they can have, like, legal, troubles, and this is possible. But if you have, like, an public API and also a private one, On one instances, if it's just a mode, I think it won't fit because a lot of data can be really sensitive.\u003C/p>\u003Cp>And, same goes with the developer mode. Yeah. I I totally agree with, like, developing something, in a in a development mode and then going to production, it doesn't work. That would not be a solution for me. And, as well that the the this this production and development mode would be probably used somewhere else, at another time.\u003C/p>\u003Cp>And, in a long term view, that will just lean in people active in the development, mode every time and, development searching, be thrown everywhere.\u003C/p>\u003Cp>Speaker 1: Yeah. That's right. It's such a tricky, and I I think if that, what was that nodes flag called? It node e and v or something as taught as anything is that you should not rely on a single dev and prod flag. Yeah.\u003C/p>\u003Cp>No. It's a good one. It's the the doing it on a collection level, on a permissions level for for collections, basically. It's it's a good angle. It's it raises some different interesting questions though as per usual.\u003C/p>\u003Cp>Everything does, Especially around requests that touch multiple collections at the same time, right? Where in REST, you can technically go, you know, nest it and then you end up with you could have an error that's thrown in the sort of nested layer of the same request. Or in a GraphQL request, you can technically request multiple collections at the root level at the same time. And then it gets a little interesting because now you can get, you know, a different error output from that request based on which of the data points of that request crashed, I guess, instead of, you know, the request itself,\u003C/p>\u003Cp>Speaker 3: which opens a little\u003C/p>\u003Cp>Speaker 1: bit of a different kind of words.\u003C/p>\u003Cp>Speaker 3: Yeah. But I I think in some case, that's what we want. Because, in the the app I I was working on, we we used to to to get in that kind of problem where, we have people, who had access to certain company, but not certain order. And we retrieve that data in one block. And if some points fails, the the whole, request will fail, so we'll have to deal with that.\u003C/p>\u003Cp>And, what what we can do at that point, I guess, it's when you you have the error only in one part of the query, it's just returning not an error not an error code, but just like in the API, an error, tag in, that object and not all the thing. But I I know that would be, like, a big breaking change. So it can be hard to implement for some people. But, I guess, by default, if we just disable all the error, like, the the basic settings will just be, what Direct just currently does, it won't be a problem because the people who turn the the feature on, would know what they do or or would have ways to find out.\u003C/p>\u003Cp>Speaker 1: I think that is\u003C/p>\u003Cp>Speaker 0: You're you're just assuming that people know what they do. I barely know what I'm doing. And when when I add features oh, no.\u003C/p>\u003Cp>Speaker 1: I think, it it there's a there's a new question hidden in there that we hadn't touched on yet, nor in our notes right now, which is if an error is thrown somewhere nested, let's say, you know, the let's use the GraphQL as an example because it's it's easy to reason about. Let's let's say you're requesting 5 collections of data at the same time. Right? And one of the 5 crashes. The question is, do you return an error and the whole thing failed, or do you return the data that worked and then have an additional error flag that just indicates this is the path of your query that didn't work?\u003C/p>\u003Cp>But return what you have and leave the rest.\u003C/p>\u003Cp>Speaker 3: And, I think for that opinions. Yeah. I think for that, the the the best way to to do it is just, like, throwing the error only for what phase. Because, if we use these directives, I assume it's that we just want to cut the the front end. And and so, it it would be, most of the time, like, an interactive app or a single page application on or something of of that kind.\u003C/p>\u003Cp>And those kind of errors are really easy to to treat with that method. So and and, I I think most of the time, if we activate the the feature, it's what we want because, that will lead in, less, just big crashes, like internal server error proof and nothing worse. So I don't know.\u003C/p>\u003Cp>Speaker 1: It's it's an interesting one because, somebody in Chet just now says it too. It's a rather fundamental question. But, you know, you see both in the wild, and both are kinda alright. It's it's, there's also an implicit difference between, you know, reading and write operations there as well, of course, that if you do a large nested update, you kinda want it to work as a single unit, as a single transaction to make sure that if, you know, part of the insertion doesn't work or part of the update, the whole thing shouldn't, you know, go through because otherwise you have that sort of half half done state. But for read queries, it could be different, but that really depends on, you know, what are you reading, and is it all tightly coupled, or are you reading multiple things at the same time for convenience sake?\u003C/p>\u003Cp>Because if I'm not mistaken, in in sort of the GraphQL spec, Like, it allows you to return partial data and then errors for other root fields. But I feel like if there's an error in a nested field in the query, it'll still fill that one sort of root query as a whole. But that is that is something I love to double check.\u003C/p>\u003Cp>Speaker 0: Yeah. Yeah. I'm I'm I'm not sure either. Like, my my gut feeling was, no. I I I don't wanna say something wrong right now.\u003C/p>\u003Cp>So, okay. Another another suggestion from the chat. How about hashing the error plus a UUID, I assume that is? Only admins will be able to see what the error really is. Well, I mean, I mean, you are probably talking about, like, error codes.\u003C/p>\u003Cp>Like, for example, many different other apps just say, okay this is error 3, 1,172 or something. And then you can look up internally what that exactly means, But, you would still be missing out on, like, more information, like the stack trace or which which file failed or something something that you would have to encode in that thing, but I don't think that's always possible or\u003C/p>\u003Cp>Speaker 1: even Or to just think very divergently. You know, an alternative approach is that you basically encrypt the whole error, save that to a database, and then only return the ID of the error that it was. So then the admin can log in and look up what the full stack was and and and and sort of decrypt it and see the whole the whole contents and everything else. But that that feels like a way to sort of persist to security and give more information at the same time. But it also feels like another skip and a hop and a skip for regular users to be able to just, you know, use do the errors that are output.\u003C/p>\u003Cp>Speaker 0: That's an interesting thing. I have never thought about it like that. People do that? Do their apps do that? That's interesting.\u003C/p>\u003Cp>Speaker 3: Yes. Some app does. I I used to work on one with the that. But I think it's the it's a problem because, like, most of the time, you you wanna informing in some way your user of what the error is because you don't want to to get someone just to to create a ticket to the IT support just every time they need, something, didn't work. But they just didn't have the permission in the first time.\u003C/p>\u003Cp>So, yeah, I don't think, it's a global sit solution. But maybe in some case in some case, if if we add, like, an EMV approach, that would be a a great option for some people that maybe need that.\u003C/p>\u003Cp>Speaker 1: And I could see it work like that for for internal server errors. Right? Well, that's one of those things where we wanna hide away the stack trace no matter what for for the API output and then save it elsewhere. But at the same time, you know, saving every error could easily blow up in your face too, because if you just have, you know, an unauthenticated user that tries to access some data there's no permissions for, we don't wanna save those. Right?\u003C/p>\u003Cp>Because now you could easily just blow up a database by a public malicious actor that just spams your API knowing that they're gonna get errors. So there is there is definitely a a difference between sort of expected and unexpected errors there and which ones are saved. Have AI blocked them. AI solves all of our problems.\u003C/p>\u003Cp>Speaker 0: Sure. Just do what I want. Parentheses open, parenthesis close. That should do it. Right?\u003C/p>\u003Cp>If only if only it would be that easy. K. So let's let's summarize a little bit because we have been, you know, throwing stuff out there. Maybe we should get back to reality a little bit. So, okay.\u003C/p>\u003Cp>So so let's say we have, we like to use the Moscow list. Right? The must have, should have, could have, type of stuff. So for must haves, let's let's get on the same train. Like like, what do we need?\u003C/p>\u003Cp>What what must we include? So, yeah. How granular do we make this? Oh, no. It has to be actionable, man.\u003C/p>\u003Cp>It has to be actionable. Okay.\u003C/p>\u003Cp>Speaker 3: I I think the the point where we've been stuck the the last time was reached is, like, we we both agree on the fact we need a granular system, but we both must agree, on the fact that it would be so long to to make and to think and all that stuff that maybe it would be nice to have something, before that. But,\u003C/p>\u003Cp>Speaker 1: Right. Yeah.\u003C/p>\u003Cp>Speaker 3: Yeah.\u003C/p>\u003Cp>Speaker 1: Yeah.\u003C/p>\u003Cp>Speaker 3: But, I I think, that's, my my point was, like, directors, is a tool who is proposing things like a a different way than the other, tools in the same category. Like, you you just want it to to be a little more, accessible and, and usable. And not just, like, being that's the way you should do that and, just follow it. And and so I I think that's the problem there. If we did something else, than a granular system, you would, follow a path that doesn't feels like directors to me.\u003C/p>\u003Cp>And I don't know that that's totally your point, but but, I I'm not sure if that's what people need. Otherwise, they they will lose WordPress or or something like that.\u003C/p>\u003Cp>Speaker 1: You you you sound like a team member in the sense of when the choice arises, let's do it the difficult way and make it unopinionated wherever we can. So no. I I do agree though. I do agree because it's it it is at the end of the day, this is a very opinionated thing, where for some apps, it's acceptable to have it a little looser or even want it. For some, you know, security minded folks, it's absolutely not, and we can't really make that decision for people at that global level, even though we have right now.\u003C/p>\u003Cp>Oops. Right now we are on the side of safety first, which, you know, it's it's defendable, but not ideal. Like, that's also why I created that feature request. It feels like decades ago, but it was 3 years. I think that the the main unresolved question now, and and that is sort of to answer your point, Dan, before we can really fill in the blanks for what are the must haves, is what is that ideal approach to how do you configure this?\u003C/p>\u003Cp>And then from from a developer experience first and then secondly does that make sense from an implementation perspective. Because doing it on the collection scope level makes sense for errors that are thrown on the collection scope, but not all errors are thrown within the context of a single collection. So that that that opens up, you know, new questions. And the opposite is true for doing it globally on the e and v level. Right?\u003C/p>\u003Cp>Because, you know, it's a low pretty much excellent point. It's not that black on white that you say make it insecure for the whole API. You know, you wanna do it on a case by case basis. That is a that's a that's just a statement with no no answer.\u003C/p>\u003Cp>Speaker 3: No. I don't another, I don't know what to say it in English, but, like, another thing we, think about at time was, like, just, if if we take, like, the the point, if we need the error, it's just to treat them. One, thing, which, was a a little bit, between the two option is just like, having some kind of way to tell directors just, okay. This error, I want you to to throw it, and other errors I don't want. So that would be a little bit more granular, but that would be more like, just a techy approach.\u003C/p>\u003Cp>And and then not, being, so universal.\u003C/p>\u003Cp>Speaker 0: Oh, Rike, you're muted, by the way.\u003C/p>\u003Cp>Speaker 1: I hit the wrong mute button. That's what you get when you have 2. I I muted myself here, and then I and then I muted myself to unmute on this. Oh, man. I mean, we've only been doing this remote thing for about 5 years now, so I'm I'll I'll get it.\u003C/p>\u003Cp>Yeah. Because I what what I was trying to say is that that approach to say, okay, which error types do we expose? That is something we could do on the role level or soon to be policy level, And it is a system where we can still have one translation middleware that handles that error no matter where is thrown from, which is you if you compare that to the sort of collection idea that we had earlier, that one is a little trickier to implement in that sense, because now you have to make sure that you know what the collection context is for every single function call that may or may not throw an error. And then do that sort of translation piece, in in situ of where those errors are created, That makes sense. Whereas with, you know, an approach where you say, okay, not found errors can be exposed.\u003C/p>\u003Cp>If that's your setting, we can do that on one middleware at the end of the stack to just say, okay. Was the error\u003C/p>\u003Cp>Speaker 0: Again, I'm not sure if if I can wrap my head around every single edge case, but, like, it does sound and may maybe I understood it a little incorrectly, but it does sound quite easy to mess that up. Like, it to to to bubble to bubble something up that does not get blocked then. And somehow I am exposing a random error that I have not thought about, like, on on an error level.\u003C/p>\u003Cp>Speaker 1: It's it's the difference of an allow list versus a deny list is basically what you're saying. Right? So if you have a filter where you're denying individual pieces, it's easy to miss something. Whereas we do the opposite way where it's blocked by default and you allow more and more stuff, it's you can't really accidentally expose anything because nothing is exposed by default. Which is similar to what, Andre Andre Andre Key are.\u003C/p>\u003Cp>Just gonna assume that's how you pronounce it. Just said in the chat as well as, you know, if you really want it super granular, effectively just make it a rule based system, right. Where you run a filter against the error object that is thrown. Like if the error types is XYZ and the extensions contain blah, blah, blah, collections, such and such, then expose it, which will be one way to make that super granular, but also a little harder to configure at that point. Because I could, I mean, at the end of the day, I could also imagine that, you know, for just local development, that is gonna be a pain in the ass because now you have to configure so much stuff to get the errors out.\u003C/p>\u003Cp>Speaker 3: I I think we what we could do is just like doing an EMV, variable just for real development case, then that system for the production mode. And later on, if we think it's too difficult or, then we can add the system, with the the permissions because that would make, like, stacks on top of each each other, with the the the the first step would be, like, the programmatic approach on the error throwing and all. And then, the the we could add later on just, instead of just throwing nothing if the error do not doesn't match, any case. Like, is it a permission error? Then is there a plain way to treat it?\u003C/p>\u003Cp>So it's made steps, and we have something, in between no permission management and on the other end, full thing.\u003C/p>\u003Cp>Speaker 2: What this makes me think of is the we've got a client that we're playing around within a proof of concept. They're they're actually have an error table for their front end, and they've actually got translations. So they've actually got a translations table on that so that they can have the language the errors translated to multiple languages. If we went something like that where we have, like, a direct us errors collection, right, as part of the system tables with a set of, you know, with translation, then we have native translations capabilities right there. So if you wanna adjust the error message, so we could have the defaults.\u003C/p>\u003Cp>Right? The I don't know. We've got a dozen or whatever that we have now, with some variable support maybe even there so that if you wanted collection information or you want that stack trace information to percolate up, you could. And you could determine at least in the short term, we can we can avoid the permissions for the short term, give you just control over your error messages. You wanna show something that we don't do natively by default, well, you can override the messaging as a thought.\u003C/p>\u003Cp>And I think that would actually help with things like flows as well. We have the same problem in flows. We can't percolate an error message to the user even though we're throwing and controlling the erroring of the of the workflow. Potentially, if we think about it in that context as well where we've got we could use that same error structure\u003C/p>\u003Cp>Speaker 1: Mhmm.\u003C/p>\u003Cp>Speaker 2: Idea. Not a not necessarily the solution or the right solution, but\u003C/p>\u003Cp>Speaker 1: here's the new rabbit hole, multilingual error output for the API. Oh, boy. Oh, boy. I mean, sort of it's an interesting angle to to sort of noodle on a little bit. The the general idea of errors as it stands right now is that you basically return an error code that is one of the standard sort of known error types.\u003C/p>\u003Cp>And then in whatever app that you're building, you can basically just say, you know, oh, if the error is not found, then use my own translations and my own front end and all that kind of stuff. But yeah. I mean, it it does raise I mean, we we know we need some sort of translations in the API no matter what for email templating, which has been that'll be a fun discussion for another day. But, yeah, it's it's an interesting idea to have errors as a sort of system collection that you can then modify. Although, we would have to hard code in what the keys are because otherwise, we don't know what error to throw still.\u003C/p>\u003Cp>That's a tricky one.\u003C/p>\u003Cp>Speaker 2: But we can hard set the keys. Right? And then if you create your own key or we lock the table, you're not allowed to add to it, you know, without core functionality. Or, again, you've got your hard set core pieces. Core knows what they are, and they can't be changed.\u003C/p>\u003Cp>Their primary key or whatever we wanna do around that Yeah. Gives us that level of flexibility. But then if users want to code other error messages for other applications and data, they can actually still maintain it in all in one place. I'm not smart enough to solve it. I just I just know that's an implementation I saw recently where we're for a front end application and the error messages that they wanna generate for that front end application.\u003C/p>\u003Cp>They're actually doing that in a set of tables. Kinda cool.\u003C/p>\u003Cp>Speaker 0: Oh, I think, like, lots of interesting things that we can do, but I think we're still stuck on where do we want to control this or configure this. Let's just go to the one extreme. I mean, very That would be the easiest thing.\u003C/p>\u003Cp>Speaker 1: You have\u003C/p>\u003Cp>Speaker 0: to And you get errors. Okay. Done. That's the easiest thing that we can do. That leaves a couple of things that we would like to have open.\u003C/p>\u003Cp>Right? Like, we ideally, or at least in my mind, it would be really useful if, for example, like, admins actually get no like, good, context rich errors and normal users don't, which would you know, it's not really that possible with that environment variable approach.\u003C/p>\u003Cp>Speaker 1: Yeah. So so it feels to me like out of everything that we've discussed so far, the direction where you effectively set up and allow list of errors on the role or soon policy level gives you, so far everything that we sort of want to achieve. Right? Where you can say, okay, you can allow one admin role to just see all of the errors with some sort of wild card flick, accept everything, allow everything. You could use the filter rules to be more granular that you could say, oh, if the error contains a collection, flag, then filter against that.\u003C/p>\u003Cp>So So you can you can do sort of the collection by collection, filtering. And, yeah. You you get to choose role by role, so make it admin only or make it make it, a different, you know. So the users can only see the granular errors for a a collection that's already public or something like that.\u003C/p>\u003Cp>Speaker 3: The the only problem there, it's for the flows. But, like, what do we do with them?\u003C/p>\u003Cp>Speaker 0: Mhmm. Mhmm.\u003C/p>\u003Cp>Speaker 3: For flow, that's\u003C/p>\u003Cp>Speaker 0: a grant. Like\u003C/p>\u003Cp>Speaker 3: Because I I think we could have\u003C/p>\u003Cp>Speaker 0: close the\u003C/p>\u003Cp>Speaker 3: The same system, like, in the in the settings of the flows. But is it gonna be the same way?\u003C/p>\u003Cp>Speaker 1: But we could also say that if you trigger a flow, you are a user or the public role. So therefore, the same settings of your role should still kick in.\u003C/p>\u003Cp>Speaker 3: Yeah. Yeah. Because they access the data. So that's good point. But, like, what if you want to, bypass a permission on a specific flow?\u003C/p>\u003Cp>Like, then you'll because in some case, may maybe it's the the old data you don't want to access, but just one field you want to show someone?\u003C/p>\u003Cp>Speaker 2: As long as the filtering's happening on the API level, that's still all API under you know, flows is still API under the hood. So if you uplift an operation, read CRUD, whatever, this the erroring although, I guess, it's still gonna then it would percolate to that user\u003C/p>\u003Cp>Speaker 1: type I think the the the underlying question is what if you want that error to be returned no matter what the settings are in your flow? Because your flow is effectively a custom endpoint or, you know, hook or whatever.\u003C/p>\u003Cp>Speaker 2: Yeah. That's what I think flows when you're throwing an error inside flows, that should be its own code. And if you throw a custom message back to that, then you should be able to get that custom message. That's the key thing that I always want. Right?\u003C/p>\u003Cp>Or that it the the initially, I thought was, oh, I'm gonna throw an error here and I wanna I wanna send back to the user, you know, you did x y z wrong, you know, or this this isn't allowed because you failed to give me the appropriate information instead of a internal server error, which means nothing. You know, I can't I can't tell the user what they've done wrong or what they're violating that I'm validating inside of my flow. I can't say, mister user, you must have your status in the right thing or, you know, these three fields have to be populated to be able to use this or\u003C/p>\u003Cp>Speaker 1: And and that's where the allow list approach for error filtering gets tricky again, because now you need to make sure that you allow list your custom errors from your flow in the policy or in the role, so it makes its way to the app.\u003C/p>\u003Cp>Speaker 2: Or I think, again, flows the error code or codes that are returned by flows, that there is a specific code, and you simply take the message that the user's providing out of the out of the, you know, exception. Yeah.\u003C/p>\u003Cp>Speaker 3: Yeah.\u003C/p>\u003Cp>Speaker 2: Yeah. Right. And so it's it's a known code. We know what it is. Right?\u003C/p>\u003Cp>We know\u003C/p>\u003Cp>Speaker 1: Oh, so here's here's another thing we haven't really message. Yeah. Another thing we haven't really touched on in with regards to flows is that, you know, you have a very explicit error handling path that every operation has a okay. If the error fill or if the operation fails, do something else. So maybe there should just be an explicit operation that says return the error, and otherwise it just defaults to, you know, hidden by default, but then it becomes it it no longer is a a permissions or roles thing.\u003C/p>\u003Cp>It just becomes a flow thing, where you just very exclusively have to end your flow with return the actual error. And at that point, it's up to the, you know, the admin to configure that flow and and whatever they want to return.\u003C/p>\u003Cp>Speaker 2: Love it.\u003C/p>\u003Cp>Speaker 3: Me too. Convinced. But\u003C/p>\u003Cp>Speaker 1: yeah. Yeah. Okay. Problem solved.\u003C/p>\u003Cp>Speaker 3: We would have we would have to to, like, also have a a custom error block, I think, if you if we do that that way.\u003C/p>\u003Cp>Speaker 1: Yeah. Yeah. Just an operation that says make a new error, whatever that error is.\u003C/p>\u003Cp>Speaker 3: Yeah. And you can pass the a variable or a text or something. Yeah.\u003C/p>\u003Cp>Speaker 1: Which is then a funny new completely unrelated question. But if you have a block that says create an error, is the good path the error or is the bad path the error?\u003C/p>\u003Cp>Speaker 3: I I think you can you can do this.\u003C/p>\u003Cp>Speaker 2: There is no path. You don't get to you don't get to leave. That's the end. You're finished. Termination note.\u003C/p>\u003Cp>Speaker 3: I think the I don't I don't know. Like, I think there you called it, like, grade pass and, error pass, but I think in so in some time, like, on the if call, trigger, the error pass is not really an error pass. So\u003C/p>\u003Cp>Speaker 1: Right. Yeah.\u003C/p>\u003Cp>Speaker 3: That would be sense to be both, really.\u003C/p>\u003Cp>Speaker 1: Yeah. So in the create an error operation, both both are the same. It just calls both.\u003C/p>\u003Cp>Speaker 3: Yeah. And then\u003C/p>\u003Cp>Speaker 1: Now you have oh, woah. Woah. But if it calls both, now you have a way to do parallel split paths because it's now\u003C/p>\u003Cp>Speaker 0: a trick.\u003C/p>\u003Cp>Speaker 1: That's a discussion\u003C/p>\u003Cp>Speaker 2: for the problem.\u003C/p>\u003Cp>Speaker 3: I I think that would be nice, but yeah. That would be a lot for that,\u003C/p>\u003Cp>Speaker 2: more importantly, I want merge capability. Be able to rejoin back into logic.\u003C/p>\u003Cp>Speaker 1: Oh, good lord. Now you have to wait for both to be done and oh, boy. Okay. Let's definitely not get into this.\u003C/p>\u003Cp>Speaker 2: We've got we've got very divergent. We have about 9 minutes left, folks.\u003C/p>\u003Cp>Speaker 1: Yeah. This this feels like another 6 hour discussion if we go that route.\u003C/p>\u003Cp>Speaker 2: It is a very, very long discussion. Flows 2.0. We're already doing some research on that, so figure out what that looks like long term. Okay. Back to API errors.\u003C/p>\u003Cp>Do we have an idea of what our must have\u003C/p>\u003Cp>Speaker 3: should have?\u003C/p>\u003Cp>Speaker 1: Yeah. I think my my current going direction is is basically the on the role level, there is an allow list type configuration that allows you to say there needs to be a wild card that says do everything for def purposes and otherwise you can use the sort of filter structure that we have to say these are the error types that we allow you to see, and these are the and then based on whatever the error contains, you can filter it more granularly if you want to. That's for me closer to a should have than a must have. The error types is really the main the heart must have MVP. Because then because our error objects, they are, you know, they have additional extensions is what I called them right now, which is basically, a not found error can have a collection flag that says this is the collection that was not found.\u003C/p>\u003Cp>And therefore, you can use those flags inside of the filter as well to just make it real granular. And then for for flows specific specifically, just to reiterate what we just said, is you wanna have some sort of operation that it it's almost like the end of the line operation that should that sort of allows you to say, okay. This is what we're returning now, in the output. And then that could be that can have a couple of settings like, what is the status? What is the, what is the message?\u003C/p>\u003Cp>What's the body? And then that body can be generated using a, sort of create error operation. So I think that would be a nice setup if we have 2 additional operations. 1 to create an error that this custom, but uses the direct as error format and everything else to make it system standard. Therefore, you can use it in things like manual triggers to output an error to the client.\u003C/p>\u003Cp>And then we need to have some sort of operation that you can use at the end of your chain to say return the data and then just format it in this in a certain way, to really allow you a lot of control about the request.\u003C/p>\u003Cp>Speaker 0: Okay. Rest of energetic typing.\u003C/p>\u003Cp>Speaker 3: This is satisfying.\u003C/p>\u003Cp>Speaker 1: It was very nice to listen to.\u003C/p>\u003Cp>Speaker 3: ASMR.\u003C/p>\u003Cp>Speaker 0: Now we switch to the ASMR section of the Can you just show\u003C/p>\u003Cp>Speaker 1: this video?\u003C/p>\u003Cp>Speaker 0: Everybody quiet. Everybody quiet.\u003C/p>\u003Cp>Speaker 1: Oh, no. Oh, no.\u003C/p>\u003Cp>Speaker 0: Let's not do this. Okay.\u003C/p>\u003Cp>Speaker 1: Alright. This this feels pretty good so far. Did we we I know we we chatted a little bit before we hopped on this session. Did we have any other questions that we prepared for this? I think I think we have for most of it.\u003C/p>\u003Cp>Let me pull it off here on the second screen that is off camera. Why are we returning for threes? Went through that. How many lovelies? We kinda figured that one out.\u003C/p>\u003Cp>It could be an environment variable, but you kinda just just figure that out. And then business logic existing scripts expected specific error code. Yeah. I mean yeah. I mean, I think we're gonna we've answered all the points that we sort of note note beforehand.\u003C/p>\u003Cp>Speaker 3: I I just have and I I know I think someone in the chat is just saying, like, for what about the extensions? But I think for the extensions, we can just have, like, a a JavaScript function with with the same as the one in flows and just like custom chats.\u003C/p>\u003Cp>Speaker 1: Yeah. Because we do we we haven't really documented it too properly yet because it's sort of it was a little bit in flux still, but we made that direct as error specage with a function that you can use to make a new sort of, like, error a direct as error that direct as then like, what's the right word? Recognizes as a direct as error that you can then throw to make sure that no d ep and API behave in the same way as the system would so for for custom extensions that should sort of be solved, which is good. Put that direction. Yeah.\u003C/p>\u003Cp>With that being said, I think we have a for the first time ever in one of these sessions, we left it off with a pretty clear idea of what we actually wanna do. It's usually, we go way too deep and then have a sort of couple ideas. But\u003C/p>\u003Cp>Speaker 0: But it's we're trying. This is my\u003C/p>\u003Cp>Speaker 1: No. No.\u003C/p>\u003Cp>Speaker 3: I I was going to to say it's just because it's a refurbish version of what we already think of later.\u003C/p>\u003Cp>Speaker 1: Yeah. Well, you'd you'd think that about every time we do a feature request review, and it's it's never never the case.\u003C/p>\u003Cp>Speaker 3: Like, a 2 years old idea or something. Okay. Maybe Yeah. Not 2 years, but, oh, yeah. It must be.\u003C/p>\u003Cp>Like, I I see 2022. So yeah. Kinda.\u003C/p>\u003Cp>Speaker 1: How passionate people got in the actual feature request that somebody said. It's like, this is the single worst thing about I hate it so much. My whole month is ruined because Directus' errors are too strict.\u003C/p>\u003Cp>Speaker 3: No. But, sir, seriously, like\u003C/p>\u003Cp>Speaker 0: I wish. I wish. Yeah. I wish director's errors were the worst thing in directors. Then directors would be very nice.\u003C/p>\u003Cp>Speaker 1: Yeah. That's actually a good point. Yeah. Ouch. If this is if this is the worst problem to talk about, then we're doing real well.\u003C/p>\u003Cp>Speaker 0: Then we're really golden. We're good and then.\u003C/p>\u003Cp>Speaker 1: Alright. Well, we're we're slipping a little bit, but let's call it for now. I wanna say as per use, thanks everybody for watching. This will be going live on direct TV, which is direct. Io/tv.\u003C/p>\u003Cp>If you haven't seen it yet, book market sends to your friends, your family, everybody else, Share it on LinkedIn, Twitter, x, whatever you whatever your flavor of the week is. We'll be back in, I think, 2 weeks. Am I saying that right? Uh-oh. Should have prepped this.\u003C/p>\u003Cp>Yes. We'll be back in 2 weeks exact, June 6th with another one. Oh, hello. Another one of these party full sessions. But until then, thanks for watching, and we'll see you next time.\u003C/p>\u003Cp>Speaker 2: Happy coding.\u003C/p>\u003Cp>Speaker 1: Bye. Like and subscribe. Save me from the algorithm.\u003C/p>","Thank you for joining for this week's, session of request review. We have a fascinating topic for you, which is a little deeper than you think from the from the title. But thanks for joining. We hope you like it. This week's topic is about the strictness of API errors. So what does that even mean? Let's kick off with that. Everybody knows software doesn't work always quite how you want it to work, so sometimes you will receive errors in your application, and Directus is no exception. So as you might have noticed, we are very strict as of right now. So if you do something wrong, chances are high that you're just gonna see the message forbidden. Like, even when the message, even when the error isn't actually that type of error. So why do we even do that? Throw throwing the, throwing the conversation ball to mister Reich over there, please. To me? Oh, man. Why do we do that? Well, it stems from a security report back in those days in that if you, let's let's use let's use a, a a 4 zero four as an example because it's it's an easy one to think about. So let's say you're fetching a collection that doesn't exist. Right? So you should get a 404 because the thing doesn't exist, so there's no route for it. No endpoint. If we would return a 404 for those, you could theoretically extract what the data model looks like by brute forcing your way through the whole API and checking which things return a 404 and which things return a 403, which, you know, to some security minded folks or setups, that's an issue because you don't wanna expose what type of data that you're managing in this system for security reasons. Now this is immediately where we're kicking off with opinions. Let's go. Because you can definitely, you know, you you can see it from both sides. You can easily say, well, that just makes the developer experience very annoying. And that's also why I created this feature request the moment I built it in this way. But it makes sense from a security perspective. Right? It's a similar reason why, during login, it'll say wrong email password or account doesn't exist, but you never exposed which of the 2 it is just to make sure that people can't slate, you know, what users exist. And the same goes for, you know, individual items in records. It's like you wanna, you wanna make sure that you can't just say, okay, slash item slash xyz and just keep scraping all of the different numbers, and now you know exactly what records exist, etcetera, etcetera. Somebody rightfully called out, you know, nobody does that in this trustworthy world, which I think sort of concludes this discussion then. Just ignore it. Lying on the Internet? What? Who does that? No. What? No. No. No. We don't do that. And a perfect example. So leaking of information is a very, very big thing. You don't want to expose stuff that you don't have to expose, but as you just said, it would be nice, for example, like the most basic, setup when you're just developing locally, it would be nice if you could actually see what went wrong. Because currently, it's just okay, forbidden. Nope. No information for you. So then the question comes. Oh, La Prima asked, can we go on stage? Sure thing. I think so. But let's let's first, summarize a little bit. So There should be a button somewhere. The question is. Yeah. Yeah. Exactly. So, immediately the question comes to mind. Okay. So if you would have multiple errors in that case, a strict one which just says forbidden and another one that has more information, Okay. How many different errors would you even like to have? So are we happy with just 2? Because, I guess this is opinion alert or something, or maybe even a useful thing for many other people. Like, what what do you guys think about this? Like, how many error, different error, messages would be nice, would be good. Useful. I mean, that is very much a sliding scale, isn't it? Because you really go from, from like, just give me every single thing. It's like, oh, I was trying to read the articles collection that I don't have access to. So I'm gonna get a forbidden error that says, well, articles exist, but you can't read it. And that's because of this permission that you don't have. For development purposes, that's really nice. But if you go to production with that, it's tricky because now you're just exposing a bunch of information about, you know, your setup. So, yeah, I'd I'd say it it there's a large range there's a large range in in that. And even within that forbidden error, you know, we can, think about how we wanna return stuff. So one thing I've been working on recently as part of this the the rules and permissions sprint that we'll we'll ship in soon is the, is that forbidden errors now include a little bit more information as in, you know, the field x that you were trying to query, you know, you don't have access to it or it doesn't exist, but at least it's a little bit more explicit while not necessarily exposing the schema, but just exposing what part of your query is wrong. Right? Which is not leaking any of that information but still being a little bit more useful. Alright. That does sound exciting, to be honest. Like, it's such a developer thing, like, normal users. I don't know if how how many people care about this, but this is such a nice thing for developers. So I gather from your answer right now maybe 3 types of messages. At least from your answer, it sounded like 2 in the beginning, like, one strict one with a little bit of information, but that could be counted as 3, right? Like the very strict one with nothing, a strict one with a little bit, and another one with very much information. Are we happy with 3? No? Yes. Asterisk. There's one more tricky thing in that the output type signature of the errors themselves change between those modes Right? So for example, if you're trying to fetch a thing that doesn't exist, we want to return a 404 status code with a not found error message. If you then program your app around that, you know, that it on your front end, it shows, you know, something because it checks 4 Oh, it was a 404 status. Therefore, do this logic. Right? The moment you now change that option to be strict when you go to production, that messes up again. Because now it's returning a 403 with a forbidden instead of a 404 with a not found. Cricky. So Let's see. May maybe maybe after we dive in a little bit deeper, we have more clarity around this. But so far, like, I personally like would like, I think, 3 modes. Let let's call them levels. Do we call them levels, modes? I think levels. Right? Yeah. It depends. As per usual, it's great. It it depends on, you know, are we considering multiple different flavors at the same time, or is it just an on and off? Because somebody in the chat just now rightfully mentioned, maybe it's just a single production versus development flag that changes that. Right? It could also be a setting within the app. Maybe it's even a setting on a per collection basis that you wanna say, well, this collection is not as, you know, private as the other ones. So for this one I wanna have, you know, nice and friendly, messages. And for the rest, we wanna keep private. There's options. It's tricky. It's it's when it comes to a single sort of Boolean flag that says production yes or no, I would be a little bit worried about getting into a point where undoubtedly 3 months later, somebody will show up and be like, well, we kinda need something in between. You know? Exactly. You can't really Or more importantly, somebody develops in development mode thinking they've got those messages, then they move that code to production, and suddenly nothing works. Right. Which is gonna be a bit of an issue no matter what because Agreed. We're not talking about, you know, changing the output errors. You could consider those, part of, the the what what would you call it? The public API contract of the APIs that you're building against. Right? Because because, you know, in your intro then, you said stuff sometimes crashes, and that's just part of part of software life. Stuff crashes on purpose. Right? In this case, like when validation fails, it's we're still throwing an error, but it's not an unexpected error or anything else. It's, you know, we stop you from doing something on purpose, so we throw an error, which is, you know, a bit of a difference there as well, of course. Because when it comes to exposing internal server errors, it's a whole different question. Because right now we do a similar thing, right, where we say you just get internal server error. That's it. Like regular users don't see anything else. If you're an admin user though, that's today, that's the difference. It'll show, you know, the stack trace of the actual JavaScript error, with where in the source codes it it it happened. So but exposing internal server errors to non authenticated users, that's gonna be that could easily become an issue. Right? Because now you find some sort of vulnerability path or whatever that's you don't wanna expose that. Definitely. From the chat, somebody has a suggestion here. It says, what about setting a trusted IP address? So you can just say, okay. When I am the one from my home to do this, I get all the pretty errors and otherwise, I can't. I think you're gonna have a similar issue with, you know, def versus prod, strict versus friendly error types, and how do you handle those in your app. It's gonna be a tricky tricky thing to figure out. And then somebody else said, the only thing where that really isn't enough is when there's a delete constraint. Users trying to delete items, and they can be deleted because they're still a referencing item. Admins already get a little oh, yeah. That's yeah. Because right now that is technically, a database error that bubbles up. So it comes out as an internal server error that for admins, it'll show the the SQL error underneath. But for regular users, they just get a whoops, you know, internal server error. Also with the IP, since currently currently, IP access, is attributed to roles. Right? You you customize that on a role with that access. So we could use that, but it does, like, sound very, very, very likely to me that you wouldn't be interested in, like, giving this to every single user of that role. You would like to have something more granular than that. So how about this also comes from, someone from the community. How about we attach this to permissions themselves? So let's say this user can access this and that, and that user is authorized to receive better errors than other users. For example, like, the simplest example, like admin users. Right? Mhmm. Like, all admin users are allowed to get the best errors that you can, But users other users get strict errors. Okay? But that, yeah. That's that, like, I I I'm not really sure how exactly complicated that would be to do at every single point in the in the code base. Well, I mean, in in terms of implementation, how like, they currently were throwing forbidden errors all over the place, but the way this would work in implementation is right at the end where we return the error in the APIs, that's where the sort of translation layer kicks in. Right? So all over the code base, it should just throw the actual errors or the actual error types and the correct ones. So if you're trying to hit something that doesn't exist, it should throw a not found error. And then all the way at the end in the middleware stack in the error response handler, it should say, oh, if your current, you know, e n v setting for errors or if the, which I'm gonna call it, if the the error permissions or whatever you wanna call it are set to a certain state, then it translates them into a different way. I think that's the way that that will be implemented realistically speaking. Yeah. That does sound quite good. Adjust intercept as a middleware. Okay. You are allowed to see this or not. Okay. Yeah. Because we're doing that on a case by case. It's gonna be insane. Just trying to do it every single time that we throw an error. That's that's too much. We currently already do a similar thing, right, where the the error handling stack, we check was this a direct as error type or any other error and that chooses between internal server error or, sort of the the expected error output. Very reasonable. I think, if somebody from the chat also has another recommendation or anything, please let us know. There's quite a quite a bit of action today, which is pretty nice, actually. Like, seeing the chat scroll up and down is pretty nice. Somebody says, I can't explain it in the chat, but I'll try. That's lovely. Well, well, La Prema can if if you you guys are okay with it, La Prema can join us on the stage. Yeah. I'm down. There should be a button somewhere that just says, I can invite them or they can add they can request, but we can also do an invite. How is that often with these? They asked to speak earlier, so I'm inviting. Or have they does Kevin have that blocked in this event? Oh, boy. With this guy. Nope. Nope. There we go. I got the invite. I got Does it work? I got him up here. I'm trying to see if I wait. Weekend. Yeah. It works. Okay. It works. Hello. Welcome. Hello. As always, sorry for my accent. I'm I'm Frenchy. But, like, I Don't worry. You're you're chatting with a Dutch and a German, so we we know you need to know the guy. Oh, yeah. But your English is better than mine. I don't know if you remember, but we used to talk to Get A Rich for about the the error management system. And at that time, I was working for a company who uses directors, but I leave them. So after, what I haven't the time to to follow the the the case of the the server management system. But, I think the the main problem, we had is is, dealing with the the the, yeah, the, like, the granular system of a thing. And what I proposed at the that time was, like, adding in the the collection a a new, column, like, you already have, edit and all that stuff. And, in permission, column where you will have, like, 1 or 2 level no. Mostly 2, but 2 or 3 level of, strictness of the error. Like, do do do I wanna send them all on that collection or not? Because, yeah, I I think that would be the I'm sorry. But because it's user related, it would be better for the companies. Because, if you if you, like, have only one private, instance of directors, I think it's not a problem to throw error to people because they are part of the company. So if they don't, respect them, their permissions, you they can have, like, legal, troubles, and this is possible. But if you have, like, an public API and also a private one, On one instances, if it's just a mode, I think it won't fit because a lot of data can be really sensitive. And, same goes with the developer mode. Yeah. I I totally agree with, like, developing something, in a in a development mode and then going to production, it doesn't work. That would not be a solution for me. And, as well that the the this this production and development mode would be probably used somewhere else, at another time. And, in a long term view, that will just lean in people active in the development, mode every time and, development searching, be thrown everywhere. Yeah. That's right. It's such a tricky, and I I think if that, what was that nodes flag called? It node e and v or something as taught as anything is that you should not rely on a single dev and prod flag. Yeah. No. It's a good one. It's the the doing it on a collection level, on a permissions level for for collections, basically. It's it's a good angle. It's it raises some different interesting questions though as per usual. Everything does, Especially around requests that touch multiple collections at the same time, right? Where in REST, you can technically go, you know, nest it and then you end up with you could have an error that's thrown in the sort of nested layer of the same request. Or in a GraphQL request, you can technically request multiple collections at the root level at the same time. And then it gets a little interesting because now you can get, you know, a different error output from that request based on which of the data points of that request crashed, I guess, instead of, you know, the request itself, which opens a little bit of a different kind of words. Yeah. But I I think in some case, that's what we want. Because, in the the app I I was working on, we we used to to to get in that kind of problem where, we have people, who had access to certain company, but not certain order. And we retrieve that data in one block. And if some points fails, the the whole, request will fail, so we'll have to deal with that. And, what what we can do at that point, I guess, it's when you you have the error only in one part of the query, it's just returning not an error not an error code, but just like in the API, an error, tag in, that object and not all the thing. But I I know that would be, like, a big breaking change. So it can be hard to implement for some people. But, I guess, by default, if we just disable all the error, like, the the basic settings will just be, what Direct just currently does, it won't be a problem because the people who turn the the feature on, would know what they do or or would have ways to find out. I think that is You're you're just assuming that people know what they do. I barely know what I'm doing. And when when I add features oh, no. I think, it it there's a there's a new question hidden in there that we hadn't touched on yet, nor in our notes right now, which is if an error is thrown somewhere nested, let's say, you know, the let's use the GraphQL as an example because it's it's easy to reason about. Let's let's say you're requesting 5 collections of data at the same time. Right? And one of the 5 crashes. The question is, do you return an error and the whole thing failed, or do you return the data that worked and then have an additional error flag that just indicates this is the path of your query that didn't work? But return what you have and leave the rest. And, I think for that opinions. Yeah. I think for that, the the the best way to to do it is just, like, throwing the error only for what phase. Because, if we use these directives, I assume it's that we just want to cut the the front end. And and so, it it would be, most of the time, like, an interactive app or a single page application on or something of of that kind. And those kind of errors are really easy to to treat with that method. So and and, I I think most of the time, if we activate the the feature, it's what we want because, that will lead in, less, just big crashes, like internal server error proof and nothing worse. So I don't know. It's it's an interesting one because, somebody in Chet just now says it too. It's a rather fundamental question. But, you know, you see both in the wild, and both are kinda alright. It's it's, there's also an implicit difference between, you know, reading and write operations there as well, of course, that if you do a large nested update, you kinda want it to work as a single unit, as a single transaction to make sure that if, you know, part of the insertion doesn't work or part of the update, the whole thing shouldn't, you know, go through because otherwise you have that sort of half half done state. But for read queries, it could be different, but that really depends on, you know, what are you reading, and is it all tightly coupled, or are you reading multiple things at the same time for convenience sake? Because if I'm not mistaken, in in sort of the GraphQL spec, Like, it allows you to return partial data and then errors for other root fields. But I feel like if there's an error in a nested field in the query, it'll still fill that one sort of root query as a whole. But that is that is something I love to double check. Yeah. Yeah. I'm I'm I'm not sure either. Like, my my gut feeling was, no. I I I don't wanna say something wrong right now. So, okay. Another another suggestion from the chat. How about hashing the error plus a UUID, I assume that is? Only admins will be able to see what the error really is. Well, I mean, I mean, you are probably talking about, like, error codes. Like, for example, many different other apps just say, okay this is error 3, 1,172 or something. And then you can look up internally what that exactly means, But, you would still be missing out on, like, more information, like the stack trace or which which file failed or something something that you would have to encode in that thing, but I don't think that's always possible or even Or to just think very divergently. You know, an alternative approach is that you basically encrypt the whole error, save that to a database, and then only return the ID of the error that it was. So then the admin can log in and look up what the full stack was and and and and sort of decrypt it and see the whole the whole contents and everything else. But that that feels like a way to sort of persist to security and give more information at the same time. But it also feels like another skip and a hop and a skip for regular users to be able to just, you know, use do the errors that are output. That's an interesting thing. I have never thought about it like that. People do that? Do their apps do that? That's interesting. Yes. Some app does. I I used to work on one with the that. But I think it's the it's a problem because, like, most of the time, you you wanna informing in some way your user of what the error is because you don't want to to get someone just to to create a ticket to the IT support just every time they need, something, didn't work. But they just didn't have the permission in the first time. So, yeah, I don't think, it's a global sit solution. But maybe in some case in some case, if if we add, like, an EMV approach, that would be a a great option for some people that maybe need that. And I could see it work like that for for internal server errors. Right? Well, that's one of those things where we wanna hide away the stack trace no matter what for for the API output and then save it elsewhere. But at the same time, you know, saving every error could easily blow up in your face too, because if you just have, you know, an unauthenticated user that tries to access some data there's no permissions for, we don't wanna save those. Right? Because now you could easily just blow up a database by a public malicious actor that just spams your API knowing that they're gonna get errors. So there is there is definitely a a difference between sort of expected and unexpected errors there and which ones are saved. Have AI blocked them. AI solves all of our problems. Sure. Just do what I want. Parentheses open, parenthesis close. That should do it. Right? If only if only it would be that easy. K. So let's let's summarize a little bit because we have been, you know, throwing stuff out there. Maybe we should get back to reality a little bit. So, okay. So so let's say we have, we like to use the Moscow list. Right? The must have, should have, could have, type of stuff. So for must haves, let's let's get on the same train. Like like, what do we need? What what must we include? So, yeah. How granular do we make this? Oh, no. It has to be actionable, man. It has to be actionable. Okay. I I think the the point where we've been stuck the the last time was reached is, like, we we both agree on the fact we need a granular system, but we both must agree, on the fact that it would be so long to to make and to think and all that stuff that maybe it would be nice to have something, before that. But, Right. Yeah. Yeah. Yeah. But, I I think, that's, my my point was, like, directors, is a tool who is proposing things like a a different way than the other, tools in the same category. Like, you you just want it to to be a little more, accessible and, and usable. And not just, like, being that's the way you should do that and, just follow it. And and so I I think that's the problem there. If we did something else, than a granular system, you would, follow a path that doesn't feels like directors to me. And I don't know that that's totally your point, but but, I I'm not sure if that's what people need. Otherwise, they they will lose WordPress or or something like that. You you you sound like a team member in the sense of when the choice arises, let's do it the difficult way and make it unopinionated wherever we can. So no. I I do agree though. I do agree because it's it it is at the end of the day, this is a very opinionated thing, where for some apps, it's acceptable to have it a little looser or even want it. For some, you know, security minded folks, it's absolutely not, and we can't really make that decision for people at that global level, even though we have right now. Oops. Right now we are on the side of safety first, which, you know, it's it's defendable, but not ideal. Like, that's also why I created that feature request. It feels like decades ago, but it was 3 years. I think that the the main unresolved question now, and and that is sort of to answer your point, Dan, before we can really fill in the blanks for what are the must haves, is what is that ideal approach to how do you configure this? And then from from a developer experience first and then secondly does that make sense from an implementation perspective. Because doing it on the collection scope level makes sense for errors that are thrown on the collection scope, but not all errors are thrown within the context of a single collection. So that that that opens up, you know, new questions. And the opposite is true for doing it globally on the e and v level. Right? Because, you know, it's a low pretty much excellent point. It's not that black on white that you say make it insecure for the whole API. You know, you wanna do it on a case by case basis. That is a that's a that's just a statement with no no answer. No. I don't another, I don't know what to say it in English, but, like, another thing we, think about at time was, like, just, if if we take, like, the the point, if we need the error, it's just to treat them. One, thing, which, was a a little bit, between the two option is just like, having some kind of way to tell directors just, okay. This error, I want you to to throw it, and other errors I don't want. So that would be a little bit more granular, but that would be more like, just a techy approach. And and then not, being, so universal. Oh, Rike, you're muted, by the way. I hit the wrong mute button. That's what you get when you have 2. I I muted myself here, and then I and then I muted myself to unmute on this. Oh, man. I mean, we've only been doing this remote thing for about 5 years now, so I'm I'll I'll get it. Yeah. Because I what what I was trying to say is that that approach to say, okay, which error types do we expose? That is something we could do on the role level or soon to be policy level, And it is a system where we can still have one translation middleware that handles that error no matter where is thrown from, which is you if you compare that to the sort of collection idea that we had earlier, that one is a little trickier to implement in that sense, because now you have to make sure that you know what the collection context is for every single function call that may or may not throw an error. And then do that sort of translation piece, in in situ of where those errors are created, That makes sense. Whereas with, you know, an approach where you say, okay, not found errors can be exposed. If that's your setting, we can do that on one middleware at the end of the stack to just say, okay. Was the error Again, I'm not sure if if I can wrap my head around every single edge case, but, like, it does sound and may maybe I understood it a little incorrectly, but it does sound quite easy to mess that up. Like, it to to to bubble to bubble something up that does not get blocked then. And somehow I am exposing a random error that I have not thought about, like, on on an error level. It's it's the difference of an allow list versus a deny list is basically what you're saying. Right? So if you have a filter where you're denying individual pieces, it's easy to miss something. Whereas we do the opposite way where it's blocked by default and you allow more and more stuff, it's you can't really accidentally expose anything because nothing is exposed by default. Which is similar to what, Andre Andre Andre Key are. Just gonna assume that's how you pronounce it. Just said in the chat as well as, you know, if you really want it super granular, effectively just make it a rule based system, right. Where you run a filter against the error object that is thrown. Like if the error types is XYZ and the extensions contain blah, blah, blah, collections, such and such, then expose it, which will be one way to make that super granular, but also a little harder to configure at that point. Because I could, I mean, at the end of the day, I could also imagine that, you know, for just local development, that is gonna be a pain in the ass because now you have to configure so much stuff to get the errors out. I I think we what we could do is just like doing an EMV, variable just for real development case, then that system for the production mode. And later on, if we think it's too difficult or, then we can add the system, with the the permissions because that would make, like, stacks on top of each each other, with the the the the first step would be, like, the programmatic approach on the error throwing and all. And then, the the we could add later on just, instead of just throwing nothing if the error do not doesn't match, any case. Like, is it a permission error? Then is there a plain way to treat it? So it's made steps, and we have something, in between no permission management and on the other end, full thing. What this makes me think of is the we've got a client that we're playing around within a proof of concept. They're they're actually have an error table for their front end, and they've actually got translations. So they've actually got a translations table on that so that they can have the language the errors translated to multiple languages. If we went something like that where we have, like, a direct us errors collection, right, as part of the system tables with a set of, you know, with translation, then we have native translations capabilities right there. So if you wanna adjust the error message, so we could have the defaults. Right? The I don't know. We've got a dozen or whatever that we have now, with some variable support maybe even there so that if you wanted collection information or you want that stack trace information to percolate up, you could. And you could determine at least in the short term, we can we can avoid the permissions for the short term, give you just control over your error messages. You wanna show something that we don't do natively by default, well, you can override the messaging as a thought. And I think that would actually help with things like flows as well. We have the same problem in flows. We can't percolate an error message to the user even though we're throwing and controlling the erroring of the of the workflow. Potentially, if we think about it in that context as well where we've got we could use that same error structure Mhmm. Idea. Not a not necessarily the solution or the right solution, but here's the new rabbit hole, multilingual error output for the API. Oh, boy. Oh, boy. I mean, sort of it's an interesting angle to to sort of noodle on a little bit. The the general idea of errors as it stands right now is that you basically return an error code that is one of the standard sort of known error types. And then in whatever app that you're building, you can basically just say, you know, oh, if the error is not found, then use my own translations and my own front end and all that kind of stuff. But yeah. I mean, it it does raise I mean, we we know we need some sort of translations in the API no matter what for email templating, which has been that'll be a fun discussion for another day. But, yeah, it's it's an interesting idea to have errors as a sort of system collection that you can then modify. Although, we would have to hard code in what the keys are because otherwise, we don't know what error to throw still. That's a tricky one. But we can hard set the keys. Right? And then if you create your own key or we lock the table, you're not allowed to add to it, you know, without core functionality. Or, again, you've got your hard set core pieces. Core knows what they are, and they can't be changed. Their primary key or whatever we wanna do around that Yeah. Gives us that level of flexibility. But then if users want to code other error messages for other applications and data, they can actually still maintain it in all in one place. I'm not smart enough to solve it. I just I just know that's an implementation I saw recently where we're for a front end application and the error messages that they wanna generate for that front end application. They're actually doing that in a set of tables. Kinda cool. Oh, I think, like, lots of interesting things that we can do, but I think we're still stuck on where do we want to control this or configure this. Let's just go to the one extreme. I mean, very That would be the easiest thing. You have to And you get errors. Okay. Done. That's the easiest thing that we can do. That leaves a couple of things that we would like to have open. Right? Like, we ideally, or at least in my mind, it would be really useful if, for example, like, admins actually get no like, good, context rich errors and normal users don't, which would you know, it's not really that possible with that environment variable approach. Yeah. So so it feels to me like out of everything that we've discussed so far, the direction where you effectively set up and allow list of errors on the role or soon policy level gives you, so far everything that we sort of want to achieve. Right? Where you can say, okay, you can allow one admin role to just see all of the errors with some sort of wild card flick, accept everything, allow everything. You could use the filter rules to be more granular that you could say, oh, if the error contains a collection, flag, then filter against that. So So you can you can do sort of the collection by collection, filtering. And, yeah. You you get to choose role by role, so make it admin only or make it make it, a different, you know. So the users can only see the granular errors for a a collection that's already public or something like that. The the only problem there, it's for the flows. But, like, what do we do with them? Mhmm. Mhmm. For flow, that's a grant. Like Because I I think we could have close the The same system, like, in the in the settings of the flows. But is it gonna be the same way? But we could also say that if you trigger a flow, you are a user or the public role. So therefore, the same settings of your role should still kick in. Yeah. Yeah. Because they access the data. So that's good point. But, like, what if you want to, bypass a permission on a specific flow? Like, then you'll because in some case, may maybe it's the the old data you don't want to access, but just one field you want to show someone? As long as the filtering's happening on the API level, that's still all API under you know, flows is still API under the hood. So if you uplift an operation, read CRUD, whatever, this the erroring although, I guess, it's still gonna then it would percolate to that user type I think the the the underlying question is what if you want that error to be returned no matter what the settings are in your flow? Because your flow is effectively a custom endpoint or, you know, hook or whatever. Yeah. That's what I think flows when you're throwing an error inside flows, that should be its own code. And if you throw a custom message back to that, then you should be able to get that custom message. That's the key thing that I always want. Right? Or that it the the initially, I thought was, oh, I'm gonna throw an error here and I wanna I wanna send back to the user, you know, you did x y z wrong, you know, or this this isn't allowed because you failed to give me the appropriate information instead of a internal server error, which means nothing. You know, I can't I can't tell the user what they've done wrong or what they're violating that I'm validating inside of my flow. I can't say, mister user, you must have your status in the right thing or, you know, these three fields have to be populated to be able to use this or And and that's where the allow list approach for error filtering gets tricky again, because now you need to make sure that you allow list your custom errors from your flow in the policy or in the role, so it makes its way to the app. Or I think, again, flows the error code or codes that are returned by flows, that there is a specific code, and you simply take the message that the user's providing out of the out of the, you know, exception. Yeah. Yeah. Yeah. Right. And so it's it's a known code. We know what it is. Right? We know Oh, so here's here's another thing we haven't really message. Yeah. Another thing we haven't really touched on in with regards to flows is that, you know, you have a very explicit error handling path that every operation has a okay. If the error fill or if the operation fails, do something else. So maybe there should just be an explicit operation that says return the error, and otherwise it just defaults to, you know, hidden by default, but then it becomes it it no longer is a a permissions or roles thing. It just becomes a flow thing, where you just very exclusively have to end your flow with return the actual error. And at that point, it's up to the, you know, the admin to configure that flow and and whatever they want to return. Love it. Me too. Convinced. But yeah. Yeah. Okay. Problem solved. We would have we would have to to, like, also have a a custom error block, I think, if you if we do that that way. Yeah. Yeah. Just an operation that says make a new error, whatever that error is. Yeah. And you can pass the a variable or a text or something. Yeah. Which is then a funny new completely unrelated question. But if you have a block that says create an error, is the good path the error or is the bad path the error? I I think you can you can do this. There is no path. You don't get to you don't get to leave. That's the end. You're finished. Termination note. I think the I don't I don't know. Like, I think there you called it, like, grade pass and, error pass, but I think in so in some time, like, on the if call, trigger, the error pass is not really an error pass. So Right. Yeah. That would be sense to be both, really. Yeah. So in the create an error operation, both both are the same. It just calls both. Yeah. And then Now you have oh, woah. Woah. But if it calls both, now you have a way to do parallel split paths because it's now a trick. That's a discussion for the problem. I I think that would be nice, but yeah. That would be a lot for that, more importantly, I want merge capability. Be able to rejoin back into logic. Oh, good lord. Now you have to wait for both to be done and oh, boy. Okay. Let's definitely not get into this. We've got we've got very divergent. We have about 9 minutes left, folks. Yeah. This this feels like another 6 hour discussion if we go that route. It is a very, very long discussion. Flows 2.0. We're already doing some research on that, so figure out what that looks like long term. Okay. Back to API errors. Do we have an idea of what our must have should have? Yeah. I think my my current going direction is is basically the on the role level, there is an allow list type configuration that allows you to say there needs to be a wild card that says do everything for def purposes and otherwise you can use the sort of filter structure that we have to say these are the error types that we allow you to see, and these are the and then based on whatever the error contains, you can filter it more granularly if you want to. That's for me closer to a should have than a must have. The error types is really the main the heart must have MVP. Because then because our error objects, they are, you know, they have additional extensions is what I called them right now, which is basically, a not found error can have a collection flag that says this is the collection that was not found. And therefore, you can use those flags inside of the filter as well to just make it real granular. And then for for flows specific specifically, just to reiterate what we just said, is you wanna have some sort of operation that it it's almost like the end of the line operation that should that sort of allows you to say, okay. This is what we're returning now, in the output. And then that could be that can have a couple of settings like, what is the status? What is the, what is the message? What's the body? And then that body can be generated using a, sort of create error operation. So I think that would be a nice setup if we have 2 additional operations. 1 to create an error that this custom, but uses the direct as error format and everything else to make it system standard. Therefore, you can use it in things like manual triggers to output an error to the client. And then we need to have some sort of operation that you can use at the end of your chain to say return the data and then just format it in this in a certain way, to really allow you a lot of control about the request. Okay. Rest of energetic typing. This is satisfying. It was very nice to listen to. ASMR. Now we switch to the ASMR section of the Can you just show this video? Everybody quiet. Everybody quiet. Oh, no. Oh, no. Let's not do this. Okay. Alright. This this feels pretty good so far. Did we we I know we we chatted a little bit before we hopped on this session. Did we have any other questions that we prepared for this? I think I think we have for most of it. Let me pull it off here on the second screen that is off camera. Why are we returning for threes? Went through that. How many lovelies? We kinda figured that one out. It could be an environment variable, but you kinda just just figure that out. And then business logic existing scripts expected specific error code. Yeah. I mean yeah. I mean, I think we're gonna we've answered all the points that we sort of note note beforehand. I I just have and I I know I think someone in the chat is just saying, like, for what about the extensions? But I think for the extensions, we can just have, like, a a JavaScript function with with the same as the one in flows and just like custom chats. Yeah. Because we do we we haven't really documented it too properly yet because it's sort of it was a little bit in flux still, but we made that direct as error specage with a function that you can use to make a new sort of, like, error a direct as error that direct as then like, what's the right word? Recognizes as a direct as error that you can then throw to make sure that no d ep and API behave in the same way as the system would so for for custom extensions that should sort of be solved, which is good. Put that direction. Yeah. With that being said, I think we have a for the first time ever in one of these sessions, we left it off with a pretty clear idea of what we actually wanna do. It's usually, we go way too deep and then have a sort of couple ideas. But But it's we're trying. This is my No. No. I I was going to to say it's just because it's a refurbish version of what we already think of later. Yeah. Well, you'd you'd think that about every time we do a feature request review, and it's it's never never the case. Like, a 2 years old idea or something. Okay. Maybe Yeah. Not 2 years, but, oh, yeah. It must be. Like, I I see 2022. So yeah. Kinda. How passionate people got in the actual feature request that somebody said. It's like, this is the single worst thing about I hate it so much. My whole month is ruined because Directus' errors are too strict. No. But, sir, seriously, like I wish. I wish. Yeah. I wish director's errors were the worst thing in directors. Then directors would be very nice. Yeah. That's actually a good point. Yeah. Ouch. If this is if this is the worst problem to talk about, then we're doing real well. Then we're really golden. We're good and then. Alright. Well, we're we're slipping a little bit, but let's call it for now. I wanna say as per use, thanks everybody for watching. This will be going live on direct TV, which is direct. Io/tv. If you haven't seen it yet, book market sends to your friends, your family, everybody else, Share it on LinkedIn, Twitter, x, whatever you whatever your flavor of the week is. We'll be back in, I think, 2 weeks. Am I saying that right? Uh-oh. Should have prepped this. Yes. We'll be back in 2 weeks exact, June 6th with another one. Oh, hello. Another one of these party full sessions. But until then, thanks for watching, and we'll see you next time. Happy coding. Bye. Like and subscribe. Save me from the algorithm.","ddd81e25-4534-4c87-af7e-f25e6832a128",[335,336,337],"146b3a54-018d-4b79-8190-a52ea1afe20c","1d6a4684-3c50-4af4-bc64-3ee590527d12","e13ded04-2af2-4552-a441-a39c373fe008",[],{"id":133,"number":134,"show":122,"year":135,"episodes":340},[137,138,139,140,141,142,143,144,145,146,147,148,149],{"id":145,"slug":342,"vimeo_id":343,"description":344,"tile":345,"length":156,"resources":346,"people":8,"episode_number":349,"published":350,"title":351,"video_transcript_html":352,"video_transcript_text":353,"content":8,"seo":354,"status":130,"episode_people":355,"recommendations":359,"season":360},"19659","986515873","Rijk, Jonathan and special guest Hannes discuss WYSIWYG Linking Existing Files.","4aa280eb-c685-4d24-b8d0-96477cd047d9",[347],{"name":304,"url":348},"https://github.com/directus/directus/discussions/19659",9,"2024-07-25","WYSIWYG Linking Existing Files","\u003Cp>Speaker 0: Welcome everybody once more. We're ready to rock. Welcome to request review. Daniel is out this week, so we got a very special guest for you here. Say hello.\u003C/p>\u003Cp>Hello. Hello. Good day.\u003C/p>\u003Cp>Speaker 1: Thomas. Welcome to the welcome to the phone.\u003C/p>\u003Cp>Speaker 2: Welcome to\u003C/p>\u003Cp>Speaker 0: the having me. So today, we're gonna be chatting about yet another feature request. And this time, Jonathan, what have we pulled up?\u003C/p>\u003Cp>Speaker 1: We have the lovely improving the way that files are injected in the WYSIWYG editors, is the discussion for today. I believe the extensions team may actually be taking this on behind the scenes in a in a short term solution. But for now, it'd be nice to understand the requirements, the the gotchas, the whys and wherefores, the way that current the way we currently add links and images and videos within a WYSIWYG field. So you can edit links, move your links, take a look at your links here. But according to the to the request, they'd like this to be a little more fully featured in the way that the tags and things are added around the HTML under the hood.\u003C/p>\u003Cp>It's my understanding. But I'm no front end expert, so let's see what we can figure out and decipher.\u003C/p>\u003Cp>Speaker 0: Alright. So this I can feel it. This is not one of those where it feels like, oh, that that should just be one button. Right? That's easy enough to do.\u003C/p>\u003Cp>Alright. So starting at the basics and pulling it up, if you seem to look enough to decide over here, by the way, I just added the same thing up, but a little bit bigger. The goal here is basically just like you can put in an image, you wanna link to a file. Right? Easy enough, you\u003C/p>\u003Cp>Speaker 1: think.\u003C/p>\u003Cp>Speaker 0: Inserting a link to a file in its purest form shouldn't be too crazy because we know what the IDs of the file. We know where you would find it slash assets. It's the same as an image. Right? Mhmm.\u003C/p>\u003Cp>Just as with an image though, the question immediately becomes permissions? Big one. Right? The user that is inserting the file has permissions to see those files and then select it to be linked. But that doesn't mean that the person on the other end that is that's seeing this HTML rendered on a website or something also has the permissions to that same file.\u003C/p>\u003Cp>Right? And we've seen this before with images.\u003C/p>\u003Cp>Speaker 2: Yeah. I was trying to say it's the same problem with images. Right? Because images share the same\u003C/p>\u003Cp>Speaker 0: properties. Yeah. So the way we do it for images right now is we do have that option where you can sort of hard code in one of the the tokens if that's the way you wanna do it. You could, of course, make permissions a little leaner for reading images. Although that way, you know, it's a little bit more than permission set up.\u003C/p>\u003Cp>Not ideal. You can have people log in, of course, on your own front end and then use that for permissions. But it feels like even with the link to files, it might get a bit worse because at least with an image, you can immediately see if it doesn't work because you get a broken image. Right? Because you get a permissions issue.\u003C/p>\u003Cp>So as the person that's implementing it, it becomes a little bit more obvious what's going on. But if you just have a link and the link doesn't work for some, but it works for others, that's tricky. That's tricky. So I think as per usual for for those who haven't seen one of these before, the way this oftentimes works is that, you know, we take the smallest feature request that that is in here. The what is the the status?\u003C/p>\u003Cp>What is the minimum viable? Then convergently think about, okay, what scope does this live in? What are all the edge cases that we have to think about? What are the problems that will come up? And then sort of take it back down to, okay, what can we actually do today?\u003C/p>\u003Cp>Right? And what is the long term plan and how do we get there? So I think to me, an important one for to make this one work as expected is all around permissions. So I'm actually very glad that you're here, Thomas, because you just work a lot on permissions as part of this, v 11 release in the RC that is out now, in the GA coming up very soon. Any immediate thoughts on the permission set up for this?\u003C/p>\u003Cp>Speaker 2: Especially with files, I do worry that giving read access to a lot of files like you suggested previously is a big foot gun for people because you might store private files. You might store exports from collections or something in your files and giving, like, real access to any of them feels wrong to do it as a blanket or something. That's like a blanket permission. We we, the best possible way would be to surface that information somehow. Like, how visible is a link or how visible is, like, something you link to, since even if you're testing out the link on your live preview or something, you still might be logged into your CMS behind the scenes.\u003C/p>\u003Cp>So for you, the link also works. So you have would have to test it in a private window or something. But then again, we could show you, hey. This is how the public what the public permissions for this file look like. Users might not be able to access it.\u003C/p>\u003Cp>On the other hand, we don't know about your setup. Right? So we don't know, are you actually just visiting those with the public public permissions? Or are you adding a token? Or are you doing some other stuff with it since we don't know really what is the implementation that relies on it.\u003C/p>\u003Cp>So it's hard to think about a catch all solution that would help people not shoot their foot. So right now with images, we do it. We basically let you do anything with it, and don't hold your hand while doing it. And I wonder if that is also the solution in this case. So just provide more functionality.\u003C/p>\u003Cp>But if stuff breaks on your end, you have to be aware of it. Seems could be a documentation issue, but then again, the people reading our documentation aren't actually the users using the product in the end maybe.\u003C/p>\u003Cp>Speaker 0: Yeah. It's a tricky one. And and to your point\u003C/p>\u003Cp>Speaker 2: of, like, where do you wanna put this education?\u003C/p>\u003Cp>Speaker 0: Right. Yeah. And and to your point, we when we had this issue for images, the conclusion was, well, you know what? Let's just make all the options available and and put the burden of setup on the the end user to make sure that they're using it right instead of on us to to try to help you with it. It did this made me, think of another feature request that we I don't think we've discussed quite yet here, but it gets come up a couple of times in the past, which is the nested relational permissions, so to speak, where you could say, files are inaccessible by default, but you can allow file reads if they are being read through another relational field.\u003C/p>\u003Cp>So for example, you could say files are off limits, but if you look up an avatar through a user, you can still access that one avatar in some of its fields, but only if you go in relationally through a user.\u003C/p>\u003Cp>Speaker 2: How does it work with the assets endpoint though?\u003C/p>\u003Cp>Speaker 0: Right. That's where it gets interesting because I'm I'm just wondering coming from. Yeah. No. Exactly.\u003C/p>\u003Cp>I'm just curious if there is an angle to that, because it made me think of this where I'm like, oh, if you assign an image or an asset into a WYSIWYG blob, maybe we can have it rely on a similar idea of permissions where it's like, okay. The things you make available within, one of those fields can be read in a certain way, but not others. Again, just convergently thinking about it.\u003C/p>\u003Cp>Speaker 1: Do you have any other issues? Sorry. Good. I I don't wanna distract you from a thought. So go ahead, Hans.\u003C/p>\u003Cp>Speaker 2: The the issue I'm seeing with that is, again, like, accessing some data of that asset, totally fine. I can see that work, how it would be set up in permissions.\u003C/p>\u003Cp>Speaker 1: I\u003C/p>\u003Cp>Speaker 2: would be able to do, like, the relational reversal of permissions or something or for items. But since the asset endpoint doesn't know about it, we are still at some point where we why would this user be able to see this? Because then we would have to look up. Are there any permissions that could allow it? And so it gets it gets really complicated on the asset end point.\u003C/p>\u003Cp>Like, the actual, like, file permissions isn't too much of a problem, but all of the metadata, but the whole, assets itself isn't too trivial to figure out Yeah. Image for that one.\u003C/p>\u003Cp>Speaker 0: Maybe. Again, divergently thinking about this. Maybe the, there's an in between where we can do kinda like what what s 3 supports and and some of those storage providers where you have, like, a signed link that is unique to where it was used. So we can know from the way the asset was accessed, what field in what collection it was accessed from. And then that way, we can do the relational permissions thingy instead of relying on having to search.\u003C/p>\u003Cp>Because to your point, if you open an asset and we have to search through every single field to see if there's any chance that you used it, that feels crazy. That feels insane. But if we make it a unique link that is unique to that collection of field combination, then that simplifies it a little bit. Because now we do know A\u003C/p>\u003Cp>Speaker 2: lot of things.\u003C/p>\u003Cp>Speaker 0: Where it was accessed from. Yeah.\u003C/p>\u003Cp>Speaker 2: Which effectively could be something like an access token for that.\u003C/p>\u003Cp>Speaker 0: Yeah. Effectively. So so it could be it's it's effectively just just a token with that connects the dots between you're trying to access this image or this asset through an HTML blob, that is on your website. And because we generated a custom link for it, we know what that blob is, and then we can also help you debug, you know, if your file got, is being accessed from sources that you didn't expect it to, we can show you. It's like, well, you got it read from your your HTML body and this and this article or something.\u003C/p>\u003Cp>Right?\u003C/p>\u003Cp>Speaker 1: Interesting. I like it. That was my thinking as well was either inherit permissions for the item, but then as Hannes noted that the asset endpoint has no idea about that currently. Now that doesn't mean that we don't enhance or find a way, kind of a unique URL or a unique identifier that indicates where this is being used. We've actually seen this.\u003C/p>\u003Cp>There's another request out there about knowing what what files are associated with which items. Right?\u003C/p>\u003Cp>Speaker 0: It's Right. Right.\u003C/p>\u003Cp>Speaker 1: We we have this problem right now without writing some very complex hook logic that track tracks through a whole set of relationals. You know, we don't because that asset endpoint is kind of independent of all of that and files kind of live independent of all of that, The way that the relational is unless you're forcing relational reverse creation, which then makes your file through, you know, direct us files gets really ugly really fast that way. We have this it's a fairly common request that we see from clients of, I wanna know what my files are associated with. Right? I wanna be able to see that and understand that.\u003C/p>\u003Cp>So This\u003C/p>\u003Cp>Speaker 0: is this is also an interesting topic in the whole security versus usability piece. Because on on from from a user experience and even a developer experience, if I have a, public HTML blob and I put an image in there, I kinda assume that that image is now also in that same public blob. Right? So I would assume it to work. At the same time, if you if if we were to make it that way where it's like, oh, whenever you put an image inside of a HTML thing, it's now public.\u003C/p>\u003Cp>You can accidentally expose a whole lot of stuff. Right? Because it's it's a little opaque under the hood. From a security perspective, it's a little tricky.\u003C/p>\u003Cp>Speaker 2: Is it though? I guess again, it's really one of those, like, what are all the different use cases Directus is used in kind of problem. And, like, who are the actual end users and who has who has been educated about that problem, caveat, whatever we wanna call it. Because I I generally like the idea like, it doesn't really have anything to do with that, feature request in general since that seems a lot more low level. But I do like the general idea of having something like a unique or signed, asset URL, which can be used to conditionally allow access to something.\u003C/p>\u003Cp>Speaker 1: And so generating something could\u003C/p>\u003Cp>Speaker 2: be go for it. Sorry.\u003C/p>\u003Cp>Speaker 1: No. No. I was just curious. So when you're generating, you know, like, this this input screen right here, so you'd have a unique URL that's being generated here, right, in some way, shape, or form, whether that's a tag on the end of the, you know, asset endpoint that gives you a question mark, you know, unique key. That has to be stored then.\u003C/p>\u003Cp>Is that stored then as part of the director's files or a relational to the director's files kind of a system table where we store those unique IDs? And not so much implementation. Just I I'm thinking about so you'd have that ID. But you'd also be able to see that here. Could you also or optionally ensure that you give, you know, an access token option here?\u003C/p>\u003Cp>So as an actual field input where you could supply an access token or even a default access token for as part of the admin configuration. Because once again, I don't necessarily want users putting in access tokens, but have a way for the administrators to get to apply an access token that has the appropriate permissions for the file.\u003C/p>\u003Cp>Speaker 0: That is the key piece there. That last that last little snippet of the sentence is the most important crucially important part that has the appropriate permissions for the files. The foot gun with the excess token is that somebody just puts in their own users' access token, YOLO it, and then it works. But now you're technically exposing that all over the place, right?\u003C/p>\u003Cp>Speaker 1: Yeah.\u003C/p>\u003Cp>Speaker 0: Because once you're, you're putting that excess token in the image and HTML, it's just a query parameter. So therefore, wherever you render it, somebody can see it. You have to consider it public.\u003C/p>\u003Cp>Speaker 2: See it. They can\u003C/p>\u003Cp>Speaker 0: So what you're effectively doing is you're not using the public role for those images. You're just using a token that you then make public. Right? So that last part is why the sort of developer or user experience or both. I mean, just the experience as a whole for using the static tokens as way to get access to those asset in a link or an image or otherwise.\u003C/p>\u003Cp>There's a couple of food guns, right, that you gotta be aware of that people may or may not be. Because again, that's one of those things where, you know, if you explain it, that makes a lot of sense. But if you don't know and you just wrongly assume you could put in any access token, you can be in a in a world of trouble. Right?\u003C/p>\u003Cp>Speaker 1: Absolutely. K.\u003C/p>\u003Cp>Speaker 2: Which makes me wonder if that is something I haven't really thought about all the ash cases, but it's something probably we can solve by using a j signed JWT or something that just scopes it to that specific item in a collection, then we don't even have to store that in the database, assuming that you have access to that. Because then in the asset endpoint, we could check, hey, does the user like, this request actually have access to that item, which is signed in the JWT? And that way, we can verify the access. And if that basically overrides whatever, like, more restrictive permissions you have, you would be good to go only for that specific item where that image is linked in.\u003C/p>\u003Cp>Speaker 0: Yeah. So we're basically saying\u003C/p>\u003Cp>Speaker 2: Linked or whatever.\u003C/p>\u003Cp>Speaker 0: Try to summarize that so I understand that we're basically saying if you attach an image or an a file, a general asset, any asset to an item in a WYSIWYG or relational interfaces, maybe even anywhere else. Well, relational interface, I guess not because then you just have a data point, not a file. But if you have an asset link inside of a Wizzywig or a block editor, some of those markdown, we use a signed link that contains what collection and item it came from. And then we can use the permissions for that item instead of the permission for files. So therefore, if you have read access to that HTML field, you defect don't have read access to the images within it.\u003C/p>\u003Cp>That feels like a very clean setup as far as I'm concerned.\u003C/p>\u003Cp>Speaker 2: Again, probably also food counts with exposing files or people linking to files, which should be internal at that point. It's more of a shooting your own foot than more, of a case where we are trying to prevent it the best we can. Yeah. But that's,\u003C/p>\u003Cp>Speaker 1: that's kind of already here anyway. Right? Because you can restrict the files and folders that this has access to. Right? In the in the actual WYSIWYG config, you can, I I think Do\u003C/p>\u003Cp>Speaker 2: the root folder or something? It's what we do. Right?\u003C/p>\u003Cp>Speaker 1: It should only be what this user has access to. Right? So if I add\u003C/p>\u003Cp>Speaker 2: Add in general. Yeah. Yeah. For sure.\u003C/p>\u003Cp>Speaker 1: If I add an image, you know, I can add or edit. I don't wanna do that.\u003C/p>\u003Cp>Speaker 2: I wanna So your your condominiums and images.\u003C/p>\u003Cp>Speaker 1: Yep. This is my my permissions restrict me to whatever I have access to, and so I shouldn't be able to technically insert something that I shouldn't be able to now. Could get a little more complex, but I like the that was my thinking and couple of notes that I took. I want a way to restrict the permissions to based on the item's permissions. Yep.\u003C/p>\u003Cp>So I like the\u003C/p>\u003Cp>Speaker 2: change that we do to go with Amazon. Yep. It's interesting. And it's it also could be something that is just a tick mark or something in that dialogue, which can say, hey. Create a signed link or create an unsigned link because people might not want to have that additional check, but just generally make stuff public or something.\u003C/p>\u003Cp>But it could be an option either for the end user to decide or for the admin setting it up to decide. I feel like that is a good way of doing it also to introduce it in a non breaking way if you ever wanna introduce it in just a feature release.\u003C/p>\u003Cp>Speaker 1: Judd's asking if we could display make it so that it's visible in the sense of you'd be able to see who has access to that data. This is not great. Can we do that? If if we're\u003C/p>\u003Cp>Speaker 2: doing it with a token, probably not.\u003C/p>\u003Cp>Speaker 1: No. But if we use, like, the scope JWT, would you be able to see so if I was in here looking at this, would I be able to see could you display here who has access? That seems crazy.\u003C/p>\u003Cp>Speaker 2: Whoever has access to, like, whatever item you're inserting this into has access to that file in or something. So it's not something where we have either this user, like, harnesses you in your file or something, or or do they do, like, color eagle? Or I don't know. So I didn't at least with the route we're planning on going or considering going, that wouldn't be the case.\u003C/p>\u003Cp>Speaker 0: Although, now I'm thinking about it. If you have the we use the permissions for the item for the asset endpoint, you still have a similar case where you could render the HTML somewhere for a person that's not logged in. Although, I guess, at that point, it's it's more expected. But you still Oh, you\u003C/p>\u003Cp>Speaker 2: mean, like, service side rendering or something where you have Yeah. Token or, like, some service level token that actually does the rendering and you still break your links?\u003C/p>\u003Cp>Speaker 0: Yep.\u003C/p>\u003Cp>Speaker 2: I mean, at that point at that point, you wanna do like, you wanna manually track what is publicly available or something, I feel like.\u003C/p>\u003Cp>Speaker 0: Yeah. I'm I'm just wondering because still divergently thinking what we can do to make this just very obvious in how it works, but still secure at the same time. Like, I'm also thinking an alternative, and this is just completely other idea. But if there is a native dedicated public folder in the file library, just a different root folder in the file library that is always public, you make it super obvious that, oh, if you wanna put a public image in your article, pull it from the public folder, right, or move it there first to make it public and then use it in your article.\u003C/p>\u003Cp>Speaker 2: Now I'm wondering if that is way too CMS specific.\u003C/p>\u003Cp>Speaker 0: It is. Although, I guess, yeah, public sharing of files, yes, no, yes, no, maybe. I don't know. Tricky. I know a lot of dams\u003C/p>\u003Cp>Speaker 2: are all public by default, which\u003C/p>\u003Cp>Speaker 0: is also a strange idea.\u003C/p>\u003Cp>Speaker 2: Lot of what? Sorry.\u003C/p>\u003Cp>Speaker 0: I know a a couple of dam providers that default to everything being public for ease of use and then you have the opposite where you can mark certain files as private instead of the other way around. But that is also\u003C/p>\u003Cp>Speaker 2: I mean, we do allow you to conf to set that up. Right? We do allow you to set up permissions. Hey. You're allowed to access files which are located within this folder\u003C/p>\u003Cp>Speaker 0: Yeah.\u003C/p>\u003Cp>Speaker 2: Through public permissions, public policies, whatever you wanna do it with. So we already have that. It's just not there by default.\u003C/p>\u003Cp>Speaker 1: We tried again, I'm kind of okay with that from, I I I don't think we have nobody complains about the ability to make something public. It's more so the one. The other thing we should make sure we come back to in this, is it's also about the way it's being embedded. I think the HTML coding that's actually being used, making it easier to con\u003C/p>\u003Cp>Speaker 2: Yeah. That is something we've glanced over so far. Right? Because\u003C/p>\u003Cp>Speaker 1: Yeah. We're more concerned. Security is to me the the first thing we should be thinking about.\u003C/p>\u003Cp>Speaker 2: Yeah. Because for an image, it's kind of there's an obvious way of how to do it. But for an a tag, I mean, there are some standard attributes we wanna put in there. Yeah. But now the question is, like, what is a standard way of linking to something?\u003C/p>\u003Cp>It's probably an a tag, but is it something that we want to make configurable if use people are using it in service side reactor ending, if you're rendering whatever? Or is that so much out of scope that we say, if you're doing this, you better use the block editor and do your custom rendering pipeline or something or use markdown and go with that? Is it something where we wanna be really open to not rendering just an a tag, but something user defined? Because in the initial request, it looks like it's the requesting only a tags or link tags, whatever. I haven't really been able to see that in the request there.\u003C/p>\u003Cp>Speaker 1: Yeah. Here. Well, that's an alternative. This is what they're doing as an alternative. They're doing some things strangely behind\u003C/p>\u003Cp>Speaker 2: the scenes. Rendered as oh, I think it's a typo. The link should be rendered as an tag. So as a tag maybe in the first sentence or the first paragraph, the motivation.\u003C/p>\u003Cp>Speaker 0: I think that's supposed to be as an as an anchor tag. Yeah.\u003C/p>\u003Cp>Speaker 2: Yeah.\u003C/p>\u003Cp>Speaker 1: So what is this considered currently when we're inserting? Because this is an h ref. Right?\u003C/p>\u003Cp>Speaker 2: It's an image.\u003C/p>\u003Cp>Speaker 0: Is it it's an anchor text. I mean, for for images, it's an image. And for for links, it's just an anchor, an a tag.\u003C/p>\u003Cp>Speaker 2: But a link is not something where we directly allow linking to any records or something. Right? It's just a insert user.\u003C/p>\u003Cp>Speaker 0: And it's just a link. Insert a link.\u003C/p>\u003Cp>Speaker 2: Yep. Yeah. Yeah. Yeah.\u003C/p>\u003Cp>Speaker 0: So so this feature request in its base in most basic form, it's just when I click add a link, allow me to choose a file instead of add a link. That's that's that's bare bones what this is saying.\u003C/p>\u003Cp>Speaker 1: So the same way that we can do image the image and media because they're applying specific tags. But if you're just adding a tag, right, so if I just say I wanna, you you know, make this a link or if I'm just creating a link, I have to specify the URL. So what they\u003C/p>\u003Cp>Speaker 0: want is the to a static file, you'd now have to type in mydirectors.com/asset/whatever the ID is. And and this is this in its simplest form, this is basically just saying, give me a link to a file.\u003C/p>\u003Cp>Speaker 1: Give me a link to a file, same as when you're doing this, where you're inserting an image and you're searching. So they want the they want this regardless of image or anything else. Got\u003C/p>\u003Cp>Speaker 0: it. It's basically the exact same flows in certain image except it pops in a link instead of an inline embed.\u003C/p>\u003Cp>Speaker 1: So you'd have another you'd have essentially another option here that's, you know, insert a direct as file or insert a file. Right? And maybe the image library filters and searches. Got it.\u003C/p>\u003Cp>Speaker 2: Yeah. Which means we immediately derailed this discussion by going, hey. What about permissions?\u003C/p>\u003Cp>Speaker 0: Exactly. That's that's the beauty of these these sessions, Thomas. Welcome aboard.\u003C/p>\u003Cp>Speaker 1: Welcome to our crazy party. I still like the idea of making this this better. Right? So making this more understandable and more usable.\u003C/p>\u003Cp>Speaker 0: Yeah. Image images within WYSIWYG are are infinitely. Because I have another topic if you wanna just derail it a little bit more on this at the other the other way, which is migrations to and from different URLs. If you change the URL of your direct installation, this technically breaks Yeah. It's paint.\u003C/p>\u003Cp>Speaker 1: Actually, I it happened on this very record. I popped this open in preparation for this this morning, and I was like, why is my image not showing up? And I right clicked and it was I'd actually migrated this from, another project, a while back.\u003C/p>\u003Cp>Speaker 2: You see.\u003C/p>\u003Cp>Speaker 1: And now my URL was just back\u003C/p>\u003Cp>Speaker 2: in just this morning.\u003C/p>\u003Cp>Speaker 1: Yep. So when I was looking at the, you know, the link here, I had to actually adjust this to my correct URL. So this is a this is a known issue when we're doing, like, data migrations and things. We've got, our support team has some scripts and things that we'll go through and find try to find and replace known values here. But it's a\u003C/p>\u003Cp>Speaker 0: It's a tricky problem to solve because it's it's by definition, the WYSIWYG one is the trickiest because it is HTML. It's not a pro like a readable format necessarily. I mean, you know.\u003C/p>\u003Cp>Speaker 2: It's something that is like easily solved in I don't know. Like, for example, our block editor or something, right?\u003C/p>\u003Cp>Speaker 0: Right. Yeah.\u003C/p>\u003Cp>Speaker 2: Image could\u003C/p>\u003Cp>Speaker 0: just be nested in JSON or something\u003C/p>\u003Cp>Speaker 2: you can even learn back. Yeah. Yeah.\u003C/p>\u003Cp>Speaker 0: Because you're also dealing with an ID and not a full link. That helps.\u003C/p>\u003Cp>Speaker 2: It's best case best case, it shouldn't even include the link. Like, I don't know what our block editor does, to be honest, but best case, it should just be a acid link or something that just includes the ID of that item you're interested in or that acid.\u003C/p>\u003Cp>Speaker 0: Right. The tricky bit is if you plop that into a browser, nothing shows up. Yeah. It doesn't\u003C/p>\u003Cp>Speaker 2: know what to do with it. Yeah. Yeah. For sure.\u003C/p>\u003Cp>Speaker 0: So you, you have very tricky, tricky setup where that is that is always an issue. And and I'm more than happy because we we have a little bit of time like Lockheed here to to try to to noodle on some ideas for ways around that. Because, you know, some some more CMS specific platforms, they use, like, short codes or something within the HTML. Right? Where it's just like bracket asset ID this and then go figure it out in in post processing.\u003C/p>\u003Cp>That is an option, but that requires the user of\u003C/p>\u003Cp>Speaker 2: the Custom.\u003C/p>\u003Cp>Speaker 0: The output to do something, or we have to have some sort of custom post processing set up for some fields where we say, oh, if you have an HTML field, we'll search through short codes and and execute them. Interesting. Or Yeah. Because custom web components.\u003C/p>\u003Cp>Speaker 2: Custom web components. We could provide a set of custom web components that is a director's image and that knows your CMS location and then just needs the ID, which is effectively what we're doing for Nuxt. Right? There is, like, a country like a Nuxt image module direct as Nuxt module, which is, like, the base URL, and then it just knows the image ID and figures the rest out.\u003C/p>\u003Cp>Speaker 0: Yeah.\u003C/p>\u003Cp>Speaker 2: So that could be an option for the WYSIWYG that it's like, hey, if you're using a custom image resolver or something, you could just insert the ID in the link.\u003C/p>\u003Cp>Speaker 0: You can't use the face tag outside of the head, could you, in HTML?\u003C/p>\u003Cp>Speaker 2: Oh, don't ask me.\u003C/p>\u003Cp>Speaker 0: I don't think so. I think base is only in the head. The for that that's just I'm not just thinking HTML brain because you were saying it should just be, like, a relative link instead of a full URL. More or less, you were talking just the ID. But I'm like, if you make it slash assets slash the ID, then it will work within Directus presumably, but it will not in your own website.\u003C/p>\u003Cp>But a base tag in HTML says, you know, graphics every single link to everything with this domain, which could be work around for that. Right? Where you just have a base tag that says, okay, make the base tag, the direct installation, and then it would just work. But I think a base\u003C/p>\u003Cp>Speaker 2: tag breaks every relative link on your Right. Right.\u003C/p>\u003Cp>Speaker 0: Right. I was gonna say breaks every relative link in your whole package. That's what I'm saying. If only there was a locally scoped base tag where you can just say only within the main tag of my Dom is the base tag something else. But, yeah, I don't think that's gonna be a good solution for this.\u003C/p>\u003Cp>Custom web component is an interesting one too because it requires, you know, a bit of custom JavaScript that needs to happen on every single website that wants to use this, and it's just just a bit of yeah. It is\u003C/p>\u003Cp>Speaker 2: one possibility. Yep.\u003C/p>\u003Cp>Speaker 0: Yeah. I think, if if we if we rely on more of a short code, based approach with some post processing, then you make the migration between projects really lightweight, assuming there's a way to skip the post processing. And then the API output could still be the full URL, but we rely on a short code in the database. So therefore, the value that we store is just like bracket asset ID with all the parameters that you want, and then we generate those into images on the fly. But it's just a bit of a I don't know.\u003C/p>\u003Cp>It's\u003C/p>\u003Cp>Speaker 2: It it doesn't feel like our responsibility necessarily. Yeah. That's kind of why I'm struggling. Same with, the public folder or something. That that feels too much like forcing one way of solving it on people.\u003C/p>\u003Cp>Speaker 0: Yeah. You're not\u003C/p>\u003Cp>Speaker 1: wrong. You're\u003C/p>\u003Cp>Speaker 0: not wrong. Tricky bum. Tricky bum. Oh, one more thing related and related, maybe a bit of both. For images, we just plop in an image tag.\u003C/p>\u003Cp>Right? That's that's what what it does. Do we want to support any other file types that are in line? Because videos images are in line, but if you link to a PDF file or something, Do we want\u003C/p>\u003Cp>Speaker 1: to It comes up. We we see that request as well as additional, like, inline viewers. Right? PDFs.\u003C/p>\u003Cp>Speaker 0: Right.\u003C/p>\u003Cp>Speaker 1: Docs, you know, spreadsheets, whatever. Being able to actually have a preview of what that looks like.\u003C/p>\u003Cp>Speaker 0: The tricky thing with those things is that they're all custom front end frameworks or plugins or libraries or web components. It's not it's not a browser standard. So if we wanna go that route, we would have to have some sort of way where you can configure what markup it spits out if you insert a PDF. Because then you get to choose between, oh, when when I'm inserting a PDF, I'm gonna insert my little HTML markup that spits out a PDF preview or something instead of just the link.\u003C/p>\u003Cp>Speaker 1: Yep. So there's that's that's another common thing that we see on those types of fields. Right? So if I go to paragraph here\u003C/p>\u003Cp>Speaker 2: Which already screams use a freaking block editor or anything other than a wizarding question.\u003C/p>\u003Cp>Speaker 0: I you're not wrong. You're not wrong.\u003C/p>\u003Cp>Speaker 1: So but, again, we support, you know, on some level. Right? Whether this is TinyMC or TipTap or name your editor. People have built their own interfaces here. There's a number of marketplace interfaces around this where the underlying libraries actually are more than we're currently exposing.\u003C/p>\u003Cp>And the question is, can we could we have interfaces have more composability or more extensibility kind of pre exposed, that you could then adapt. You can when the users, you know, when the administrators are setting these up, you could have custom, menu options. Right? So if you could actually I I know tinymc supports it because we've done it. Right?\u003C/p>\u003Cp>We've got the image and the video editor buttons that are there, and they inspect the appropriate tags. I think Tiny MC and Tiptap both support this ability to have an override or a templating option where you can adjust the configuration, add new buttons, add new drop down.\u003C/p>\u003Cp>Speaker 0: Oh, sure. Yeah. We could we could support that for, you know, file insert as well. If we have an insert button that we say, oh, if you're inserting a type of a PDF or something that we, you know, we render it in a different way. It's just so much setup that you end up having to do.\u003C/p>\u003Cp>Right? So right now, indirect is you would have to do that per field, which will be kind of annoying. So we would have to add some sort of global defaults as well for for interfaces to make that a little bit more editable.\u003C/p>\u003Cp>Speaker 1: Yep. And that's why, again, I think some of that we're actually looking at. It's for the extensions team, the the directus labs team to take a look at actually doing some tests on creating some new interfaces or modifying faces Yeah. To give us an idea of what's possible, what would what would work well, and then we can decide down the line whether we adapt that and roll that back into the core interface options as well. Yeah.\u003C/p>\u003Cp>But\u003C/p>\u003Cp>Speaker 0: Or or use a block editor. Like, there's there's, of course, you know, when it comes to and this is this is huge breaking changes and that's something we will do anytime soon, but there's also the argument to be made that is maybe we shouldn't be dealing with HTML at all. I I know it's it's the sort of easiest path to website, but from a data format perspective and for a data portability perspective and a migration perspective and, using it in non web platforms perspective, it is objectively not the right tool for the job, I think.\u003C/p>\u003Cp>Speaker 2: Yep. Yeah.\u003C/p>\u003Cp>Speaker 1: Yep.\u003C/p>\u003Cp>Speaker 0: I think markdown is slightly better. You still have to render it out yourself and you still have some of these migration problems, but at least, you know, renderers for markdown exist across, you know, output types, iOS development, web development, etcetera. But as far as I'm concerned, July 2024, you know, a block editor that returns it in in JSON is the most friendly way to actually render it out across different output vendors. Right? So there's also a world where we can say, maybe we don't concern ourselves with an HTML editor at all.\u003C/p>\u003Cp>We really focus on having one really good block editor, be it based on, tip- tab, shout out to chat, or or anything else, and then offer some utilities to have that transform to HTML, just to make your life a little bit easier, but not try to save it and manage it as HTML within directness.\u003C/p>\u003Cp>Speaker 1: So like an on the fly, the API endpoint would dynamically transform the block editor JSON format into HTML as an option parameter.\u003C/p>\u003Cp>Speaker 2: Right.\u003C/p>\u003Cp>Speaker 1: Clever. Clever.\u003C/p>\u003Cp>Speaker 0: Because that way we get around a lot of these these issues effectively all of them by just not dealing with HTML.\u003C/p>\u003Cp>Speaker 1: No.\u003C/p>\u003Cp>Speaker 2: Are there, folks are doing it as well to provide you with JavaScript libraries to convert to HTML. It doesn't even need to be server side. Though server side seems like a cool option, but, there are libraries out there for converting, like, adjacent tree to whatever, and you can have custom elements. You can render them customly within your frameworks, all of that. I've done that personally as well.\u003C/p>\u003Cp>Like, I've worked with abstract documents as a JSON and rendered them in different frameworks with different components, all of that. And it just makes it a lot nicer to handle if you're willing to spend the effort. But that is kind of the catch of it. Right? HTML is just super easy, but it doesn't give you all the nice options which you would have if you dealt with it in a more advanced way.\u003C/p>\u003Cp>Yeah. But probably it's the reason why we have Wizzy Week in the first place But it's it leaves you with certain limits. Yeah. It leaves you with certain limits.\u003C/p>\u003Cp>Speaker 1: Yeah. Yeah. No. I've got people that are, you know, they they\u003C/p>\u003Cp>Speaker 2: Which makes me always wonder, like\u003C/p>\u003Cp>Speaker 1: Go ahead.\u003C/p>\u003Cp>Speaker 2: No. Go for it.\u003C/p>\u003Cp>Speaker 1: No. I was just saying I've seen people copying and pasting in Wizzy, you know, HTML from other sources and breaking their actual web page.\u003C/p>\u003Cp>Speaker 0: Oh, yeah.\u003C/p>\u003Cp>Speaker 1: Because they've got CSS and other things that they're trying to override, and it's being overridden. And they're complaining that, oh, my fonts don't match on this thing that I copied and pasted from some third party source. Right? Think Oh,\u003C/p>\u003Cp>Speaker 0: that's a big thing. Work. Oh.\u003C/p>\u003Cp>Speaker 1: Yeah. It's I I actually dealt with this just recently for one of our and for one of our clients, one of our actually, a a legacy Ranger Studios client, that we still kind of help out and monitor and support their site. And they came complaining that the fonts weren't matching on articles that they were that they just published. And they said, sometimes it works and sometimes it doesn't. And I was initially, I'm thinking there's some I'm digging through\u003C/p>\u003Cp>Speaker 2: Some of the code on the site. Google Docs and sometimes go into And\u003C/p>\u003Cp>Speaker 1: and then I'm looking at the Wizzio, and then I happen I'm like, what are all these spans and these classes don't exist in our code.\u003C/p>\u003Cp>Speaker 0: What are yeah. And\u003C/p>\u003Cp>Speaker 1: then I real and then I started removing so and suddenly the formatting for the correct. It was picking up the correct font, but they were it was this font code for this HTML was overriding all of the underlying CSS that was configured for the site. So yeah. Yeah. It's a nightmare.\u003C/p>\u003Cp>Speaker 2: Okay. That leaves us with one more feature request after this feature request review, which is how do we get shareable, like, permission permissions baked into an asset link, which makes it easier to manage permissions for anything you link in your editor. And with the agreement that it's probably cool idea and a good idea to include a, a, an, button form, whatever in there that allows you to create an 8 anchor tag to any asset in directors.\u003C/p>\u003Cp>Speaker 0: Yeah. I think that would be a great one to have. And to your point, that's a new feature of choice.\u003C/p>\u003Cp>Speaker 2: Have anyone in the audience who wanna wants to tag on to that.\u003C/p>\u003Cp>Speaker 0: Now the good news is of this session is that all of these things that we described so far, they're all non blockers or supporting the MVP of this, which is insert link to file, which is fantastic, which means that I wanna say, okay. Let's just do it. Let's just do it. It's improvement. It's a new feature, but small one, you know, PRs are welcome.\u003C/p>\u003Cp>It's a good first issue. Let's just do it. Like, the the minimum viable of this? Sure.\u003C/p>\u003Cp>Speaker 2: Is it something we only wanna do in the week, or is it also something we wanna support in the\u003C/p>\u003Cp>Speaker 0: That is a good question. I don't think it's relevant for the block editor because, a file is filed. You can render it out as a link or an image however you want for the markdown interface though. I think it's relevant.\u003C/p>\u003Cp>Speaker 1: Yeah. Because currently, it's just a URL link. Right? You've got the add in an image. I don't see do we support video in markdown?\u003C/p>\u003Cp>I There's markdown, and that's\u003C/p>\u003Cp>Speaker 0: There's really no such yeah. There's there's no native markdown for video.\u003C/p>\u003Cp>Speaker 1: K.\u003C/p>\u003Cp>Speaker 0: So not really. There's also no HTML attributes in markdown. There's a lot of things that are in markdown.\u003C/p>\u003Cp>Speaker 1: That's okay. So, technically, we just need the file link. I'm putting a note in the ticket here in the in the discussion here. Go ahead. Go on this.\u003C/p>\u003Cp>Speaker 2: Alright. Same question for the block editor. Is it also something where we wanna support it as well? Since we might want feature parity between between all of our editor interfaces.\u003C/p>\u003Cp>Speaker 1: Agree.\u003C/p>\u003Cp>Speaker 2: I don't even know what the block editor is capable of doing right now.\u003C/p>\u003Cp>Speaker 1: So it's got image.\u003C/p>\u003Cp>Speaker 2: Like we do image and attachment. What is attachment? Is is attachment already what we're trying to do?\u003C/p>\u003Cp>Speaker 0: I think it is. Yeah.\u003C/p>\u003Cp>Speaker 2: It might be. Yeah?\u003C/p>\u003Cp>Speaker 0: Yeah. I think it is.\u003C/p>\u003Cp>Speaker 1: Already is. Yep. So the only thing we because,\u003C/p>\u003Cp>Speaker 0: the block editor natively supports that. The the library that we use for that just has it. Yep. Yep. The Wizzy tiny MCE does not doesn't have a concept of that yet, so we have to edit edit ourselves.\u003C/p>\u003Cp>Speaker 1: Yep. Yeah. So you get select the file, and I guess the the one thing that I noticed is it doesn't have video. Should block editor have video? Or is it just file as a file as a file for these guys outside of the images that have captions?\u003C/p>\u003Cp>That's a good question. Let's see. Do I have video first deal in here? It's just in some video and see what the preview or window. I don't know what that just did.\u003C/p>\u003Cp>Oh, it downloaded. No. I have a duplicate copy of that. Lovely. So should it have so for parity, does does the block editor support video?\u003C/p>\u003Cp>Speaker 2: Seems like it's just an attachment. Right?\u003C/p>\u003Cp>Speaker 0: I think it's just an attachment.\u003C/p>\u003Cp>Speaker 1: It's just doing it as an attachment right now, but should it have a video interface the same as the HTML does? No. Maybe. Or a video blank. Just for, like, again, feature parity across the where where possible.\u003C/p>\u003Cp>Speaker 0: I think there's a separate plugin for editor JS, which is what we use in the for the block editor, but we'll have to try it out. Different feature request for a different day.\u003C/p>\u003Cp>Speaker 1: All good. So we already have file, so the only place that this needs to be done is. Markdown in HTML. Right?\u003C/p>\u003Cp>Speaker 2: And I think the block edit can just treat whatever attachment the way it sees fit.\u003C/p>\u003Cp>Speaker 1: I will put a note Just\u003C/p>\u003Cp>Speaker 2: for videos in the WEEZY week, do we just insert a video tag, or how does it work?\u003C/p>\u003Cp>Speaker 1: Let's have a look.\u003C/p>\u003Cp>Speaker 0: Yeah.\u003C/p>\u003Cp>Speaker 1: I'll go test it.\u003C/p>\u003Cp>Speaker 2: Yep. K. That's what I figured. Wizardwig. Also, what kind of fan fancy collection is it that you have there, Jonathan?\u003C/p>\u003Cp>My test my test collections always have all 3 of the editors in there. You guys can actually show and hide it. That's cool.\u003C/p>\u003Cp>Speaker 1: Yeah. So I'm using the conditional rules. I use it for demos. So I have this in my Yeah.\u003C/p>\u003Cp>Speaker 2: Yeah. Yeah.\u003C/p>\u003Cp>Speaker 1: My CMS demo essentially where I've got a page a paragraph component. And then depending on, you know, if they're a WYSIWYG shop or they're a markdown shop or they're a block header, just being able to show off the different interfaces quickly and easily, but show and hide them. And it shows off the conditional rule capabilities of the app as well. So\u003C/p>\u003Cp>Speaker 0: It's cool. My my debugging instance is just one of each on every page.\u003C/p>\u003Cp>Speaker 1: Yeah. So so you do get a video player in Wizziweb. Yeah. It's yeah. I think\u003C/p>\u003Cp>Speaker 0: it's just a video tag. If you check out the raw HTML of that, it's it's literally Giant\u003C/p>\u003Cp>Speaker 2: kitchen sink collection. We everything in there.\u003C/p>\u003Cp>Speaker 1: Yep. I have including just a flat text area. So all of our kind\u003C/p>\u003Cp>Speaker 2: of Yeah. So it probably is a video. Yeah.\u003C/p>\u003Cp>Speaker 1: Yep. So it actually renders it with Under the hood. With video HTML tags accordingly. So the question is, does the block editor and or we know markdown doesn't support it, but does the block editor support something similar? Right now we're just inserting it as a file.\u003C/p>\u003Cp>But if the block editor technically supports video, it would be nice to have parity to have the equivalency where video renders nicely. So I'll just put a note.\u003C/p>\u003Cp>Speaker 0: Anyways, taking this back slightly more on track. This feature request as a whole, easy. I think it's easy easy to to accept it. That that's what I was going for. That's so much easy to implement necessarily.\u003C/p>\u003Cp>Easy to accept it. I think it's we should just do it. It's a good first issue. I think it's great for for PRs, if anybody wants to take a swing at this. I think there's a lot of new ideas and new feature requests that are worth discussing more.\u003C/p>\u003Cp>Like, I think this signed link approach to permissions is a very, very interesting one that will be very relevant for something like this. But with that being said, the eye on the clock and me also have a hard stop, unfortunately. I wanna say thank you very much for watching once more. We'll be back soon. Soon, Asia.\u003C/p>\u003Cp>It was a it was a minute since last time, but we'll be back, I believe in 2 weeks, and if not, soon. Make sure to check out this show on direct. Io/tv. Your request review. If you like doing this, somebody like having to get here.\u003C/p>","Welcome everybody once more. We're ready to rock. Welcome to request review. Daniel is out this week, so we got a very special guest for you here. Say hello. Hello. Hello. Good day. Thomas. Welcome to the welcome to the phone. Welcome to the having me. So today, we're gonna be chatting about yet another feature request. And this time, Jonathan, what have we pulled up? We have the lovely improving the way that files are injected in the WYSIWYG editors, is the discussion for today. I believe the extensions team may actually be taking this on behind the scenes in a in a short term solution. But for now, it'd be nice to understand the requirements, the the gotchas, the whys and wherefores, the way that current the way we currently add links and images and videos within a WYSIWYG field. So you can edit links, move your links, take a look at your links here. But according to the to the request, they'd like this to be a little more fully featured in the way that the tags and things are added around the HTML under the hood. It's my understanding. But I'm no front end expert, so let's see what we can figure out and decipher. Alright. So this I can feel it. This is not one of those where it feels like, oh, that that should just be one button. Right? That's easy enough to do. Alright. So starting at the basics and pulling it up, if you seem to look enough to decide over here, by the way, I just added the same thing up, but a little bit bigger. The goal here is basically just like you can put in an image, you wanna link to a file. Right? Easy enough, you think. Inserting a link to a file in its purest form shouldn't be too crazy because we know what the IDs of the file. We know where you would find it slash assets. It's the same as an image. Right? Mhmm. Just as with an image though, the question immediately becomes permissions? Big one. Right? The user that is inserting the file has permissions to see those files and then select it to be linked. But that doesn't mean that the person on the other end that is that's seeing this HTML rendered on a website or something also has the permissions to that same file. Right? And we've seen this before with images. Yeah. I was trying to say it's the same problem with images. Right? Because images share the same properties. Yeah. So the way we do it for images right now is we do have that option where you can sort of hard code in one of the the tokens if that's the way you wanna do it. You could, of course, make permissions a little leaner for reading images. Although that way, you know, it's a little bit more than permission set up. Not ideal. You can have people log in, of course, on your own front end and then use that for permissions. But it feels like even with the link to files, it might get a bit worse because at least with an image, you can immediately see if it doesn't work because you get a broken image. Right? Because you get a permissions issue. So as the person that's implementing it, it becomes a little bit more obvious what's going on. But if you just have a link and the link doesn't work for some, but it works for others, that's tricky. That's tricky. So I think as per usual for for those who haven't seen one of these before, the way this oftentimes works is that, you know, we take the smallest feature request that that is in here. The what is the the status? What is the minimum viable? Then convergently think about, okay, what scope does this live in? What are all the edge cases that we have to think about? What are the problems that will come up? And then sort of take it back down to, okay, what can we actually do today? Right? And what is the long term plan and how do we get there? So I think to me, an important one for to make this one work as expected is all around permissions. So I'm actually very glad that you're here, Thomas, because you just work a lot on permissions as part of this, v 11 release in the RC that is out now, in the GA coming up very soon. Any immediate thoughts on the permission set up for this? Especially with files, I do worry that giving read access to a lot of files like you suggested previously is a big foot gun for people because you might store private files. You might store exports from collections or something in your files and giving, like, real access to any of them feels wrong to do it as a blanket or something. That's like a blanket permission. We we, the best possible way would be to surface that information somehow. Like, how visible is a link or how visible is, like, something you link to, since even if you're testing out the link on your live preview or something, you still might be logged into your CMS behind the scenes. So for you, the link also works. So you have would have to test it in a private window or something. But then again, we could show you, hey. This is how the public what the public permissions for this file look like. Users might not be able to access it. On the other hand, we don't know about your setup. Right? So we don't know, are you actually just visiting those with the public public permissions? Or are you adding a token? Or are you doing some other stuff with it since we don't know really what is the implementation that relies on it. So it's hard to think about a catch all solution that would help people not shoot their foot. So right now with images, we do it. We basically let you do anything with it, and don't hold your hand while doing it. And I wonder if that is also the solution in this case. So just provide more functionality. But if stuff breaks on your end, you have to be aware of it. Seems could be a documentation issue, but then again, the people reading our documentation aren't actually the users using the product in the end maybe. Yeah. It's a tricky one. And and to your point of, like, where do you wanna put this education? Right. Yeah. And and to your point, we when we had this issue for images, the conclusion was, well, you know what? Let's just make all the options available and and put the burden of setup on the the end user to make sure that they're using it right instead of on us to to try to help you with it. It did this made me, think of another feature request that we I don't think we've discussed quite yet here, but it gets come up a couple of times in the past, which is the nested relational permissions, so to speak, where you could say, files are inaccessible by default, but you can allow file reads if they are being read through another relational field. So for example, you could say files are off limits, but if you look up an avatar through a user, you can still access that one avatar in some of its fields, but only if you go in relationally through a user. How does it work with the assets endpoint though? Right. That's where it gets interesting because I'm I'm just wondering coming from. Yeah. No. Exactly. I'm just curious if there is an angle to that, because it made me think of this where I'm like, oh, if you assign an image or an asset into a WYSIWYG blob, maybe we can have it rely on a similar idea of permissions where it's like, okay. The things you make available within, one of those fields can be read in a certain way, but not others. Again, just convergently thinking about it. Do you have any other issues? Sorry. Good. I I don't wanna distract you from a thought. So go ahead, Hans. The the issue I'm seeing with that is, again, like, accessing some data of that asset, totally fine. I can see that work, how it would be set up in permissions. I would be able to do, like, the relational reversal of permissions or something or for items. But since the asset endpoint doesn't know about it, we are still at some point where we why would this user be able to see this? Because then we would have to look up. Are there any permissions that could allow it? And so it gets it gets really complicated on the asset end point. Like, the actual, like, file permissions isn't too much of a problem, but all of the metadata, but the whole, assets itself isn't too trivial to figure out Yeah. Image for that one. Maybe. Again, divergently thinking about this. Maybe the, there's an in between where we can do kinda like what what s 3 supports and and some of those storage providers where you have, like, a signed link that is unique to where it was used. So we can know from the way the asset was accessed, what field in what collection it was accessed from. And then that way, we can do the relational permissions thingy instead of relying on having to search. Because to your point, if you open an asset and we have to search through every single field to see if there's any chance that you used it, that feels crazy. That feels insane. But if we make it a unique link that is unique to that collection of field combination, then that simplifies it a little bit. Because now we do know A lot of things. Where it was accessed from. Yeah. Which effectively could be something like an access token for that. Yeah. Effectively. So so it could be it's it's effectively just just a token with that connects the dots between you're trying to access this image or this asset through an HTML blob, that is on your website. And because we generated a custom link for it, we know what that blob is, and then we can also help you debug, you know, if your file got, is being accessed from sources that you didn't expect it to, we can show you. It's like, well, you got it read from your your HTML body and this and this article or something. Right? Interesting. I like it. That was my thinking as well was either inherit permissions for the item, but then as Hannes noted that the asset endpoint has no idea about that currently. Now that doesn't mean that we don't enhance or find a way, kind of a unique URL or a unique identifier that indicates where this is being used. We've actually seen this. There's another request out there about knowing what what files are associated with which items. Right? It's Right. Right. We we have this problem right now without writing some very complex hook logic that track tracks through a whole set of relationals. You know, we don't because that asset endpoint is kind of independent of all of that and files kind of live independent of all of that, The way that the relational is unless you're forcing relational reverse creation, which then makes your file through, you know, direct us files gets really ugly really fast that way. We have this it's a fairly common request that we see from clients of, I wanna know what my files are associated with. Right? I wanna be able to see that and understand that. So This is this is also an interesting topic in the whole security versus usability piece. Because on on from from a user experience and even a developer experience, if I have a, public HTML blob and I put an image in there, I kinda assume that that image is now also in that same public blob. Right? So I would assume it to work. At the same time, if you if if we were to make it that way where it's like, oh, whenever you put an image inside of a HTML thing, it's now public. You can accidentally expose a whole lot of stuff. Right? Because it's it's a little opaque under the hood. From a security perspective, it's a little tricky. Is it though? I guess again, it's really one of those, like, what are all the different use cases Directus is used in kind of problem. And, like, who are the actual end users and who has who has been educated about that problem, caveat, whatever we wanna call it. Because I I generally like the idea like, it doesn't really have anything to do with that, feature request in general since that seems a lot more low level. But I do like the general idea of having something like a unique or signed, asset URL, which can be used to conditionally allow access to something. And so generating something could be go for it. Sorry. No. No. I was just curious. So when you're generating, you know, like, this this input screen right here, so you'd have a unique URL that's being generated here, right, in some way, shape, or form, whether that's a tag on the end of the, you know, asset endpoint that gives you a question mark, you know, unique key. That has to be stored then. Is that stored then as part of the director's files or a relational to the director's files kind of a system table where we store those unique IDs? And not so much implementation. Just I I'm thinking about so you'd have that ID. But you'd also be able to see that here. Could you also or optionally ensure that you give, you know, an access token option here? So as an actual field input where you could supply an access token or even a default access token for as part of the admin configuration. Because once again, I don't necessarily want users putting in access tokens, but have a way for the administrators to get to apply an access token that has the appropriate permissions for the file. That is the key piece there. That last that last little snippet of the sentence is the most important crucially important part that has the appropriate permissions for the files. The foot gun with the excess token is that somebody just puts in their own users' access token, YOLO it, and then it works. But now you're technically exposing that all over the place, right? Yeah. Because once you're, you're putting that excess token in the image and HTML, it's just a query parameter. So therefore, wherever you render it, somebody can see it. You have to consider it public. See it. They can So what you're effectively doing is you're not using the public role for those images. You're just using a token that you then make public. Right? So that last part is why the sort of developer or user experience or both. I mean, just the experience as a whole for using the static tokens as way to get access to those asset in a link or an image or otherwise. There's a couple of food guns, right, that you gotta be aware of that people may or may not be. Because again, that's one of those things where, you know, if you explain it, that makes a lot of sense. But if you don't know and you just wrongly assume you could put in any access token, you can be in a in a world of trouble. Right? Absolutely. K. Which makes me wonder if that is something I haven't really thought about all the ash cases, but it's something probably we can solve by using a j signed JWT or something that just scopes it to that specific item in a collection, then we don't even have to store that in the database, assuming that you have access to that. Because then in the asset endpoint, we could check, hey, does the user like, this request actually have access to that item, which is signed in the JWT? And that way, we can verify the access. And if that basically overrides whatever, like, more restrictive permissions you have, you would be good to go only for that specific item where that image is linked in. Yeah. So we're basically saying Linked or whatever. Try to summarize that so I understand that we're basically saying if you attach an image or an a file, a general asset, any asset to an item in a WYSIWYG or relational interfaces, maybe even anywhere else. Well, relational interface, I guess not because then you just have a data point, not a file. But if you have an asset link inside of a Wizzywig or a block editor, some of those markdown, we use a signed link that contains what collection and item it came from. And then we can use the permissions for that item instead of the permission for files. So therefore, if you have read access to that HTML field, you defect don't have read access to the images within it. That feels like a very clean setup as far as I'm concerned. Again, probably also food counts with exposing files or people linking to files, which should be internal at that point. It's more of a shooting your own foot than more, of a case where we are trying to prevent it the best we can. Yeah. But that's, that's kind of already here anyway. Right? Because you can restrict the files and folders that this has access to. Right? In the in the actual WYSIWYG config, you can, I I think Do the root folder or something? It's what we do. Right? It should only be what this user has access to. Right? So if I add Add in general. Yeah. Yeah. For sure. If I add an image, you know, I can add or edit. I don't wanna do that. I wanna So your your condominiums and images. Yep. This is my my permissions restrict me to whatever I have access to, and so I shouldn't be able to technically insert something that I shouldn't be able to now. Could get a little more complex, but I like the that was my thinking and couple of notes that I took. I want a way to restrict the permissions to based on the item's permissions. Yep. So I like the change that we do to go with Amazon. Yep. It's interesting. And it's it also could be something that is just a tick mark or something in that dialogue, which can say, hey. Create a signed link or create an unsigned link because people might not want to have that additional check, but just generally make stuff public or something. But it could be an option either for the end user to decide or for the admin setting it up to decide. I feel like that is a good way of doing it also to introduce it in a non breaking way if you ever wanna introduce it in just a feature release. Judd's asking if we could display make it so that it's visible in the sense of you'd be able to see who has access to that data. This is not great. Can we do that? If if we're doing it with a token, probably not. No. But if we use, like, the scope JWT, would you be able to see so if I was in here looking at this, would I be able to see could you display here who has access? That seems crazy. Whoever has access to, like, whatever item you're inserting this into has access to that file in or something. So it's not something where we have either this user, like, harnesses you in your file or something, or or do they do, like, color eagle? Or I don't know. So I didn't at least with the route we're planning on going or considering going, that wouldn't be the case. Although, now I'm thinking about it. If you have the we use the permissions for the item for the asset endpoint, you still have a similar case where you could render the HTML somewhere for a person that's not logged in. Although, I guess, at that point, it's it's more expected. But you still Oh, you mean, like, service side rendering or something where you have Yeah. Token or, like, some service level token that actually does the rendering and you still break your links? Yep. I mean, at that point at that point, you wanna do like, you wanna manually track what is publicly available or something, I feel like. Yeah. I'm I'm just wondering because still divergently thinking what we can do to make this just very obvious in how it works, but still secure at the same time. Like, I'm also thinking an alternative, and this is just completely other idea. But if there is a native dedicated public folder in the file library, just a different root folder in the file library that is always public, you make it super obvious that, oh, if you wanna put a public image in your article, pull it from the public folder, right, or move it there first to make it public and then use it in your article. Now I'm wondering if that is way too CMS specific. It is. Although, I guess, yeah, public sharing of files, yes, no, yes, no, maybe. I don't know. Tricky. I know a lot of dams are all public by default, which is also a strange idea. Lot of what? Sorry. I know a a couple of dam providers that default to everything being public for ease of use and then you have the opposite where you can mark certain files as private instead of the other way around. But that is also I mean, we do allow you to conf to set that up. Right? We do allow you to set up permissions. Hey. You're allowed to access files which are located within this folder Yeah. Through public permissions, public policies, whatever you wanna do it with. So we already have that. It's just not there by default. We tried again, I'm kind of okay with that from, I I I don't think we have nobody complains about the ability to make something public. It's more so the one. The other thing we should make sure we come back to in this, is it's also about the way it's being embedded. I think the HTML coding that's actually being used, making it easier to con Yeah. That is something we've glanced over so far. Right? Because Yeah. We're more concerned. Security is to me the the first thing we should be thinking about. Yeah. Because for an image, it's kind of there's an obvious way of how to do it. But for an a tag, I mean, there are some standard attributes we wanna put in there. Yeah. But now the question is, like, what is a standard way of linking to something? It's probably an a tag, but is it something that we want to make configurable if use people are using it in service side reactor ending, if you're rendering whatever? Or is that so much out of scope that we say, if you're doing this, you better use the block editor and do your custom rendering pipeline or something or use markdown and go with that? Is it something where we wanna be really open to not rendering just an a tag, but something user defined? Because in the initial request, it looks like it's the requesting only a tags or link tags, whatever. I haven't really been able to see that in the request there. Yeah. Here. Well, that's an alternative. This is what they're doing as an alternative. They're doing some things strangely behind the scenes. Rendered as oh, I think it's a typo. The link should be rendered as an tag. So as a tag maybe in the first sentence or the first paragraph, the motivation. I think that's supposed to be as an as an anchor tag. Yeah. Yeah. So what is this considered currently when we're inserting? Because this is an h ref. Right? It's an image. Is it it's an anchor text. I mean, for for images, it's an image. And for for links, it's just an anchor, an a tag. But a link is not something where we directly allow linking to any records or something. Right? It's just a insert user. And it's just a link. Insert a link. Yep. Yeah. Yeah. Yeah. So so this feature request in its base in most basic form, it's just when I click add a link, allow me to choose a file instead of add a link. That's that's that's bare bones what this is saying. So the same way that we can do image the image and media because they're applying specific tags. But if you're just adding a tag, right, so if I just say I wanna, you you know, make this a link or if I'm just creating a link, I have to specify the URL. So what they want is the to a static file, you'd now have to type in mydirectors.com/asset/whatever the ID is. And and this is this in its simplest form, this is basically just saying, give me a link to a file. Give me a link to a file, same as when you're doing this, where you're inserting an image and you're searching. So they want the they want this regardless of image or anything else. Got it. It's basically the exact same flows in certain image except it pops in a link instead of an inline embed. So you'd have another you'd have essentially another option here that's, you know, insert a direct as file or insert a file. Right? And maybe the image library filters and searches. Got it. Yeah. Which means we immediately derailed this discussion by going, hey. What about permissions? Exactly. That's that's the beauty of these these sessions, Thomas. Welcome aboard. Welcome to our crazy party. I still like the idea of making this this better. Right? So making this more understandable and more usable. Yeah. Image images within WYSIWYG are are infinitely. Because I have another topic if you wanna just derail it a little bit more on this at the other the other way, which is migrations to and from different URLs. If you change the URL of your direct installation, this technically breaks Yeah. It's paint. Actually, I it happened on this very record. I popped this open in preparation for this this morning, and I was like, why is my image not showing up? And I right clicked and it was I'd actually migrated this from, another project, a while back. You see. And now my URL was just back in just this morning. Yep. So when I was looking at the, you know, the link here, I had to actually adjust this to my correct URL. So this is a this is a known issue when we're doing, like, data migrations and things. We've got, our support team has some scripts and things that we'll go through and find try to find and replace known values here. But it's a It's a tricky problem to solve because it's it's by definition, the WYSIWYG one is the trickiest because it is HTML. It's not a pro like a readable format necessarily. I mean, you know. It's something that is like easily solved in I don't know. Like, for example, our block editor or something, right? Right. Yeah. Image could just be nested in JSON or something you can even learn back. Yeah. Yeah. Because you're also dealing with an ID and not a full link. That helps. It's best case best case, it shouldn't even include the link. Like, I don't know what our block editor does, to be honest, but best case, it should just be a acid link or something that just includes the ID of that item you're interested in or that acid. Right. The tricky bit is if you plop that into a browser, nothing shows up. Yeah. It doesn't know what to do with it. Yeah. Yeah. For sure. So you, you have very tricky, tricky setup where that is that is always an issue. And and I'm more than happy because we we have a little bit of time like Lockheed here to to try to to noodle on some ideas for ways around that. Because, you know, some some more CMS specific platforms, they use, like, short codes or something within the HTML. Right? Where it's just like bracket asset ID this and then go figure it out in in post processing. That is an option, but that requires the user of the Custom. The output to do something, or we have to have some sort of custom post processing set up for some fields where we say, oh, if you have an HTML field, we'll search through short codes and and execute them. Interesting. Or Yeah. Because custom web components. Custom web components. We could provide a set of custom web components that is a director's image and that knows your CMS location and then just needs the ID, which is effectively what we're doing for Nuxt. Right? There is, like, a country like a Nuxt image module direct as Nuxt module, which is, like, the base URL, and then it just knows the image ID and figures the rest out. Yeah. So that could be an option for the WYSIWYG that it's like, hey, if you're using a custom image resolver or something, you could just insert the ID in the link. You can't use the face tag outside of the head, could you, in HTML? Oh, don't ask me. I don't think so. I think base is only in the head. The for that that's just I'm not just thinking HTML brain because you were saying it should just be, like, a relative link instead of a full URL. More or less, you were talking just the ID. But I'm like, if you make it slash assets slash the ID, then it will work within Directus presumably, but it will not in your own website. But a base tag in HTML says, you know, graphics every single link to everything with this domain, which could be work around for that. Right? Where you just have a base tag that says, okay, make the base tag, the direct installation, and then it would just work. But I think a base tag breaks every relative link on your Right. Right. Right. I was gonna say breaks every relative link in your whole package. That's what I'm saying. If only there was a locally scoped base tag where you can just say only within the main tag of my Dom is the base tag something else. But, yeah, I don't think that's gonna be a good solution for this. Custom web component is an interesting one too because it requires, you know, a bit of custom JavaScript that needs to happen on every single website that wants to use this, and it's just just a bit of yeah. It is one possibility. Yep. Yeah. I think, if if we if we rely on more of a short code, based approach with some post processing, then you make the migration between projects really lightweight, assuming there's a way to skip the post processing. And then the API output could still be the full URL, but we rely on a short code in the database. So therefore, the value that we store is just like bracket asset ID with all the parameters that you want, and then we generate those into images on the fly. But it's just a bit of a I don't know. It's It it doesn't feel like our responsibility necessarily. Yeah. That's kind of why I'm struggling. Same with, the public folder or something. That that feels too much like forcing one way of solving it on people. Yeah. You're not wrong. You're not wrong. Tricky bum. Tricky bum. Oh, one more thing related and related, maybe a bit of both. For images, we just plop in an image tag. Right? That's that's what what it does. Do we want to support any other file types that are in line? Because videos images are in line, but if you link to a PDF file or something, Do we want to It comes up. We we see that request as well as additional, like, inline viewers. Right? PDFs. Right. Docs, you know, spreadsheets, whatever. Being able to actually have a preview of what that looks like. The tricky thing with those things is that they're all custom front end frameworks or plugins or libraries or web components. It's not it's not a browser standard. So if we wanna go that route, we would have to have some sort of way where you can configure what markup it spits out if you insert a PDF. Because then you get to choose between, oh, when when I'm inserting a PDF, I'm gonna insert my little HTML markup that spits out a PDF preview or something instead of just the link. Yep. So there's that's that's another common thing that we see on those types of fields. Right? So if I go to paragraph here Which already screams use a freaking block editor or anything other than a wizarding question. I you're not wrong. You're not wrong. So but, again, we support, you know, on some level. Right? Whether this is TinyMC or TipTap or name your editor. People have built their own interfaces here. There's a number of marketplace interfaces around this where the underlying libraries actually are more than we're currently exposing. And the question is, can we could we have interfaces have more composability or more extensibility kind of pre exposed, that you could then adapt. You can when the users, you know, when the administrators are setting these up, you could have custom, menu options. Right? So if you could actually I I know tinymc supports it because we've done it. Right? We've got the image and the video editor buttons that are there, and they inspect the appropriate tags. I think Tiny MC and Tiptap both support this ability to have an override or a templating option where you can adjust the configuration, add new buttons, add new drop down. Oh, sure. Yeah. We could we could support that for, you know, file insert as well. If we have an insert button that we say, oh, if you're inserting a type of a PDF or something that we, you know, we render it in a different way. It's just so much setup that you end up having to do. Right? So right now, indirect is you would have to do that per field, which will be kind of annoying. So we would have to add some sort of global defaults as well for for interfaces to make that a little bit more editable. Yep. And that's why, again, I think some of that we're actually looking at. It's for the extensions team, the the directus labs team to take a look at actually doing some tests on creating some new interfaces or modifying faces Yeah. To give us an idea of what's possible, what would what would work well, and then we can decide down the line whether we adapt that and roll that back into the core interface options as well. Yeah. But Or or use a block editor. Like, there's there's, of course, you know, when it comes to and this is this is huge breaking changes and that's something we will do anytime soon, but there's also the argument to be made that is maybe we shouldn't be dealing with HTML at all. I I know it's it's the sort of easiest path to website, but from a data format perspective and for a data portability perspective and a migration perspective and, using it in non web platforms perspective, it is objectively not the right tool for the job, I think. Yep. Yeah. Yep. I think markdown is slightly better. You still have to render it out yourself and you still have some of these migration problems, but at least, you know, renderers for markdown exist across, you know, output types, iOS development, web development, etcetera. But as far as I'm concerned, July 2024, you know, a block editor that returns it in in JSON is the most friendly way to actually render it out across different output vendors. Right? So there's also a world where we can say, maybe we don't concern ourselves with an HTML editor at all. We really focus on having one really good block editor, be it based on, tip- tab, shout out to chat, or or anything else, and then offer some utilities to have that transform to HTML, just to make your life a little bit easier, but not try to save it and manage it as HTML within directness. So like an on the fly, the API endpoint would dynamically transform the block editor JSON format into HTML as an option parameter. Right. Clever. Clever. Because that way we get around a lot of these these issues effectively all of them by just not dealing with HTML. No. Are there, folks are doing it as well to provide you with JavaScript libraries to convert to HTML. It doesn't even need to be server side. Though server side seems like a cool option, but, there are libraries out there for converting, like, adjacent tree to whatever, and you can have custom elements. You can render them customly within your frameworks, all of that. I've done that personally as well. Like, I've worked with abstract documents as a JSON and rendered them in different frameworks with different components, all of that. And it just makes it a lot nicer to handle if you're willing to spend the effort. But that is kind of the catch of it. Right? HTML is just super easy, but it doesn't give you all the nice options which you would have if you dealt with it in a more advanced way. Yeah. But probably it's the reason why we have Wizzy Week in the first place But it's it leaves you with certain limits. Yeah. It leaves you with certain limits. Yeah. Yeah. No. I've got people that are, you know, they they Which makes me always wonder, like Go ahead. No. Go for it. No. I was just saying I've seen people copying and pasting in Wizzy, you know, HTML from other sources and breaking their actual web page. Oh, yeah. Because they've got CSS and other things that they're trying to override, and it's being overridden. And they're complaining that, oh, my fonts don't match on this thing that I copied and pasted from some third party source. Right? Think Oh, that's a big thing. Work. Oh. Yeah. It's I I actually dealt with this just recently for one of our and for one of our clients, one of our actually, a a legacy Ranger Studios client, that we still kind of help out and monitor and support their site. And they came complaining that the fonts weren't matching on articles that they were that they just published. And they said, sometimes it works and sometimes it doesn't. And I was initially, I'm thinking there's some I'm digging through Some of the code on the site. Google Docs and sometimes go into And and then I'm looking at the Wizzio, and then I happen I'm like, what are all these spans and these classes don't exist in our code. What are yeah. And then I real and then I started removing so and suddenly the formatting for the correct. It was picking up the correct font, but they were it was this font code for this HTML was overriding all of the underlying CSS that was configured for the site. So yeah. Yeah. It's a nightmare. Okay. That leaves us with one more feature request after this feature request review, which is how do we get shareable, like, permission permissions baked into an asset link, which makes it easier to manage permissions for anything you link in your editor. And with the agreement that it's probably cool idea and a good idea to include a, a, an, button form, whatever in there that allows you to create an 8 anchor tag to any asset in directors. Yeah. I think that would be a great one to have. And to your point, that's a new feature of choice. Have anyone in the audience who wanna wants to tag on to that. Now the good news is of this session is that all of these things that we described so far, they're all non blockers or supporting the MVP of this, which is insert link to file, which is fantastic, which means that I wanna say, okay. Let's just do it. Let's just do it. It's improvement. It's a new feature, but small one, you know, PRs are welcome. It's a good first issue. Let's just do it. Like, the the minimum viable of this? Sure. Is it something we only wanna do in the week, or is it also something we wanna support in the That is a good question. I don't think it's relevant for the block editor because, a file is filed. You can render it out as a link or an image however you want for the markdown interface though. I think it's relevant. Yeah. Because currently, it's just a URL link. Right? You've got the add in an image. I don't see do we support video in markdown? I There's markdown, and that's There's really no such yeah. There's there's no native markdown for video. K. So not really. There's also no HTML attributes in markdown. There's a lot of things that are in markdown. That's okay. So, technically, we just need the file link. I'm putting a note in the ticket here in the in the discussion here. Go ahead. Go on this. Alright. Same question for the block editor. Is it also something where we wanna support it as well? Since we might want feature parity between between all of our editor interfaces. Agree. I don't even know what the block editor is capable of doing right now. So it's got image. Like we do image and attachment. What is attachment? Is is attachment already what we're trying to do? I think it is. Yeah. It might be. Yeah? Yeah. I think it is. Already is. Yep. So the only thing we because, the block editor natively supports that. The the library that we use for that just has it. Yep. Yep. The Wizzy tiny MCE does not doesn't have a concept of that yet, so we have to edit edit ourselves. Yep. Yeah. So you get select the file, and I guess the the one thing that I noticed is it doesn't have video. Should block editor have video? Or is it just file as a file as a file for these guys outside of the images that have captions? That's a good question. Let's see. Do I have video first deal in here? It's just in some video and see what the preview or window. I don't know what that just did. Oh, it downloaded. No. I have a duplicate copy of that. Lovely. So should it have so for parity, does does the block editor support video? Seems like it's just an attachment. Right? I think it's just an attachment. It's just doing it as an attachment right now, but should it have a video interface the same as the HTML does? No. Maybe. Or a video blank. Just for, like, again, feature parity across the where where possible. I think there's a separate plugin for editor JS, which is what we use in the for the block editor, but we'll have to try it out. Different feature request for a different day. All good. So we already have file, so the only place that this needs to be done is. Markdown in HTML. Right? And I think the block edit can just treat whatever attachment the way it sees fit. I will put a note Just for videos in the WEEZY week, do we just insert a video tag, or how does it work? Let's have a look. Yeah. I'll go test it. Yep. K. That's what I figured. Wizardwig. Also, what kind of fan fancy collection is it that you have there, Jonathan? My test my test collections always have all 3 of the editors in there. You guys can actually show and hide it. That's cool. Yeah. So I'm using the conditional rules. I use it for demos. So I have this in my Yeah. Yeah. Yeah. My CMS demo essentially where I've got a page a paragraph component. And then depending on, you know, if they're a WYSIWYG shop or they're a markdown shop or they're a block header, just being able to show off the different interfaces quickly and easily, but show and hide them. And it shows off the conditional rule capabilities of the app as well. So It's cool. My my debugging instance is just one of each on every page. Yeah. So so you do get a video player in Wizziweb. Yeah. It's yeah. I think it's just a video tag. If you check out the raw HTML of that, it's it's literally Giant kitchen sink collection. We everything in there. Yep. I have including just a flat text area. So all of our kind of Yeah. So it probably is a video. Yeah. Yep. So it actually renders it with Under the hood. With video HTML tags accordingly. So the question is, does the block editor and or we know markdown doesn't support it, but does the block editor support something similar? Right now we're just inserting it as a file. But if the block editor technically supports video, it would be nice to have parity to have the equivalency where video renders nicely. So I'll just put a note. Anyways, taking this back slightly more on track. This feature request as a whole, easy. I think it's easy easy to to accept it. That that's what I was going for. That's so much easy to implement necessarily. Easy to accept it. I think it's we should just do it. It's a good first issue. I think it's great for for PRs, if anybody wants to take a swing at this. I think there's a lot of new ideas and new feature requests that are worth discussing more. Like, I think this signed link approach to permissions is a very, very interesting one that will be very relevant for something like this. But with that being said, the eye on the clock and me also have a hard stop, unfortunately. I wanna say thank you very much for watching once more. We'll be back soon. Soon, Asia. It was a it was a minute since last time, but we'll be back, I believe in 2 weeks, and if not, soon. Make sure to check out this show on direct. Io/tv. Your request review. If you like doing this, somebody like having to get here.","e668e4c9-da13-438e-b855-95afe8a9e24c",[356,357,358],"6a0ed408-e558-4d6a-b647-0ad0ebe976f9","1205f141-ef72-462f-9515-e073fd888720","daf59fdc-7852-4d6b-abb0-47c605254e9e",[],{"id":133,"number":134,"show":122,"year":135,"episodes":361},[137,138,139,140,141,142,143,144,145,146,147,148,149],{"id":146,"slug":363,"vimeo_id":364,"description":365,"tile":366,"length":324,"resources":367,"people":8,"episode_number":370,"published":371,"title":372,"video_transcript_html":373,"video_transcript_text":374,"content":8,"seo":375,"status":130,"episode_people":376,"recommendations":380,"season":381},"18618","1000292187","In this recording of our live event on August 15 2024, Daniel, Jonathan, and Rick discuss import and export options for flows","d71dfd7c-0662-41cc-aece-dfa8bc79919a",[368],{"name":304,"url":369},"https://github.com/directus/directus/discussions/18618",10,"2024-08-22","Import & Export option for Flows","\u003Cp>Speaker 0: Welcome to another episode of request review. What are we talking about today?\u003C/p>\u003Cp>Speaker 1: We're talking about import and export options for flows.\u003C/p>\u003Cp>Speaker 0: Oh. Now then if he says a like that, it sounds\u003C/p>\u003Cp>Speaker 2: Why don't we just edit then? You know? It should be quick fix. Right?\u003C/p>\u003Cp>Speaker 0: I think that's a great idea. Well, with that being said, thank you so much for watching. Find this episode on of course, I'm kidding. There's there's interesting, as per usual, these episodes, that's why we do them. Some fun edge cases here to consider.\u003C/p>\u003Cp>First and foremost, for those, you know, out of the loop flows, automation workflows, you can set up, you know, triggers. If somebody saves a thing, somebody hits an endpoint, somebody clicks a button in the app, do something. Right? And that something is a set of individual operations, different blocks, so to speak. You can connect together to make it do things.\u003C/p>\u003Cp>Now if you create multiple similar flows or you wanna move them to and from different installations, having some sort of way to import them and export them makes sense. Right? Just as a core set of functionality, absolutely. Somebody in the chat too. You know, flow and operation import is the number one thing that breaks when we sync our schemas and database across different projects.\u003C/p>\u003Cp>So why doesn't it not exist then, or why does it not work properly?\u003C/p>\u003Cp>Speaker 2: That's a good question. I think, that was before my time. So you're probably better equipped to answer that question.\u003C/p>\u003Cp>Speaker 1: There's there's a variety of things that happen here. Right? So schema differentials. Right? So if the scheme is different ahead of the flows being imported, if you're watching and monitoring things that don't exist in that import side, problematic, variables, referencing data and information that doesn't exist in one system to another.\u003C/p>\u003Cp>There's a flows are moving flows, I mean, the APIs are there. We do it all the time with our templating stuff, but we do that in a very controlled way where we're importing and handling the relationals. Because once again, now you've got relational data operations to the flows themselves and all of the data. What I've got a marketplace operation that's not installed in the next environment, there's, you know, there's a there's a great many things that have to be validated and checked, especially on import. Export, not so much, but on import, import gets\u003C/p>\u003Cp>Speaker 0: Absolutely. Has to be And then another important part of those same edge cases there is what about options that need to be different installation to installation, but, you know, 90% of the rest of it is the same. So for example, a a super simple flow that I oftentimes use as an example is, you know, you make a change and you trigger a build on your CD platform, like a Netlify build or something. That production Netlify URL is different project to project because you're building different websites, but the flow configuration, the trigger, you know, the setup for making the request and all that is the same. Cool.\u003C/p>\u003Cp>So looking at this discussion here on GitHub, basic example, motivation. Now the motivation makes a lot of sense. That's just basically, you know, what we're what we're talking about here. I think there's no no discussion on, the usefulness here. When it comes to actual implementation, there's a question of, do we tie this to part of the schema snapshot and apply logic?\u003C/p>\u003Cp>Right? Do we really treat this as it's part of your project's configuration, and we wanna move that between different instances? Or do we treat this more as a kinda more traditional import export like we have for regular collections where you can just say, well, give me all of the operations, and we'll reimport them back in.\u003C/p>\u003Cp>Speaker 2: To me, personally, it sounds more of the traditional way. Like, the correct way would be the traditional way because flows are not specifically schemas. Right? Like like, they're entries in the table, and that's not the schema, those would be items, and I think we should sync them separately. But yeah.\u003C/p>\u003Cp>Speaker 0: And immediately, people start chat typing in the chat. I love it. So this is this is a fun discussion that that has come up in the past in in these request review sessions anyways, but we're we're yet to reach the the the silver bullet answer for what is schema or what is configuration. Right? Flows is to me is one of those points where I think 80% of it is configuration of your project.\u003C/p>\u003Cp>And if you wanna duplicate your project or if you wanna move that from dev to prod or you wanna, you know, use it as a template starting point for something else, you can make the argument that it's definitely part of the same thing that is just one unit of export for the whole configuration of your project. Right? So that's schema and and flows. Last time we were talking about it, you know, it was in the context of roles and permissions, which is a similar but different, you know, part of data, part not. But to to just Josh's point here in the chat, in the data model, you know, the flows are just data in the database.\u003C/p>\u003Cp>But for the perspective of that end user, they're all part of the application that you're, you know, configuring, right, which makes sense. And in that case, you can definitely make the argument, oh, it's just part of, you know, the the application model settings, schema export, and and apply. But that still raises the question, is it the blanket everything? How do you subset it? Because for the schema right now, it's it's everything.\u003C/p>\u003Cp>And how do you deal with options that are different? And how do you deal with active versus inactive? Do we deactivate them on import by default just to be safe. Because you could have a cron thing that could go haywire and talk to, you know, 3rd party production systems if you just spin it up in a new thing.\u003C/p>\u003Cp>Speaker 2: Very valid points. And I and I do see the argument also from Joshua. It kinda it does make sense, right, if you interpret the flows as being part of your infrastructure, then they do kind of feel\u003C/p>\u003Cp>Speaker 0: schemey. Scheme.\u003C/p>\u003Cp>Speaker 2: I'm gonna use that. Scheme esque. Yeah. I I can see that argument. Okay.\u003C/p>\u003Cp>I'm kinda okay. Like in, in the beginning I was like, no, no, no, no. The data, they just stayed up. Those are rules. But now thinking about it, yeah.\u003C/p>\u003Cp>Speaker 0: It's the rules.\u003C/p>\u003Cp>Speaker 2: Damn. Interesting. Yeah. Kinda I'm kinda torn. I'm kinda in between.\u003C/p>\u003Cp>Like, it does it does make a hell of a lot of sense, but,\u003C/p>\u003Cp>Speaker 0: they got a lot. It's funny because we we keep finding ourselves coming back to the age old question of what is and isn't, project configuration that should be sort of version controlled is kinda the the where that's going. Right? Where you wanna have a file that you version control and that includes a bunch of stuff versus within the data, so you differentiate between the 2. And this is this is kinda what earlier when I said, oh, if I make if I build flow, the whole flow but I want the URL that we're talking to to be different.\u003C/p>\u003Cp>So that URL should be in the same static file export. Then by definition, it needs to be in this static file. Right? Because otherwise, you have to do both. Is that easier to maintain?\u003C/p>\u003Cp>Is that worse? Right? But if you're treating it as I wanna have a template that I use to create new projects, but then manage the rest in the project itself, that would still work. If you're treating it as the file becomes the source of truth, now you have to make duplicates of the same, you know, config files to make it work for your different projects. Might be a good thing.\u003C/p>\u003Cp>Might not be a good thing.\u003C/p>\u003Cp>Speaker 2: Did we did we actually, I think there's another small thing, related to this with, like, if if I just want to quickly export one specific one or, I had a not sure if this is, like, a slight tangent that we should go down on, but, when I played around with flows, I had the problem of, I created, like, 15 or 20 different ones, because I was, you know, trying it out and, they got automatically generated. And I had this little gripe with our way of displaying them because there was no, possibility to actually select multiple ones and delete multiple ones. And that kinda sounds to me like if we touch this, you know, with selecting them, exporting them, maybe, you know, filtering them so you only export a couple of them, it feels like selecting them would also fall or, like, lend itself to also be done with this issue. Right? But this is kinda a little different.\u003C/p>\u003Cp>Sorry. Just came to mind.\u003C/p>\u003Cp>Speaker 0: No. Yeah. You're absolutely right, though. Yeah.\u003C/p>\u003Cp>Speaker 2: Okay. So Joshua says, for a user story, we use tons of flows in production and development across 2 applications with the following workflow. We run the whole application locally, modify flows, code extensions. Okay. So far so good.\u003C/p>\u003Cp>Export the schema flows, collections, fields, etcetera etcetera, using a schema sync extension. Okay. So far so good. Commit the schema to version control and build images. Okay.\u003C/p>\u003Cp>In production, import the schema collections and flows as defined in the image. Alright. The result is that flows are always consistent between development and production, and the production flows are immutable. It makes sense. But this, I I guess this is to the point that I said earlier.\u003C/p>\u003Cp>Right? With then, you know, if you want to have, like, development flows production flows, then you have to duplicate them and both of them.\u003C/p>\u003Cp>Speaker 0: Here we go the route in the chat as well saying, you know, what I usually do is try to keep the flows clean by saying, the only thing I export is the values everywhere. And then for the parts where you use different day the data model, there's a sort of settings collection, I imagine, for those flow operations.\u003C/p>\u003Cp>Speaker 2: So you're actually fetching your needed stuff out of your database, and those fields would be different on your dev machine and the production environment. Correct?\u003C/p>\u003Cp>Speaker 0: Right. Yeah. It's basically the way to have that sort of 90%, 10%, you know, split I described earlier solved by using a a settings collection for that, which which makes me think, is that something that could be a native thing where at the top of whatever the file export is for flows, there is a set of very tools you can define, reuse within the file. So you have a single file source of truth that then the app, once you're importing it, the requests, what values do you wanna use for these variables to get food for thought. Right?\u003C/p>\u003Cp>For for those new in this session, it's always about divergently thinking through all of the options, and all of the edge cases and then trying to converge back to, okay, what is something we can do today versus the long term plan? That would be a kinda cool in between, I think, where, you know, in the static file, we have to make sure it's human readable and easy to manage, of course, but you can have you can just describe at the top of the file. Here's a couple of variables that I wanna be installation installation, and then reuse those in your operation settings. The moment you you know, from within Directus where you're using those flows, we can show a a sort of mini form in options that says, okay. What what are those variable values?\u003C/p>\u003Cp>Okay. Okay. Then I think one other thing in, in close that has been there's there's a couple of I mean, I don't know if it's a bug, but it's kind of annoying to deal with is that right now flows make an operations to tables. And it works right. So if you're using the current APIs, you have an export for operations expect you have an export for flows.\u003C/p>\u003Cp>Flows are sort of it's it's a one to many type of thing. Right? You have more 1 or more operations per flow. A very normalized SQL data model for that, which in its, you know, theoretical purity is correct. But it does also definitely mean that sometimes if you're importing operations where the flows doesn't exist, you get foreign key constraint problems.\u003C/p>\u003Cp>Right? Because you're pointing it to a flow that doesn't exist. It also means that when you're exporting it, you end up with 2 different export flows, one for the operations. So that is a bit of an order of insertion interesting thing. It also means that every operation points to the next operation it needs to trigger.\u003C/p>\u003Cp>So that also means that operation insertion order matters, in that table. And, again, that all makes sense from a SQL database perspective, but definitely not, you know, the most user friendly way to do it. And that is just, you know, the the thing you learn over time in in terms of the data model. The question actually came up just now. I see it in the chat, Joshua.\u003C/p>\u003Cp>Out of curiosity, you know, why is that a separate table instead of a big JSON field? Concerns about size and speed, script operations. The, it's partially because JSON fields were just not as well supported or existed at all. And at that point, it did become a bit of a, you know, performance concern in some databases. Luckily, you know, I know 2024, that is that is a different, picture now or, you know, even SQLite has support for for JSF, JSON fields, which is fantastic.\u003C/p>\u003Cp>Concerns about speed has been sort of resolved because of that because now databases can store them, you know, efficiently instead of the large text blob. Size is a concern still a little bit, and that is a similar thing where before it was just a text field, you know, databases were fairly inefficient around storing, you know, unbound blobs of text that would have been JSON but that should also now be way more doable across the SQL vendors. So for what it's worth, I actually think that now, especially now with SQLite support and Oracle DB also being on the JSON train, this is now a new question, right? Should operation just be a nested object on a flow? To which the answer is probably yes, actually, because it's always a tight coupling.\u003C/p>\u003Cp>You're not really moving an operation from one flow to another And storing the actual flow as a nested tree of operations is more efficient, so we don't have to stitch together that tree from from the c port rows. That was just the thing we couldn't do yet, you know, when we when we shipped flows, but nowadays, for sure. Yeah. So that is that is also an interesting thing, which helps with exporting and importing and helps with the ease of authoring it as a file. Right?\u003C/p>\u003Cp>Because if we're saying that operations are represented as a nested tree, kinda like, for those who are familiar with it, like CICD pipelines in GitHub or or those tools, it's oftentimes just a YAML file that says it runs step, step, step, step. Right? So a flow could be a very similar syntax in that sense if we store it that way.\u003C/p>\u003Cp>Speaker 2: Sounds reasonable.\u003C/p>\u003Cp>Speaker 0: And it's only a tiny method for I can change.\u003C/p>\u003Cp>Speaker 2: Okay. So we talked a little bit. How does it look like? How could it look like? Why would this feature be not as easy as you think?\u003C/p>\u003Cp>It's probably our standard go to.\u003C/p>\u003Cp>Speaker 0: So I think in its purest form, just export everything from one flow and import everything from one flow, either through a duplicate button or a separate endpoint. That is not super tricky. The insertion order when you're doing the import is a bit of technical complexity on the implementer side. But from a user experience perspective, it shouldn't be the end of the world. I think the real questions that we have to prepare ourselves for are around what happens if you have a flow that does something destructive and like a cron.\u003C/p>\u003Cp>And the moment you import it, it starts wreaking havoc. Right? Do we import them as disabled by default? Is that what you want? If you're in an environment where your prod is just importing it and and otherwise, it's considered immutable, you want them to be active instead of inactive.\u003C/p>\u003Cp>Right? So how do we do with deal with that? And then around that variableness of you have the flow that's the same, but you have some of the settings that need to be different. Is that something that we have to bake in, or is that something that we say, well, sucks. That just doesn't exist, and you have to duplicate files.\u003C/p>\u003Cp>I think it's worth at least thinking through those questions even if the initial implementation is just going to be, you know, almost the exact same what was described here, which is just import flows, export flows. Bang. Right?\u003C/p>\u003Cp>Speaker 2: According to Joshua, having a, destructive crone is just a skill issue. Fair enough. Problem problem fixed. One less problem to worry about. Alright.\u003C/p>\u003Cp>And, yeah, okay. So so the so the template ability, it it really does sound like a mustache template kinda thing. But, like, I'm I mean, we had a similar thing before, right, with, like, the script operation, for example, where it pulls in, like, your environment. So technically, the environment variables could be different. So you can actually have differing logic inside of them.\u003C/p>\u003Cp>Speaker 0: Yeah. And we do allow you know, in every operation, we allow you to use a value out of a previous step. So using, you know, the the suggestion that we set as a settings table is is a very good alternative, I think. Honestly, it makes a lot of sense. It makes a lot of sense.\u003C/p>\u003Cp>But that is something that we have to just say, okay. If that is our recommended approach, then let's document it as such, because we know it is a I I I mean, of course, we haven't done the the full surveys and everything else, but I would assume that this is a fairly common use case where, you know, the the main use story here is you have a dev environment, you export it so you have a single source of truth that's version controlled, and then you use that to power your production instance. Right? So you use the UI and everything else to configure it, and then you use the code as your immutable source of truth for prod. That's that's sort of the the first user story.\u003C/p>\u003Cp>And I think the second one is really that you have the export as a templated starting point or templated source of truth for multiple projects that are all in prod. Right? So either it is a starting point where if you spin up a new, you know, templated, the, event website or something and they're all the same, so you wanna use the same kickoff point. You have multiple production instances that use the same config. Right?\u003C/p>\u003Cp>That I think those are basically the main to, use cases for for this. Mhmm. And I think in both cases, there's a case to be made for, you know, template ability or at least the the variable, settings, which, again, table.\u003C/p>\u003Cp>Speaker 2: Table does sound pretty good. Pretty pretty reasonable. And similar to what you said, Rijk, earlier, or Jonathan rather, I think, the flows, according to Joshua, you know, if you import something, you could be referencing some tables that no longer exist. So how do we deal with that? Error messages, error pop ups, aborting, disabling the flow and just, you\u003C/p>\u003Cp>Speaker 0: know I think there's also a good data modeling question to that to be honest. I think for operations right now those settings that hold a a field or a collection name, those are basically just a string. Right? And then we, one once the operation runs, it uses that string to try to read data from those tables and whatnot. I think the only solution here is that we treat those as a separate data type.\u003C/p>\u003Cp>So instead of saying it's a string, we say it has to be a collection reference. And therefore, the moment you do an export or import, Directus as a platform can recognize what those settings are supposed to be and validate if they are valid paths. Yes or no. Right? So I I think the the the longer term answer to this question would be to treat those as different data types where it's like, okay, collection reference, field reference.\u003C/p>\u003Cp>So therefore, we can validate it on import or export or both, and almost do like a if you ever see it in in Word or Pages when you open the document, somebody had a bunch of custom fonts and it shows, you know, cannot use cannot find these fonts. Choose what you wanna use instead. That would be kinda the only way I can imagine that to work. Yeah? Mhmm.\u003C/p>\u003Cp>Speaker 2: I mean, if we, yeah, if we treat, you know, the, flows as part of your schema or your your infrastructure, your application, and if then an imported flow does not work because of, you know, like an an unreferenced or wrongly referenced thing in an operation, then technically we should reject that whole import because your entire application becomes inconsistent or can can could become inconsistent. So think, like, if we really consider it part of your application and your whole infrastructure, then we just have to reject everything if something goes wrong.\u003C/p>\u003Cp>Speaker 0: Hans makes a good point here in, in the chat saying, you know, same with role IDs in the permission settings. Effectively, what we're talking about is foreign key constraints, but in JSON, right, where it's like you have a a blob of settings that is different and unique to an operation type because every operation is different and we don't have like a we don't have individual tables for each of the operation types or something where that'd be insane. But what we're talking about here is effectively, how do we do forward key constraints within an operation here? Right? And exactly everything comes back to cache invalidation, naming things, and validating and structure data formats.\u003C/p>\u003Cp>That's great. Yeah. But some sort of way, you know, in the operation value, if we can read it statically, that'd be great, you know, where you can look at an operation settings value and just be recognize what are supposed to be form keys. It could be some sort of unique value syntax, although that feels a little proprietary. It could be, you know, that the operation defines, a sort of JSON schema type of thing that we know what that unstructured data type is supposed to be so we can validate it.\u003C/p>\u003Cp>But, yeah, at the end of the day, what we're talking about is really much foreign key constraints for, operational layout settings and everything else.\u003C/p>\u003Cp>Speaker 2: Yeah. Validation. Just to because I got curious, like, I'm, I think, just to getting back to the import order, like, please correct me if I'm wrong. So I think, if I remember correctly, the flow, references the first operation, and then each operation references the next operation. So the order of operate the the order of import would have to start with the first operate no.\u003C/p>\u003Cp>Because then you can't access you can't reference the second one. Oh, okay. So you have to do it backwards. Yeah.\u003C/p>\u003Cp>Speaker 0: Yeah. Yeah. Yeah. Yeah. Exactly.\u003C/p>\u003Cp>Speaker 2: Exactly. Exactly.\u003C/p>\u003Cp>Speaker 0: I'm still the father\u003C/p>\u003Cp>Speaker 2: to change.\u003C/p>\u003Cp>Speaker 0: Go on. It's the other way, bro.\u003C/p>\u003Cp>Speaker 2: Teacher, that's wrong. No. Right. I can see you have to step step through it once and then just pop off the stack and then go backwards. Okay.\u003C/p>\u003Cp>Speaker 0: Which is also why, you know, I mentioned if we save it as a nested object tree as is and just treat it as one big blob, right, instead of a semi structured thing, that that simplifies export import, like, tremendously, really, because we don't have to do that. We don't have to care about, insertion order because it's all nested on the flow. So, therefore, you don't have those foreign keys pointing back and forth. And a resolve and a reject just becomes a nested object instead of, what you call it, reference to a different, thing in the flat list. Right?\u003C/p>\u003Cp>So that simplifies quite a bit, in in that sense. It's a bit of a break and change for tooling that exists against the operations endpoint, but it would make this a lot a lot less annoying. And I think it also solves one other bug. We we've had a bug in flows where people have run-in into where if you're editing a flow, and I think it's you disconnect operation, then you try to reconnect it somewhere else\u003C/p>\u003Cp>Speaker 1: Right.\u003C/p>\u003Cp>Speaker 0: You get that error that is, like, cannot 4 giga straight. Right? Because you're, Yep.\u003C/p>\u003Cp>Speaker 1: You have to\u003C/p>\u003Cp>Speaker 0: disconnect it. You're dealing with 4 giga\u003C/p>\u003Cp>Speaker 1: from reconnect it in the order that you want. Yeah. It's a Yeah.\u003C/p>\u003Cp>Speaker 0: Exactly. And that is because you're trying to change those foreign key and how they point to each other in a way that is database technically speaking.\u003C/p>\u003Cp>Speaker 1: We have to answer that question for clients on\u003C/p>\u003Cp>Speaker 0: probably almost It's it's a it's theoretically correct. It's also annoying as hell. Yeah. It's one of those\u003C/p>\u003Cp>Speaker 2: Is neck beard correct? Actually actually, it is correct.\u003C/p>\u003Cp>Speaker 0: It is. Pure. It's database pure. Suck\u003C/p>\u003Cp>Speaker 2: it. Yeah. Oh, asks, are we talking about creating custom operations from the UI? No. We are actually talking about importing and exporting flows.\u003C/p>\u003Cp>So, for example, if you export your current schema and import your schema into your new environment, Should flows be included, how should how would that look like, etcetera etcetera.\u003C/p>\u003Cp>Speaker 1: So the template CLI utility that Alex and Bryant and the team put together, we migrate everything including flows. But we have full control over everything. It it's exporting content and schema and everything else comes back in in the appropriate order. So your schema, your, you know, updates and things that need to exist before flows get created all happens as part of that kind of operation steps through the CLI. So configuration as code, kind of the general thoughts that we're working towards there will help with this generally, but I I was taking notes here.\u003C/p>\u003Cp>I saw some of the comments over here. If you're updating an existing flow, Well, if you're updating something in production, flow migration is now gonna have to be maintenance window for anybody doing that. Right? Because if you've got active flows, you've got crons, you've got other things that are going on, if you suddenly come in and hammer a flow that made changes, you're gonna cause issues. You can break, you can lose data, cause problems.\u003C/p>\u003Cp>Transactional processing and other things can be impacted with updating an existing flow. So because currently, you know, our practice with the CLI tool is we delete all the operations and recreate them in order to avoid any kind of, you know, what changed or didn't change just from a complexity standpoint. But those are things that we're gonna have to consider as well as when you're migrating a flow. Are you updating the existing flow, or are you gonna delete and recreate?\u003C/p>\u003Cp>Speaker 0: Yeah. But,\u003C/p>\u003Cp>Speaker 1: you know, from an operational standpoint, my my alerts go off from a security risk perspective of if I'm using Flows for invoice processing or I'm using Flows as part of a payment process, which we have clients doing, And we're suddenly gonna, you know, whack a flow and recreate it, or we're gonna update it in some way. What are the operational impacts and risks of doing that? And they've gone crazy in the chat again.\u003C/p>\u003Cp>Speaker 0: To Hamza's point, that's kind of always a problem with with any sort of data migration. Right? If you import anything new into a production environment, you gotta make sure that you know what you're importing. That's that's the name of the game. That is also why, you know, the static file route in between is is what we're all talking about here.\u003C/p>\u003Cp>So that becomes your source of truth, and that is version controlled so you can see when it was updated by who. You can have some, you know, review processes in place to make sure that it has needs to have sign off, all that kind of stuff. But, yeah, it is technically always just a problem with any sort of data migration. If you have a settings table and import whatever on top of it, then it also breaks. Thinking about the settings table a little bit more, Are the settings always tied to a flow or is it more common to have settings that are global to your whole project and then happen to be reused in the flow?\u003C/p>\u003Cp>The reason why I'm saying that is in in a flow execution, we have that data object. Right? So that holds the all the data that's available in the operations and in the flow. One of the fields in there is that dollar sign trigger. That is just the information of the flow itself.\u003C/p>\u003Cp>Like, what caused it to trigger? I figured we could just have an additional flag in there for any sort of custom data that you wanna just have in that flow global, Right? That you can then reuse in those operations with the existing tools. So therefore, you can make a flow field, flow setting, Netlify URL and that just is becomes one of those data things that you can in in your request operation, you can use the parenthesis the the curly brackets, to reference back to your global flow data. Right?\u003C/p>\u003Cp>That could be a a sort of alternative to a settings table, but it would be unique to each individual flow. Yeah. Exactly what Joshua is saying right now. It's basically specific flow environment variables. Right?\u003C/p>\u003Cp>It would be, you know, environments in the, just that flow. And, yeah, you could theoretically already do that. You could use script operations or you could use the the JSON operation to just return, you know, some static data and then use that elsewhere. That's very true. Very true.\u003C/p>\u003Cp>But it could be a native thing. Then when you export and import it, you just have it as a sort of flow level thing, instead of as a separate operation.\u003C/p>\u003Cp>Speaker 2: Oh, I mean yeah. There's definitely both, both options. Like, having a global thing, is very useful for general stuff, like, even general info between operations, like a brand name, a URL that you reuse in between different actions. But I can also see, you know, the usefulness of tying something specifically to one, thing just for one thing. Sounds pretty good.\u003C/p>\u003Cp>I guess the the the, the actual question is just, okay, how do you manage that in a good way? You know, like, how do we make it pretty? How do we make it a good UX? But I yeah. It it makes sense from,\u003C/p>\u003Cp>Speaker 0: and One one I know Brian and Kevin will yell at me for if I don't bring it up. How do you save it encrypted? Like, some of those settings could very well be, you know, an API token or or things like that. Right? So how do you make sure that that stays secure as well?\u003C/p>\u003Cp>Speaker 1: Yep. That's why I I I think traditionally, most people seen here end up creating a custom table, that's an admin accessible only table. It's not given any permissions for anybody else. You can then store hashed keys. You can store data and values that are masked, only accessible to the administrators kinds of things.\u003C/p>\u003Cp>But I, you know, I've run into this. I actually had this report just a, like, a default language as a filter right across a flow. I was doing a bunch of flow operations and they were nested translations, and I wanted to be able to just say, oh, I only want a specific language. And then I was and you can do things like it's it's simple enough to do a run script that just exports the value. So now you've got that variable in memory, right, in in the data data payloads.\u003C/p>\u003Cp>But Right.\u003C/p>\u003Cp>Speaker 0: So That's that's where it gets that's oh, here comes another site engine. That's the fun thing about these episodes, man. I thought this is gonna be a 10 minute topic, and here we are 45 minutes in, and I just realized something new. When it comes to secret values like that, we have to store them encrypted, not hashed because we have to be able to decrypt them for use in the actual operation. Right?\u003C/p>\u003Cp>So when you make a request and you have to include some sort of token, it needs to be the original token, not the encrypted version. But to the chat's question here from Joshua again, you've been killing all of these questions. Thank you for them. You know, who's allowed to see the config? Right?\u003C/p>\u003Cp>Then, well, I'd say for the right UX at this, you can insert them once, and then that's it. Right? We don't show them again. But at the exact same time, you can then use a run script operation, return them, and then there they are. Right?\u003C/p>\u003Cp>So it's it's just a bit of a fake fake sense of security. They are encrypted into the database to make sure that that stays as secure as we can, so it will never be I mean, that's that's kinda this is kinda the crux of it. I it will never be exported as is, but at the same time, you know, does that matter? Even when you're doing it, it's not a closed closed.\u003C/p>\u003Cp>Speaker 2: Right? Yeah. Yeah. Especially since flows are, at least at least right now, just, an admin exclusive thing. So we kinda you know, like, security schmecurity.\u003C/p>\u003Cp>You know? Like, if you're already an admin, you you have different problems. Like, if your attacker is already an admin, your flow keys are the least of your worries, basically.\u003C/p>\u003Cp>Speaker 0: Yeah. Yes. No. Yes. No.\u003C/p>\u003Cp>Yes. No. Maybe. It's it's tricky in that sense. It's it's weird, though, when you think about it.\u003C/p>\u003Cp>And this is the same when you're talking from a platform team perspective, this is the same problem you're seeing on, you know, AWS secrets manager or d o environment variables or something like that. If you have an encrypted value and you save it, you then, you know, s h into your container, you do print f and there they are. Right? It's like they're stored as secure as possible, but then in your running process, you can just print the environment and everything is right there. But you gotta figure out what is what is the right move.\u003C/p>\u003Cp>Right? Because it can you have read only access to flows where they're hidden? But then if you have update access now, by definition, you have a way to expose them. Right? Is there a way is there a different security level where there should be the the sort of admins that have access to secure stuff and admins that can edit flows, but they're not the same thing?\u003C/p>\u003Cp>That that's a different question. Yeah. I\u003C/p>\u003Cp>Speaker 2: mean, if if we go down, you know, the the settings table route, then we already profit from our, authentication, authorization, system. So, you know, you you can already then assign oh, exclusively these people are allowed to read them, look at them, and stuff like that. So You don't need to plan out every case ahead of time. Well, then you're you're in the wrong stream, my friend. This this is what we do.\u003C/p>\u003Cp>Speaker 0: And again, this is this is the divergent part of all this. Right? This is luckily Yeah. A lot of these things are not blockers to at least get to the minimum viable, which is let us explore these damn things.\u003C/p>\u003Cp>Speaker 2: But Right.\u003C/p>\u003Cp>Speaker 0: These these are the things that people will, you know, use it for and maybe use it wrongly and then maybe expose themselves to massive headaches and issues down the line. So I do I do wanna at least be aware of the types of things that we might see in the future. So we can either prevent it in code, make it better, make it make it better down the line or document it in a way or just warn people about some of the dangers that they might hit. Right? It's, it's it's fun that you mentioned it, but at the same time, we've seen people do shit before.\u003C/p>\u003Cp>It's like, make a cron job that runs every second and put something in the table. Table blows up. Whose fault is that? Right? Did we did we have to do something to prevent that?\u003C/p>\u003Cp>Is that a user error? That who's who's responsible? Exactly. Featurex activity, see revisions. Working working on that, by the way.\u003C/p>\u003Cp>Unrelated for this call.\u003C/p>\u003Cp>Speaker 2: Don't tell. Don't tell. Hooray. Okay.\u003C/p>\u003Cp>Speaker 0: I don't want the sidetracked too much, but, yeah, we have the, retention settings for that coming, shipping fairly soon. Thank god. Yes, Amar. If you want to.\u003C/p>\u003Cp>Speaker 2: No. I\u003C/p>\u003Cp>Speaker 0: don't wanna get in trouble with HR. I don't think that's a good idea.\u003C/p>\u003Cp>Speaker 2: Goosebumps. Oh, no. Okay. So, just just keeping the time, in mind, we don't have that much time left. So maybe we should start to kinda converge now a little bit, You know, yeah, just to, get back on track a little bit.\u003C/p>\u003Cp>Oh, wow. And then the whole essay drops\u003C/p>\u003Cp>Speaker 0: from Yeah. There goes the next 10 minutes.\u003C/p>\u003Cp>Speaker 2: Oh, wow. Should we read that aloud? Are there bad words in it? Looks good. Okay.\u003C/p>\u003Cp>In my humble opinion, the whole edit complexity of environment migration I'm using directdis comes from the yaw application becoming data itself. Alright. While not using Directus, you can run different versions of the application side by side, and it's easy to switch version which version is running because the structure is defined within the application. Wildirectors, most of you. My guy, there there's not a single dot in that sentence.\u003C/p>\u003Cp>Oh my god. That's that's one sentence.\u003C/p>\u003Cp>Speaker 0: Don't throw too much shade. And it the the gist of it is because all the configuration is in the database instead of in code, therefore, you have migrations back and forth prompts. Right? And to Joshua's point, that is definitely a configuration as code discussion, which I think we had a couple episodes ago, actually, which is a great segue. Directs.i0/tv under request review.\u003C/p>\u003Cp>Highly recommend it. The the the 5 second summary of that discussion is really around there's multiple use cases. Right? There's a lot of people that prefer configuring everything from the UX and UI and then making an export. So by definition, it is in the database.\u003C/p>\u003Cp>Right? It's it's a mixed environment where there needs to be a two way binding into configuration. We don't wanna end up in a sort of again, the choices are different different use cases, different type of people. I'd I'd rather not end up with a sanity slash strappy type of environment where you have to pull things locally to code, you know, your settings and then redeploy it. That is just not quite the vision that we have for, you know, the ease of use and the user experience for this.\u003C/p>\u003Cp>Also, I know from some inside chatter that they're trying to get out of that as well. So this is this is a bit of a two way binding discussion.\u003C/p>\u003Cp>Speaker 2: Did you did you see They updated their comment and broke up the paragraph into multiple sentences now.\u003C/p>\u003Cp>Speaker 0: Danielle, look at what you've done. I think this is called cyberbullies. We don't condone that here.\u003C/p>\u003Cp>Speaker 2: Oh, no. Thank you for thank you for the, not not, what is it? Thank you for your cooperation, Wolfolas. Thanks for being here. Thanks for your message.\u003C/p>\u003Cp>We do appreciate it.\u003C/p>\u003Cp>Speaker 1: I'm not sure how you say it, but Wolf Wolf of us is an awesome contributor. He's been an incredible community member and contributor and helps out across everywhere across the platform. So\u003C/p>\u003Cp>Speaker 0: we are\u003C/p>\u003Cp>Speaker 2: It turns out.\u003C/p>\u003Cp>Speaker 0: Anyhoo, to your point then, converging it down to okay. What can we do? I think the the question that I do have is, do we wanna look into storing this as a nested JSON blob versus a separate table? Right? It would be a bit of a breaking change, but it simplifies both the output files and it simplifies the, the way to import it for us quite a bit.\u003C/p>\u003Cp>And it also solves that cannot resolve foreign key type thing bug in the same time. Right? The alternative is that we don't do that, but we avoid that breaking change in the operations endpoint with the downside that then for both export and import, we have to make sure that the whole nested tree is included at all times. And then during import, we do it in the correct insertion order. Right?\u003C/p>\u003Cp>Gut feeling wise, I'm kinda leaning towards let's blop it all as a nest of blob because it simplifies things. At the same time, couple downsides of that is that I think we'd lose the ability to choose what fields are returned from operations. I don't know if that matters as much if you're dealing with flows. Theoretically speaking, most of the databases now should support field selection for JSON. But seeing that we're talking about a theoretical infinitely deep object, that might be tricky.\u003C/p>\u003Cp>Right? Or we have to filter it down in in post after we got the data back.\u003C/p>\u003Cp>Speaker 2: Quick quick tangent. Can SQLite do that? I'm not sure. I don't think so. Right?\u003C/p>\u003Cp>Speaker 0: I think that update came earlier this year that they have some sort of SQL path, JSON path selection. Yeah.\u003C/p>\u003Cp>Speaker 2: They they've\u003C/p>\u003Cp>Speaker 1: got some JSON path.\u003C/p>\u003Cp>Speaker 0: Yeah. It's fairly recent. That's also one of the reasons why I missed we couldn't really do this earlier. Right?\u003C/p>\u003Cp>Speaker 2: Yeah. Oh, that's nice. Okay. Okay.\u003C/p>\u003Cp>Speaker 1: Yeah. So the lights are getting a lot of attention because you've got companies like Terso and others that are using this distributed edge file based databasing, caching kinds of things. So there's some there's a lot of work going on in that space and SQLite's gotten some pretty good attention.\u003C/p>\u003Cp>Speaker 0: But, I\u003C/p>\u003Cp>Speaker 1: mean, vendor variation, I think, as we move towards hopefully, as we move towards Duris, you know, whether or not that vendor supports it, then we can decide sourcing wise how we handle that. But for the main\u003C/p>\u003Cp>Speaker 2: I'm a big proponent of s Eskelet. Like, if if we if I do something, it it I wanted it for an SQLite, please. Okay. The end of this tangent. I'm sorry to I just I was curious.\u003C/p>\u003Cp>Yeah. Okay.\u003C/p>\u003Cp>Speaker 0: So so I think because, you know, the nested JSON stuff is something we haven't historically done because we couldn't really do that cross database vendor properly support it. It is something that probably comes with new issues that we don't know about yet. Right? So oh, yeah. Somebody actually mentioned it here too.\u003C/p>\u003Cp>It was like, Joshua again. Get a shout out, Josh. Stick with the current structure because making breaking breaking changes to the operation config will get to be a huge problem if using nested JSON objects. It's gonna be easier if you have a single row that changes. Just fair enough.\u003C/p>\u003Cp>And also see support for older databases and vendors that don't have JSON support. Also true.\u003C/p>\u003Cp>Speaker 2: Although,\u003C/p>\u003Cp>Speaker 0: I I wanna say that the ones that don't have an end of life I guess SQLite, the previous version, not yet, of course. Yeah. So and and, also, obviously, the big breaking change. People have been exporting, importing things through the APIs. The separate tools have been made.\u003C/p>\u003Cp>We saw that BCC schema sync shout out earlier. So we wanna make sure that that is not a huge freaking change either, right, where we just completely wreck any of those existing things. So sticking with the current structure probably makes the most sense. And then that raises the question around, you know, data integrity and import order, but that is a technical problem to solve that we just have to do during import. So that does mean that it'll probably be a separate way that we, do this than than compared to your usual export import just because order matters and that integrity matters.\u003C/p>\u003Cp>No. That's fine.\u003C/p>\u003Cp>Speaker 2: That should be really doable. You know? Walk the tree once and then just pop off from the back.\u003C/p>\u003Cp>Speaker 0: Yeah. And and the age old question, is this part of the schema export? Yes or no?\u003C/p>\u003Cp>Speaker 2: Oh, right. The the gonna\u003C/p>\u003Cp>Speaker 0: be a discussion for a different day, which is discussion we've had before around roles. And the yeah. But Joshua basically is concluding as well. We just need some schema export flags, which is, like, what do we include? What do we not include?\u003C/p>\u003Cp>This this this is the discussion we had exactly the same around roles. Do you wanna include roles and permissions? Probably. Do you wanna include users? Probably not.\u003C/p>\u003Cp>Do you wanna include permissions? Probably. Do you wanna include all of the permissions or just the ones that are about your production databases? Probably just the prod ones. How do you filter that down?\u003C/p>\u003Cp>This is the exact same stuff. Right? Is it all the flows? Is it some of the flows? How do you choose which of the flows are included and which ones aren't?\u003C/p>\u003Cp>Do we just export everything and then assume that somebody goes into the file and deletes them manually? Lots of more fun questions to be had in this. And for that, I wanna say, subscribe, like, and subscribe.\u003C/p>\u003Cp>Speaker 1: Nope. I think\u003C/p>\u003Cp>Speaker 2: Hit the bell. Hit the bell.\u003C/p>\u003Cp>Speaker 1: Always been.\u003C/p>\u003Cp>Speaker 0: Hit the bell and make sure you don't miss that episode when we go deep on that.\u003C/p>\u003Cp>Speaker 1: Now selective import export is gonna be needed for most of these things, I think. And ideally, whether export could export everything, but selective import on the import side, the ability to choose what I'm actually merging into the next iteration is is key.\u003C/p>\u003Cp>Speaker 2: Right.\u003C/p>\u003Cp>Speaker 0: Oh, that being said, I've not been muting. I'm muting. I'm muting. I'm muting. And I'm muting.\u003C/p>\u003Cp>The the doorbell is ringing, so I just wanted to make sure it didn't get too annoying. But that being said, we're at the top of the hour here. There's one more question that just came in. So another quick thought, what about pulling changes instead of pushing them in? Like, a sort of federation type of thing where you link data from multiple direct instances, you pull change from another instance.\u003C/p>\u003Cp>That sounds like a discussion for another day.\u003C/p>\u003Cp>Speaker 1: I think we've had that as part of the dual syncing as part of the configuration as code anyway. It is something that we we've we're we're thinking about, on that side of the house, and that's this is part of that as well. Right? So the configuration as code affects this, having utilities that make this easy now, versus, you know\u003C/p>\u003Cp>Speaker 0: Yeah. I I think that two way bind to me always has the file in between. So you push it from dev to file, and you pull it from prod from file. That is kind of the the the one to jump. Anyways, with that being said, thank you all for tuning in.\u003C/p>\u003Cp>Thank you all for the great questions and ideas in the chat. This episode will be available on Directus TV in the very near future. Shout out to shout out to Nat. Dan, did you make sure there's any any Zingers in here? Do we have the thumbnail?\u003C/p>\u003Cp>Speaker 2: Oh, that's not quite sure. May may maybe the the technically technically correct, maybe. I'm not sure.\u003C/p>\u003Cp>Speaker 0: There you go. That's that's the perfect one. That being said, check it out drex. Io/tv. We'll be doing this again in in the near future.\u003C/p>","Welcome to another episode of request review. What are we talking about today? We're talking about import and export options for flows. Oh. Now then if he says a like that, it sounds Why don't we just edit then? You know? It should be quick fix. Right? I think that's a great idea. Well, with that being said, thank you so much for watching. Find this episode on of course, I'm kidding. There's there's interesting, as per usual, these episodes, that's why we do them. Some fun edge cases here to consider. First and foremost, for those, you know, out of the loop flows, automation workflows, you can set up, you know, triggers. If somebody saves a thing, somebody hits an endpoint, somebody clicks a button in the app, do something. Right? And that something is a set of individual operations, different blocks, so to speak. You can connect together to make it do things. Now if you create multiple similar flows or you wanna move them to and from different installations, having some sort of way to import them and export them makes sense. Right? Just as a core set of functionality, absolutely. Somebody in the chat too. You know, flow and operation import is the number one thing that breaks when we sync our schemas and database across different projects. So why doesn't it not exist then, or why does it not work properly? That's a good question. I think, that was before my time. So you're probably better equipped to answer that question. There's there's a variety of things that happen here. Right? So schema differentials. Right? So if the scheme is different ahead of the flows being imported, if you're watching and monitoring things that don't exist in that import side, problematic, variables, referencing data and information that doesn't exist in one system to another. There's a flows are moving flows, I mean, the APIs are there. We do it all the time with our templating stuff, but we do that in a very controlled way where we're importing and handling the relationals. Because once again, now you've got relational data operations to the flows themselves and all of the data. What I've got a marketplace operation that's not installed in the next environment, there's, you know, there's a there's a great many things that have to be validated and checked, especially on import. Export, not so much, but on import, import gets Absolutely. Has to be And then another important part of those same edge cases there is what about options that need to be different installation to installation, but, you know, 90% of the rest of it is the same. So for example, a a super simple flow that I oftentimes use as an example is, you know, you make a change and you trigger a build on your CD platform, like a Netlify build or something. That production Netlify URL is different project to project because you're building different websites, but the flow configuration, the trigger, you know, the setup for making the request and all that is the same. Cool. So looking at this discussion here on GitHub, basic example, motivation. Now the motivation makes a lot of sense. That's just basically, you know, what we're what we're talking about here. I think there's no no discussion on, the usefulness here. When it comes to actual implementation, there's a question of, do we tie this to part of the schema snapshot and apply logic? Right? Do we really treat this as it's part of your project's configuration, and we wanna move that between different instances? Or do we treat this more as a kinda more traditional import export like we have for regular collections where you can just say, well, give me all of the operations, and we'll reimport them back in. To me, personally, it sounds more of the traditional way. Like, the correct way would be the traditional way because flows are not specifically schemas. Right? Like like, they're entries in the table, and that's not the schema, those would be items, and I think we should sync them separately. But yeah. And immediately, people start chat typing in the chat. I love it. So this is this is a fun discussion that that has come up in the past in in these request review sessions anyways, but we're we're yet to reach the the the silver bullet answer for what is schema or what is configuration. Right? Flows is to me is one of those points where I think 80% of it is configuration of your project. And if you wanna duplicate your project or if you wanna move that from dev to prod or you wanna, you know, use it as a template starting point for something else, you can make the argument that it's definitely part of the same thing that is just one unit of export for the whole configuration of your project. Right? So that's schema and and flows. Last time we were talking about it, you know, it was in the context of roles and permissions, which is a similar but different, you know, part of data, part not. But to to just Josh's point here in the chat, in the data model, you know, the flows are just data in the database. But for the perspective of that end user, they're all part of the application that you're, you know, configuring, right, which makes sense. And in that case, you can definitely make the argument, oh, it's just part of, you know, the the application model settings, schema export, and and apply. But that still raises the question, is it the blanket everything? How do you subset it? Because for the schema right now, it's it's everything. And how do you deal with options that are different? And how do you deal with active versus inactive? Do we deactivate them on import by default just to be safe. Because you could have a cron thing that could go haywire and talk to, you know, 3rd party production systems if you just spin it up in a new thing. Very valid points. And I and I do see the argument also from Joshua. It kinda it does make sense, right, if you interpret the flows as being part of your infrastructure, then they do kind of feel schemey. Scheme. I'm gonna use that. Scheme esque. Yeah. I I can see that argument. Okay. I'm kinda okay. Like in, in the beginning I was like, no, no, no, no. The data, they just stayed up. Those are rules. But now thinking about it, yeah. It's the rules. Damn. Interesting. Yeah. Kinda I'm kinda torn. I'm kinda in between. Like, it does it does make a hell of a lot of sense, but, they got a lot. It's funny because we we keep finding ourselves coming back to the age old question of what is and isn't, project configuration that should be sort of version controlled is kinda the the where that's going. Right? Where you wanna have a file that you version control and that includes a bunch of stuff versus within the data, so you differentiate between the 2. And this is this is kinda what earlier when I said, oh, if I make if I build flow, the whole flow but I want the URL that we're talking to to be different. So that URL should be in the same static file export. Then by definition, it needs to be in this static file. Right? Because otherwise, you have to do both. Is that easier to maintain? Is that worse? Right? But if you're treating it as I wanna have a template that I use to create new projects, but then manage the rest in the project itself, that would still work. If you're treating it as the file becomes the source of truth, now you have to make duplicates of the same, you know, config files to make it work for your different projects. Might be a good thing. Might not be a good thing. Did we did we actually, I think there's another small thing, related to this with, like, if if I just want to quickly export one specific one or, I had a not sure if this is, like, a slight tangent that we should go down on, but, when I played around with flows, I had the problem of, I created, like, 15 or 20 different ones, because I was, you know, trying it out and, they got automatically generated. And I had this little gripe with our way of displaying them because there was no, possibility to actually select multiple ones and delete multiple ones. And that kinda sounds to me like if we touch this, you know, with selecting them, exporting them, maybe, you know, filtering them so you only export a couple of them, it feels like selecting them would also fall or, like, lend itself to also be done with this issue. Right? But this is kinda a little different. Sorry. Just came to mind. No. Yeah. You're absolutely right, though. Yeah. Okay. So Joshua says, for a user story, we use tons of flows in production and development across 2 applications with the following workflow. We run the whole application locally, modify flows, code extensions. Okay. So far so good. Export the schema flows, collections, fields, etcetera etcetera, using a schema sync extension. Okay. So far so good. Commit the schema to version control and build images. Okay. In production, import the schema collections and flows as defined in the image. Alright. The result is that flows are always consistent between development and production, and the production flows are immutable. It makes sense. But this, I I guess this is to the point that I said earlier. Right? With then, you know, if you want to have, like, development flows production flows, then you have to duplicate them and both of them. Here we go the route in the chat as well saying, you know, what I usually do is try to keep the flows clean by saying, the only thing I export is the values everywhere. And then for the parts where you use different day the data model, there's a sort of settings collection, I imagine, for those flow operations. So you're actually fetching your needed stuff out of your database, and those fields would be different on your dev machine and the production environment. Correct? Right. Yeah. It's basically the way to have that sort of 90%, 10%, you know, split I described earlier solved by using a a settings collection for that, which which makes me think, is that something that could be a native thing where at the top of whatever the file export is for flows, there is a set of very tools you can define, reuse within the file. So you have a single file source of truth that then the app, once you're importing it, the requests, what values do you wanna use for these variables to get food for thought. Right? For for those new in this session, it's always about divergently thinking through all of the options, and all of the edge cases and then trying to converge back to, okay, what is something we can do today versus the long term plan? That would be a kinda cool in between, I think, where, you know, in the static file, we have to make sure it's human readable and easy to manage, of course, but you can have you can just describe at the top of the file. Here's a couple of variables that I wanna be installation installation, and then reuse those in your operation settings. The moment you you know, from within Directus where you're using those flows, we can show a a sort of mini form in options that says, okay. What what are those variable values? Okay. Okay. Then I think one other thing in, in close that has been there's there's a couple of I mean, I don't know if it's a bug, but it's kind of annoying to deal with is that right now flows make an operations to tables. And it works right. So if you're using the current APIs, you have an export for operations expect you have an export for flows. Flows are sort of it's it's a one to many type of thing. Right? You have more 1 or more operations per flow. A very normalized SQL data model for that, which in its, you know, theoretical purity is correct. But it does also definitely mean that sometimes if you're importing operations where the flows doesn't exist, you get foreign key constraint problems. Right? Because you're pointing it to a flow that doesn't exist. It also means that when you're exporting it, you end up with 2 different export flows, one for the operations. So that is a bit of an order of insertion interesting thing. It also means that every operation points to the next operation it needs to trigger. So that also means that operation insertion order matters, in that table. And, again, that all makes sense from a SQL database perspective, but definitely not, you know, the most user friendly way to do it. And that is just, you know, the the thing you learn over time in in terms of the data model. The question actually came up just now. I see it in the chat, Joshua. Out of curiosity, you know, why is that a separate table instead of a big JSON field? Concerns about size and speed, script operations. The, it's partially because JSON fields were just not as well supported or existed at all. And at that point, it did become a bit of a, you know, performance concern in some databases. Luckily, you know, I know 2024, that is that is a different, picture now or, you know, even SQLite has support for for JSF, JSON fields, which is fantastic. Concerns about speed has been sort of resolved because of that because now databases can store them, you know, efficiently instead of the large text blob. Size is a concern still a little bit, and that is a similar thing where before it was just a text field, you know, databases were fairly inefficient around storing, you know, unbound blobs of text that would have been JSON but that should also now be way more doable across the SQL vendors. So for what it's worth, I actually think that now, especially now with SQLite support and Oracle DB also being on the JSON train, this is now a new question, right? Should operation just be a nested object on a flow? To which the answer is probably yes, actually, because it's always a tight coupling. You're not really moving an operation from one flow to another And storing the actual flow as a nested tree of operations is more efficient, so we don't have to stitch together that tree from from the c port rows. That was just the thing we couldn't do yet, you know, when we when we shipped flows, but nowadays, for sure. Yeah. So that is that is also an interesting thing, which helps with exporting and importing and helps with the ease of authoring it as a file. Right? Because if we're saying that operations are represented as a nested tree, kinda like, for those who are familiar with it, like CICD pipelines in GitHub or or those tools, it's oftentimes just a YAML file that says it runs step, step, step, step. Right? So a flow could be a very similar syntax in that sense if we store it that way. Sounds reasonable. And it's only a tiny method for I can change. Okay. So we talked a little bit. How does it look like? How could it look like? Why would this feature be not as easy as you think? It's probably our standard go to. So I think in its purest form, just export everything from one flow and import everything from one flow, either through a duplicate button or a separate endpoint. That is not super tricky. The insertion order when you're doing the import is a bit of technical complexity on the implementer side. But from a user experience perspective, it shouldn't be the end of the world. I think the real questions that we have to prepare ourselves for are around what happens if you have a flow that does something destructive and like a cron. And the moment you import it, it starts wreaking havoc. Right? Do we import them as disabled by default? Is that what you want? If you're in an environment where your prod is just importing it and and otherwise, it's considered immutable, you want them to be active instead of inactive. Right? So how do we do with deal with that? And then around that variableness of you have the flow that's the same, but you have some of the settings that need to be different. Is that something that we have to bake in, or is that something that we say, well, sucks. That just doesn't exist, and you have to duplicate files. I think it's worth at least thinking through those questions even if the initial implementation is just going to be, you know, almost the exact same what was described here, which is just import flows, export flows. Bang. Right? According to Joshua, having a, destructive crone is just a skill issue. Fair enough. Problem problem fixed. One less problem to worry about. Alright. And, yeah, okay. So so the so the template ability, it it really does sound like a mustache template kinda thing. But, like, I'm I mean, we had a similar thing before, right, with, like, the script operation, for example, where it pulls in, like, your environment. So technically, the environment variables could be different. So you can actually have differing logic inside of them. Yeah. And we do allow you know, in every operation, we allow you to use a value out of a previous step. So using, you know, the the suggestion that we set as a settings table is is a very good alternative, I think. Honestly, it makes a lot of sense. It makes a lot of sense. But that is something that we have to just say, okay. If that is our recommended approach, then let's document it as such, because we know it is a I I I mean, of course, we haven't done the the full surveys and everything else, but I would assume that this is a fairly common use case where, you know, the the main use story here is you have a dev environment, you export it so you have a single source of truth that's version controlled, and then you use that to power your production instance. Right? So you use the UI and everything else to configure it, and then you use the code as your immutable source of truth for prod. That's that's sort of the the first user story. And I think the second one is really that you have the export as a templated starting point or templated source of truth for multiple projects that are all in prod. Right? So either it is a starting point where if you spin up a new, you know, templated, the, event website or something and they're all the same, so you wanna use the same kickoff point. You have multiple production instances that use the same config. Right? That I think those are basically the main to, use cases for for this. Mhmm. And I think in both cases, there's a case to be made for, you know, template ability or at least the the variable, settings, which, again, table. Table does sound pretty good. Pretty pretty reasonable. And similar to what you said, Rijk, earlier, or Jonathan rather, I think, the flows, according to Joshua, you know, if you import something, you could be referencing some tables that no longer exist. So how do we deal with that? Error messages, error pop ups, aborting, disabling the flow and just, you know I think there's also a good data modeling question to that to be honest. I think for operations right now those settings that hold a a field or a collection name, those are basically just a string. Right? And then we, one once the operation runs, it uses that string to try to read data from those tables and whatnot. I think the only solution here is that we treat those as a separate data type. So instead of saying it's a string, we say it has to be a collection reference. And therefore, the moment you do an export or import, Directus as a platform can recognize what those settings are supposed to be and validate if they are valid paths. Yes or no. Right? So I I think the the the longer term answer to this question would be to treat those as different data types where it's like, okay, collection reference, field reference. So therefore, we can validate it on import or export or both, and almost do like a if you ever see it in in Word or Pages when you open the document, somebody had a bunch of custom fonts and it shows, you know, cannot use cannot find these fonts. Choose what you wanna use instead. That would be kinda the only way I can imagine that to work. Yeah? Mhmm. I mean, if we, yeah, if we treat, you know, the, flows as part of your schema or your your infrastructure, your application, and if then an imported flow does not work because of, you know, like an an unreferenced or wrongly referenced thing in an operation, then technically we should reject that whole import because your entire application becomes inconsistent or can can could become inconsistent. So think, like, if we really consider it part of your application and your whole infrastructure, then we just have to reject everything if something goes wrong. Hans makes a good point here in, in the chat saying, you know, same with role IDs in the permission settings. Effectively, what we're talking about is foreign key constraints, but in JSON, right, where it's like you have a a blob of settings that is different and unique to an operation type because every operation is different and we don't have like a we don't have individual tables for each of the operation types or something where that'd be insane. But what we're talking about here is effectively, how do we do forward key constraints within an operation here? Right? And exactly everything comes back to cache invalidation, naming things, and validating and structure data formats. That's great. Yeah. But some sort of way, you know, in the operation value, if we can read it statically, that'd be great, you know, where you can look at an operation settings value and just be recognize what are supposed to be form keys. It could be some sort of unique value syntax, although that feels a little proprietary. It could be, you know, that the operation defines, a sort of JSON schema type of thing that we know what that unstructured data type is supposed to be so we can validate it. But, yeah, at the end of the day, what we're talking about is really much foreign key constraints for, operational layout settings and everything else. Yeah. Validation. Just to because I got curious, like, I'm, I think, just to getting back to the import order, like, please correct me if I'm wrong. So I think, if I remember correctly, the flow, references the first operation, and then each operation references the next operation. So the order of operate the the order of import would have to start with the first operate no. Because then you can't access you can't reference the second one. Oh, okay. So you have to do it backwards. Yeah. Yeah. Yeah. Yeah. Yeah. Exactly. Exactly. Exactly. I'm still the father to change. Go on. It's the other way, bro. Teacher, that's wrong. No. Right. I can see you have to step step through it once and then just pop off the stack and then go backwards. Okay. Which is also why, you know, I mentioned if we save it as a nested object tree as is and just treat it as one big blob, right, instead of a semi structured thing, that that simplifies export import, like, tremendously, really, because we don't have to do that. We don't have to care about, insertion order because it's all nested on the flow. So, therefore, you don't have those foreign keys pointing back and forth. And a resolve and a reject just becomes a nested object instead of, what you call it, reference to a different, thing in the flat list. Right? So that simplifies quite a bit, in in that sense. It's a bit of a break and change for tooling that exists against the operations endpoint, but it would make this a lot a lot less annoying. And I think it also solves one other bug. We we've had a bug in flows where people have run-in into where if you're editing a flow, and I think it's you disconnect operation, then you try to reconnect it somewhere else Right. You get that error that is, like, cannot 4 giga straight. Right? Because you're, Yep. You have to disconnect it. You're dealing with 4 giga from reconnect it in the order that you want. Yeah. It's a Yeah. Exactly. And that is because you're trying to change those foreign key and how they point to each other in a way that is database technically speaking. We have to answer that question for clients on probably almost It's it's a it's theoretically correct. It's also annoying as hell. Yeah. It's one of those Is neck beard correct? Actually actually, it is correct. It is. Pure. It's database pure. Suck it. Yeah. Oh, asks, are we talking about creating custom operations from the UI? No. We are actually talking about importing and exporting flows. So, for example, if you export your current schema and import your schema into your new environment, Should flows be included, how should how would that look like, etcetera etcetera. So the template CLI utility that Alex and Bryant and the team put together, we migrate everything including flows. But we have full control over everything. It it's exporting content and schema and everything else comes back in in the appropriate order. So your schema, your, you know, updates and things that need to exist before flows get created all happens as part of that kind of operation steps through the CLI. So configuration as code, kind of the general thoughts that we're working towards there will help with this generally, but I I was taking notes here. I saw some of the comments over here. If you're updating an existing flow, Well, if you're updating something in production, flow migration is now gonna have to be maintenance window for anybody doing that. Right? Because if you've got active flows, you've got crons, you've got other things that are going on, if you suddenly come in and hammer a flow that made changes, you're gonna cause issues. You can break, you can lose data, cause problems. Transactional processing and other things can be impacted with updating an existing flow. So because currently, you know, our practice with the CLI tool is we delete all the operations and recreate them in order to avoid any kind of, you know, what changed or didn't change just from a complexity standpoint. But those are things that we're gonna have to consider as well as when you're migrating a flow. Are you updating the existing flow, or are you gonna delete and recreate? Yeah. But, you know, from an operational standpoint, my my alerts go off from a security risk perspective of if I'm using Flows for invoice processing or I'm using Flows as part of a payment process, which we have clients doing, And we're suddenly gonna, you know, whack a flow and recreate it, or we're gonna update it in some way. What are the operational impacts and risks of doing that? And they've gone crazy in the chat again. To Hamza's point, that's kind of always a problem with with any sort of data migration. Right? If you import anything new into a production environment, you gotta make sure that you know what you're importing. That's that's the name of the game. That is also why, you know, the static file route in between is is what we're all talking about here. So that becomes your source of truth, and that is version controlled so you can see when it was updated by who. You can have some, you know, review processes in place to make sure that it has needs to have sign off, all that kind of stuff. But, yeah, it is technically always just a problem with any sort of data migration. If you have a settings table and import whatever on top of it, then it also breaks. Thinking about the settings table a little bit more, Are the settings always tied to a flow or is it more common to have settings that are global to your whole project and then happen to be reused in the flow? The reason why I'm saying that is in in a flow execution, we have that data object. Right? So that holds the all the data that's available in the operations and in the flow. One of the fields in there is that dollar sign trigger. That is just the information of the flow itself. Like, what caused it to trigger? I figured we could just have an additional flag in there for any sort of custom data that you wanna just have in that flow global, Right? That you can then reuse in those operations with the existing tools. So therefore, you can make a flow field, flow setting, Netlify URL and that just is becomes one of those data things that you can in in your request operation, you can use the parenthesis the the curly brackets, to reference back to your global flow data. Right? That could be a a sort of alternative to a settings table, but it would be unique to each individual flow. Yeah. Exactly what Joshua is saying right now. It's basically specific flow environment variables. Right? It would be, you know, environments in the, just that flow. And, yeah, you could theoretically already do that. You could use script operations or you could use the the JSON operation to just return, you know, some static data and then use that elsewhere. That's very true. Very true. But it could be a native thing. Then when you export and import it, you just have it as a sort of flow level thing, instead of as a separate operation. Oh, I mean yeah. There's definitely both, both options. Like, having a global thing, is very useful for general stuff, like, even general info between operations, like a brand name, a URL that you reuse in between different actions. But I can also see, you know, the usefulness of tying something specifically to one, thing just for one thing. Sounds pretty good. I guess the the the, the actual question is just, okay, how do you manage that in a good way? You know, like, how do we make it pretty? How do we make it a good UX? But I yeah. It it makes sense from, and One one I know Brian and Kevin will yell at me for if I don't bring it up. How do you save it encrypted? Like, some of those settings could very well be, you know, an API token or or things like that. Right? So how do you make sure that that stays secure as well? Yep. That's why I I I think traditionally, most people seen here end up creating a custom table, that's an admin accessible only table. It's not given any permissions for anybody else. You can then store hashed keys. You can store data and values that are masked, only accessible to the administrators kinds of things. But I, you know, I've run into this. I actually had this report just a, like, a default language as a filter right across a flow. I was doing a bunch of flow operations and they were nested translations, and I wanted to be able to just say, oh, I only want a specific language. And then I was and you can do things like it's it's simple enough to do a run script that just exports the value. So now you've got that variable in memory, right, in in the data data payloads. But Right. So That's that's where it gets that's oh, here comes another site engine. That's the fun thing about these episodes, man. I thought this is gonna be a 10 minute topic, and here we are 45 minutes in, and I just realized something new. When it comes to secret values like that, we have to store them encrypted, not hashed because we have to be able to decrypt them for use in the actual operation. Right? So when you make a request and you have to include some sort of token, it needs to be the original token, not the encrypted version. But to the chat's question here from Joshua again, you've been killing all of these questions. Thank you for them. You know, who's allowed to see the config? Right? Then, well, I'd say for the right UX at this, you can insert them once, and then that's it. Right? We don't show them again. But at the exact same time, you can then use a run script operation, return them, and then there they are. Right? So it's it's just a bit of a fake fake sense of security. They are encrypted into the database to make sure that that stays as secure as we can, so it will never be I mean, that's that's kinda this is kinda the crux of it. I it will never be exported as is, but at the same time, you know, does that matter? Even when you're doing it, it's not a closed closed. Right? Yeah. Yeah. Especially since flows are, at least at least right now, just, an admin exclusive thing. So we kinda you know, like, security schmecurity. You know? Like, if you're already an admin, you you have different problems. Like, if your attacker is already an admin, your flow keys are the least of your worries, basically. Yeah. Yes. No. Yes. No. Yes. No. Maybe. It's it's tricky in that sense. It's it's weird, though, when you think about it. And this is the same when you're talking from a platform team perspective, this is the same problem you're seeing on, you know, AWS secrets manager or d o environment variables or something like that. If you have an encrypted value and you save it, you then, you know, s h into your container, you do print f and there they are. Right? It's like they're stored as secure as possible, but then in your running process, you can just print the environment and everything is right there. But you gotta figure out what is what is the right move. Right? Because it can you have read only access to flows where they're hidden? But then if you have update access now, by definition, you have a way to expose them. Right? Is there a way is there a different security level where there should be the the sort of admins that have access to secure stuff and admins that can edit flows, but they're not the same thing? That that's a different question. Yeah. I mean, if if we go down, you know, the the settings table route, then we already profit from our, authentication, authorization, system. So, you know, you you can already then assign oh, exclusively these people are allowed to read them, look at them, and stuff like that. So You don't need to plan out every case ahead of time. Well, then you're you're in the wrong stream, my friend. This this is what we do. And again, this is this is the divergent part of all this. Right? This is luckily Yeah. A lot of these things are not blockers to at least get to the minimum viable, which is let us explore these damn things. But Right. These these are the things that people will, you know, use it for and maybe use it wrongly and then maybe expose themselves to massive headaches and issues down the line. So I do I do wanna at least be aware of the types of things that we might see in the future. So we can either prevent it in code, make it better, make it make it better down the line or document it in a way or just warn people about some of the dangers that they might hit. Right? It's, it's it's fun that you mentioned it, but at the same time, we've seen people do shit before. It's like, make a cron job that runs every second and put something in the table. Table blows up. Whose fault is that? Right? Did we did we have to do something to prevent that? Is that a user error? That who's who's responsible? Exactly. Featurex activity, see revisions. Working working on that, by the way. Unrelated for this call. Don't tell. Don't tell. Hooray. Okay. I don't want the sidetracked too much, but, yeah, we have the, retention settings for that coming, shipping fairly soon. Thank god. Yes, Amar. If you want to. No. I don't wanna get in trouble with HR. I don't think that's a good idea. Goosebumps. Oh, no. Okay. So, just just keeping the time, in mind, we don't have that much time left. So maybe we should start to kinda converge now a little bit, You know, yeah, just to, get back on track a little bit. Oh, wow. And then the whole essay drops from Yeah. There goes the next 10 minutes. Oh, wow. Should we read that aloud? Are there bad words in it? Looks good. Okay. In my humble opinion, the whole edit complexity of environment migration I'm using directdis comes from the yaw application becoming data itself. Alright. While not using Directus, you can run different versions of the application side by side, and it's easy to switch version which version is running because the structure is defined within the application. Wildirectors, most of you. My guy, there there's not a single dot in that sentence. Oh my god. That's that's one sentence. Don't throw too much shade. And it the the gist of it is because all the configuration is in the database instead of in code, therefore, you have migrations back and forth prompts. Right? And to Joshua's point, that is definitely a configuration as code discussion, which I think we had a couple episodes ago, actually, which is a great segue. Directs.i0/tv under request review. Highly recommend it. The the the 5 second summary of that discussion is really around there's multiple use cases. Right? There's a lot of people that prefer configuring everything from the UX and UI and then making an export. So by definition, it is in the database. Right? It's it's a mixed environment where there needs to be a two way binding into configuration. We don't wanna end up in a sort of again, the choices are different different use cases, different type of people. I'd I'd rather not end up with a sanity slash strappy type of environment where you have to pull things locally to code, you know, your settings and then redeploy it. That is just not quite the vision that we have for, you know, the ease of use and the user experience for this. Also, I know from some inside chatter that they're trying to get out of that as well. So this is this is a bit of a two way binding discussion. Did you did you see They updated their comment and broke up the paragraph into multiple sentences now. Danielle, look at what you've done. I think this is called cyberbullies. We don't condone that here. Oh, no. Thank you for thank you for the, not not, what is it? Thank you for your cooperation, Wolfolas. Thanks for being here. Thanks for your message. We do appreciate it. I'm not sure how you say it, but Wolf Wolf of us is an awesome contributor. He's been an incredible community member and contributor and helps out across everywhere across the platform. So we are It turns out. Anyhoo, to your point then, converging it down to okay. What can we do? I think the the question that I do have is, do we wanna look into storing this as a nested JSON blob versus a separate table? Right? It would be a bit of a breaking change, but it simplifies both the output files and it simplifies the, the way to import it for us quite a bit. And it also solves that cannot resolve foreign key type thing bug in the same time. Right? The alternative is that we don't do that, but we avoid that breaking change in the operations endpoint with the downside that then for both export and import, we have to make sure that the whole nested tree is included at all times. And then during import, we do it in the correct insertion order. Right? Gut feeling wise, I'm kinda leaning towards let's blop it all as a nest of blob because it simplifies things. At the same time, couple downsides of that is that I think we'd lose the ability to choose what fields are returned from operations. I don't know if that matters as much if you're dealing with flows. Theoretically speaking, most of the databases now should support field selection for JSON. But seeing that we're talking about a theoretical infinitely deep object, that might be tricky. Right? Or we have to filter it down in in post after we got the data back. Quick quick tangent. Can SQLite do that? I'm not sure. I don't think so. Right? I think that update came earlier this year that they have some sort of SQL path, JSON path selection. Yeah. They they've got some JSON path. Yeah. It's fairly recent. That's also one of the reasons why I missed we couldn't really do this earlier. Right? Yeah. Oh, that's nice. Okay. Okay. Yeah. So the lights are getting a lot of attention because you've got companies like Terso and others that are using this distributed edge file based databasing, caching kinds of things. So there's some there's a lot of work going on in that space and SQLite's gotten some pretty good attention. But, I mean, vendor variation, I think, as we move towards hopefully, as we move towards Duris, you know, whether or not that vendor supports it, then we can decide sourcing wise how we handle that. But for the main I'm a big proponent of s Eskelet. Like, if if we if I do something, it it I wanted it for an SQLite, please. Okay. The end of this tangent. I'm sorry to I just I was curious. Yeah. Okay. So so I think because, you know, the nested JSON stuff is something we haven't historically done because we couldn't really do that cross database vendor properly support it. It is something that probably comes with new issues that we don't know about yet. Right? So oh, yeah. Somebody actually mentioned it here too. It was like, Joshua again. Get a shout out, Josh. Stick with the current structure because making breaking breaking changes to the operation config will get to be a huge problem if using nested JSON objects. It's gonna be easier if you have a single row that changes. Just fair enough. And also see support for older databases and vendors that don't have JSON support. Also true. Although, I I wanna say that the ones that don't have an end of life I guess SQLite, the previous version, not yet, of course. Yeah. So and and, also, obviously, the big breaking change. People have been exporting, importing things through the APIs. The separate tools have been made. We saw that BCC schema sync shout out earlier. So we wanna make sure that that is not a huge freaking change either, right, where we just completely wreck any of those existing things. So sticking with the current structure probably makes the most sense. And then that raises the question around, you know, data integrity and import order, but that is a technical problem to solve that we just have to do during import. So that does mean that it'll probably be a separate way that we, do this than than compared to your usual export import just because order matters and that integrity matters. No. That's fine. That should be really doable. You know? Walk the tree once and then just pop off from the back. Yeah. And and the age old question, is this part of the schema export? Yes or no? Oh, right. The the gonna be a discussion for a different day, which is discussion we've had before around roles. And the yeah. But Joshua basically is concluding as well. We just need some schema export flags, which is, like, what do we include? What do we not include? This this this is the discussion we had exactly the same around roles. Do you wanna include roles and permissions? Probably. Do you wanna include users? Probably not. Do you wanna include permissions? Probably. Do you wanna include all of the permissions or just the ones that are about your production databases? Probably just the prod ones. How do you filter that down? This is the exact same stuff. Right? Is it all the flows? Is it some of the flows? How do you choose which of the flows are included and which ones aren't? Do we just export everything and then assume that somebody goes into the file and deletes them manually? Lots of more fun questions to be had in this. And for that, I wanna say, subscribe, like, and subscribe. Nope. I think Hit the bell. Hit the bell. Always been. Hit the bell and make sure you don't miss that episode when we go deep on that. Now selective import export is gonna be needed for most of these things, I think. And ideally, whether export could export everything, but selective import on the import side, the ability to choose what I'm actually merging into the next iteration is is key. Right. Oh, that being said, I've not been muting. I'm muting. I'm muting. I'm muting. And I'm muting. The the doorbell is ringing, so I just wanted to make sure it didn't get too annoying. But that being said, we're at the top of the hour here. There's one more question that just came in. So another quick thought, what about pulling changes instead of pushing them in? Like, a sort of federation type of thing where you link data from multiple direct instances, you pull change from another instance. That sounds like a discussion for another day. I think we've had that as part of the dual syncing as part of the configuration as code anyway. It is something that we we've we're we're thinking about, on that side of the house, and that's this is part of that as well. Right? So the configuration as code affects this, having utilities that make this easy now, versus, you know Yeah. I I think that two way bind to me always has the file in between. So you push it from dev to file, and you pull it from prod from file. That is kind of the the the one to jump. Anyways, with that being said, thank you all for tuning in. Thank you all for the great questions and ideas in the chat. This episode will be available on Directus TV in the very near future. Shout out to shout out to Nat. Dan, did you make sure there's any any Zingers in here? Do we have the thumbnail? Oh, that's not quite sure. May may maybe the the technically technically correct, maybe. I'm not sure. There you go. That's that's the perfect one. That being said, check it out drex. Io/tv. We'll be doing this again in in the near future.","c781a3e8-c119-41ef-a569-febf1970edb1",[377,378,379],"bb27ac7a-c413-4c5e-9fd0-0ea8bd9e86be","75add66e-c2ed-48da-a664-7a20c7da6a24","9d371e56-3e80-472c-abd3-22faf2a10c32",[],{"id":133,"number":134,"show":122,"year":135,"episodes":382},[137,138,139,140,141,142,143,144,145,146,147,148,149],{"id":147,"slug":384,"vimeo_id":385,"description":386,"tile":387,"length":324,"resources":388,"people":8,"episode_number":391,"published":392,"title":393,"video_transcript_html":394,"video_transcript_text":395,"content":8,"seo":396,"status":130,"episode_people":397,"recommendations":401,"season":402},"9161","1004131420","In this recording of our live event on August 29th 2024, Daniel, Jonathan, and Rijk discuss Additional Form/Field Layout Options.","fb2eeeee-6c4e-4227-adb1-9806fc50f2cf",[389],{"name":304,"url":390},"https://github.com/directus/directus/discussions/9161",11,"2024-08-29","Additional Form/Field Layout Options","\u003Cp>Speaker 0: We are covering additional form and field layout options. This is actually related to our item editing experience, and it is something that I would actually love to have. We're very we have some awesome capabilities right now, but the 2 field across kinda limitation, it would be nice to have some more flexibility there. So that's our discussion. This is discussion number 9161.\u003C/p>\u003Cp>I'll drop it in the chat in case anyone wants to follow along there.\u003C/p>\u003Cp>Speaker 1: Oh, 4 digits. You know, it's an old one when you're in the 4 digits.\u003C/p>\u003Cp>Speaker 0: Oh, yeah. This is an oldie. An oldie but a goodie. This was an October 26, 2021 Ben Haines special.\u003C/p>\u003Cp>Speaker 2: Oh, damn.\u003C/p>\u003Cp>Speaker 0: But it actually surprisingly, this was pre RFC, but Ben actually put in example screenshots, good description. It wasn't just a one liner. I I was actually very pleasantly surprised when I opened this up to review it.\u003C/p>\u003Cp>Speaker 1: Yeah. It's it's a good day when the feature request is not a one liner. It's Yes. It's great. Yeah.\u003C/p>\u003Cp>Speaker 0: So I will let you guys kick it off. Alright. Well, 4 pages.\u003C/p>\u003Cp>Speaker 2: Yeah. Right. So if I understand this correctly, we are talking about having a different layout for editing entries, which we currently do in 2 columns. You can divide your editing experience into a left column, right column, or go through with the whole input field? And wouldn't it be nice if we could do something else?\u003C/p>\u003Cp>I guess, it's the question. What could we have?\u003C/p>\u003Cp>Speaker 0: So yeah. That's the the general question is a little bit more flexibility, more feet you know, again, things like toggles. Right? Don't need even half width. They could be 25%.\u003C/p>\u003Cp>3rd. You know, maybe maybe a percentage based. Some of the more the more interesting feature styles, I think, that we can do today or that are possible. So Ben's got some different examples of what you might wanna have for layout options. Although this this was actually noted a little bit further down in this request that putting the label to the side is actually negatively impacting to users' experience.\u003C/p>\u003Cp>It's not not a recommended practice in general, but having some flexibility and being able to do some things. I think more so just being able to add more more configuration in the layout style, and and how things get positioned It's the general my my general client feedback, community feedback that I've heard, you know, in general with meetings and talking to people is just the ability to have more flexibility in the item editing design experience.\u003C/p>\u003Cp>Speaker 2: So quick question.\u003C/p>\u003Cp>Speaker 1: Yeah. I was gonna I I I think you're gonna go the same way as I'm gonna go, Daniel, but I'll let you go first.\u003C/p>\u003Cp>Speaker 2: Not sure. I'm I'm just, I just want to clarify a little bit because, because of the screenshot. So currently, I think we're only talking or a question. Are we only talking about the layout in and of itself? So just positioning of elements beside each other, or are we also talking about different visual styles for the same interfaces?\u003C/p>\u003Cp>Because, when you scroll down a little bit, for the checkboxes, for example, they look different than what we have currently. Is also part of this, idea that, for example, you can have multiple different, toggles? Let's say the this one this let's call it filled in toggle or a different toggle. What about the, like like, what is it checkboxes? Now the selects where you can only select 1, like radio buttons for example cause they are a couple of examples here right the product category for example.\u003C/p>\u003Cp>Because they look different. Like, are we currently just talking about the layout or are we also talking about different styles?\u003C/p>\u003Cp>Speaker 0: Let's look.\u003C/p>\u003Cp>Speaker 2: Okay. Oh,\u003C/p>\u003Cp>Speaker 0: no. He's got interface options to add well. So he's adding additional interface optioning capabilities as well. I thought, initially, I missed that. I thought it was just the item view formatting, you know, tab styles, other kinds of capabilities potentially.\u003C/p>\u003Cp>It's another frequent one that we see is instead of having just a full list of fields. Right? We have detailed things currently, but like a tab style interface there as a presentation layer. Could be other things we can consider. We can decide what we want this to be.\u003C/p>\u003Cp>We can narrow this. We can put this into RFC spec format, when we're done. So I'm happy to, well, you know, we'll do our let's do explode and then figure out\u003C/p>\u003Cp>Speaker 2: what we\u003C/p>\u003Cp>Speaker 0: want this to actually cover when we're done. So primary things that clients currently right? This is your current capability. Let me grab one that's got some, do I have one with groups? Remember if I've got something with field groups in it.\u003C/p>\u003Cp>Top of my, those products haven't.\u003C/p>\u003Cp>Speaker 1: Why?\u003C/p>\u003Cp>Speaker 2: You guys I think in in the end, when we when we scope down again, in the end, we can probably, like, make a make a rough, MVP of this feature where we just say, okay, maybe this is just it. But if you wanna take it further, then it would also include different, visuals for the same interface.\u003C/p>\u003Cp>Speaker 0: Yeah. So these are kind of your current options. Right? You can have field groupings. Right?\u003C/p>\u003Cp>And otherwise, you got it didn't half with. So to me yeah. I think we should start with with let's let's think about the I think I mean, options to existing interfaces could be discussed here. But I think in general, the way that this thing started and the way that I see this, the the biggest struggle that clients have today is you have very limited kinds of options actual form editing experience. How things can be laid out.\u003C/p>\u003Cp>Yeah. For sure. I think the other parts,\u003C/p>\u003Cp>Speaker 1: you know, a toggle instead of a checkbox, that's a new interface. That's just a custom interface or an option or stuff like that. But it doesn't really change the way the form itself is rendered. So I think for the sake of this discussion, we can focus on that. Cool.\u003C/p>\u003Cp>I think some of the bigger ones that we see here in the feature request is around where does the field label and description go. I think that is sort of one bucket. Does it go top? Does it go bottom? Does it go left?\u003C/p>\u003Cp>Does it go right? Then around how do certain groups come together? So there's like a sort of a new group UI, like a group of the title, and it's in a gray box instead of on a white background sort of visually, you know, cluster some of these form inputs, which then made some where the descriptions go. And then the other one is around, and it's not so much in the original screenshots, funnily enough, but it is I think of an important one here to bring up is what does the grit look like if you go beyond 2? Right?\u003C/p>\u003Cp>And and, where I can see this discussion going quickly is what about responsive? How does that work? And what about, on the screen that is about 6 meters wide, to make that work in a way that is still user friendly?\u003C/p>\u003Cp>Speaker 2: That is a good question. I this reminds me of a small little bug if we want to just take a little tangent for a story time. Because we have this little bug, where if you have a checkbox with multiple, options, we change the way how they are displayed depending on how many options you have. So if you only have 2, then they are right beside each other. But, for example, or if you have, like, I don't know, 5 or let's say 10, then we put them below each other.\u003C/p>\u003Cp>And we had this interesting fun little little bug is that we made this also dependent on the content of those checkboxes. So if you have long text, then we actually, you know, span the whole width so you can actually read the thing inside of the checkbox. But what this resulted in is that actually, in like languages which are very short and there are languages that which are very long, like in German words, you know, which means that you have different layouts depending on what kind of language you have. And then, there were a couple users that used Chinese characters, Mandarin characters. And this then resulted, like, if you translate it and then you got different layouts for different languages and stuff, that that was quite quite a fun thing.\u003C/p>\u003Cp>I think I fixed that, by the way. But, okay. Enough of that. Sorry. Yeah.\u003C/p>\u003Cp>Let's see. I mean, there's there's lots of perspectives. Right? Like, how many columns should that be dynamic? Do we want to provide a fixed fixed width as of right now?\u003C/p>\u003Cp>Like, 2. Let's just say, okay. You get 12. Is that good enough? And how do you configure the responsiveness?\u003C/p>\u003Cp>Then how do we have breakpoints? How many breakpoints do we have? 2, mobile, desktop, but not every screen is the same. How do you configure that? Do do we even want to configure that?\u003C/p>\u003Cp>Like, yes, but no. Meh. I mean, really, how much database work and actual data modeling are you interested in doing on mobile, to be honest? Like, how many people actually, editing the databases and data records on the phone? Like, how important is he's he's funny.\u003C/p>\u003Cp>The answer\u003C/p>\u003Cp>Speaker 1: is very important.\u003C/p>\u003Cp>Speaker 0: This guy does.\u003C/p>\u003Cp>Speaker 1: You'd you'd be surprised by how many people use mobile or mobile adjacent stuff now too. Right? If you have the folks with flip phones and you have people with with, you know, small iPads or, yeah. Yeah. Just going by the chat.\u003C/p>\u003Cp>People are saying the same thing too. Mobile interface, main point, which isn't direct is people editing videos on their phones. The people do everything on their phones nowadays, and I'm one of them too for what it's worth. So when it comes to grit and responsive, this is this is one of the reasons why, there's a lot of apps that are sort of, like, app builders, like a read tool, for example, that opt to make it a scrollable window when you go smaller for this exact reason so it doesn't have to do any sort of weird new reflowing. There is tools out there that I won't name by name that just straight up say there's no native there's no responsive design at all.\u003C/p>\u003Cp>There's no mobile version. There is different ways of of handling that. The way Directus does it right now is in the in the sort of 2 grid in the 2 up, the screen gets too small, becomes a one up. And that an easy easy enough sort of reflow to make. Right?\u003C/p>\u003Cp>Because whatever used to be side by side is now beneath each other, and that is good enough. Right? It it's it's what you'd sort of expect to happen, and it doesn't really cause anything too strange, from happening. If you're in a 6 column grid or so, like, if I'm scrolling down this feature request a little bit more, there were some screenshots from a tool called They have, like, a a sort of rich layout, which is roughly 4 columns. But then within, you know, one of the columns, there's another sort of 6 column y thing nested.\u003C/p>\u003Cp>And now I'm like, okay. Well, if you're responsibly squishing that down, weird things will happen. Like, what goes where? How does it flow? How does it grow?\u003C/p>\u003Cp>Do you expect, like, the 4th column to become, 3 columns of white when it goes to the next one? Do you intend it to still be blocked, but then you have 3 and 1 sort of weirdly underneath it? Or does it switch forward to a 2 grid? There's there's weird questions that happen at that point when you go down. And all so how does it interact with other fields that are then further down the page?\u003C/p>\u003Cp>Right? So right now, because every field is basically just in the same, same list of fields, It would start showing up side by side with other fields in that same grid, which could get funky and sort of unintentional. So one way around that potentially is to instead of doing a grid, let me do it now where it is based always one column, but there's a group type for creating grid sections in your form. Right? Because that way, it will always wrap within just that group.\u003C/p>\u003Cp>You don't your unintended interactions with other fields further down the page. And then that also means that you can start nesting those in whatever way you want. So if you're trying to re replicate that sort of 4 knocks set up where you have 4 columns, where the 4th column itself is like a a 6 column grid or something, you could because you can start nesting those those grid forms. Right? And it it kinda starts responsively matching the column size rather than the form size.\u003C/p>\u003Cp>Hannes in the chat says, additional groups feel cumbersome to set up. Yeah. Fair. Although at the same time, you know, to achieve the same thing that we have now, you could have one group and just put everything in it. Doesn't necessarily, you know is that is that what the price of admission get for, flexibility in the new layouts?\u003C/p>\u003Cp>And then on that same note, you know, the the some of the other layout settings, like, is the field name on the left or on the top, the description on the top or on the bottom, that kind of stuff could be settings of a group. Like, it doesn't have to be, settings of the whole form at once. Right? We could also say that the form, by definition, just has one root group, and therefore, it's always there, but it uses the same same system.\u003C/p>\u003Cp>Speaker 2: Alright. I can see that work in my hand. Like, is there a leaner way with less clicking? Currently trying to, like because if for me for me personally, the I I want I would want it to be as least intrusive as it can be because because I just wanna set up my thing and I wanna keep going. Right?\u003C/p>\u003Cp>Like I do not want to spend my time with designing, you know, layout. Like like this is like, I'm not sure how to say it. Like I I want to model stuff, I want to make like this this is how it how it works now. Like I just want to model stuff left, right, things and move on, you know. And I have other stuff to do.\u003C/p>\u003Cp>I have problems to solve as a administrator, let's say, of an instance, and I just wanna put some stuff in and keep going. So if you then have to jump through hoops and and, you know, like with all the, oh, but then on mobile, because I didn't, click on the full width. Now on mobile it is only half and it looks bad. And then I have to click this again and then the drawer opens again and I have to go into specific settings of a thing and then close the drawer again and choose the other. And that's that that feels icky.\u003C/p>\u003Cp>Like, I'm not sure if if we could design it in a way maybe with just small little toggles, like, without, specific options for those interfaces, when, like, the drawer opens, maybe we can make them just, small little toggles that you quickly go through just just without leaving the modeling page. Maybe maybe I don't know, like, it did did that make sense?\u003C/p>\u003Cp>Speaker 1: It does. It it's a, you know, it's a tricky thing because on the one hand, it's like if you wanna do it sort of quick and dirty, so to speak, then that's fine. That should be possible. At the same time, if you wanna make the best user experience for your end user so so let me back up a little bit. I think there's a difference in, flow when you're first setting it up and you're doing the data modeling versus when your data modeling is done and sort of finalized and you go into the details to make it a nicer user experience for your end user.\u003C/p>\u003Cp>At which point, you might set up, you know, I wanna use monospace for an input and add a little icon to make it, you know, friendlier for the end user, that kind of stuff. Right? I think that is also where this whole gridding stuff comes in. It's like, do you care about grids and how it responsibly shows up side by side instead of ordered top to bottom? Well, if you're doing the data modeling, possibly, probably not.\u003C/p>\u003Cp>It's just like you need to have the fields to check if it works, build the integration, move on. Right? Only then when your data modeling piece is done, can you circle back and be like, okay. Now I'm gonna spend an hour or so to just really make this form the best form it can possibly be for the use case that I have. I wanna conditionally show and hide some things.\u003C/p>\u003Cp>I wanna do it in certain sections have to be like a 4 up grid or a half half width group where, I wanna order it differently, etcetera, etcetera. Right? So I think there's 2 different points in time and 2 different, user flows that that are related. So to your point, I do agree. It's like for that first one, I mean, you're just setting up the data modeling, experimenting with what fields and what names and everything else.\u003C/p>\u003Cp>Quick and dirty. You don't wanna be slowed down by having to think about, is it 2 or 4 or 6 columns? Like, who cares? Just go quick. Right?\u003C/p>\u003Cp>Make it work. But I do think that is where we can introduce that additional flexibility that we're talking about as part of this this feature request to saying, well, if we hard code this form to be 4 columns instead of 2, we're gonna have the same discussion a month from now where it's like, okay. What about 6? Right?\u003C/p>\u003Cp>Speaker 2: Yeah. And we're\u003C/p>\u003Cp>Speaker 1: gonna have the same discussion a month from now where it's like, okay. Somebody wants 12. So by doing it as a group extension type where we say, okay. The group is just the thing that makes it x number of columns and we don't care. We allow that flexibility in a sort of opt in type of fashion rather than us having to predefine, okay, a direct this form is always x.\u003C/p>\u003Cp>Like, it is now. We say it's always to deal with it. Right?\u003C/p>\u003Cp>Speaker 2: Yeah. For for me, priority would be, just looking at at the screen right now, let's see, let's look at the theming group, right, or the SEO group also. I would like to avoid, or it would be it is near and dear to my heart, you know. Like, if I now want to split the theming group, I don't, like, I don't want to be the kind of back end where you have to click on the, 3 dots, then a dialogue or, like, a popover opens, then you have to click on edit fields, then the drawer opens, then you have to go inside of that, and then you have to configure some type of grid system and break points and stuff and then the whole thing closes and then, oops, I forgot one thing, I have to go through the entire thing again like this. Like I really want to avoid that.\u003C/p>\u003Cp>So I'm like, okay, And we maybe make sure that this doesn't happen. Maybe we can include some controls that are maybe enough already on the screen right now. So like, side the three points where the options would be, maybe there could be quick toggles where you can very quickly just with one click, like, boop, and then it's half view. And, you can configure it and then another click, boop, it's it's it's the mobile view. And then you can configure it again.\u003C/p>\u003Cp>Yeah. How about that?\u003C/p>\u003Cp>Speaker 1: So the reason why it has to be a drawer now is that those groups and interfaces themselves are an extension type. So, therefore, we don't know what those options are. Right? So if somebody makes a new custom grid group now, which you could theoretically, the options for that group is like a an open ended question mark. It's just a set of fields, and we don't know what they are.\u003C/p>\u003Cp>And we don't know how to, you know we we know how to render them because we ask you we ask the extensions, like, what options do you wanna render? And it's basically just another view component. Right? So it's like a black we just anything goes into that drawer and have have at it. So we can do that.\u003C/p>\u003Cp>We'll have to come up with some sort of standardized syntax for those plugins to say, here is the 2 or 3 things I wanna be able to edit in line that makes sense for this type of thing that I'm doing. Or we have to go the other way and say, well, we just built more of an Apple approach. That's who it where we say, well, the direct extensions are special and they get to do some of these inline things, but regular extensions are back to the old drawer style. You know what I mean? It's just that that flexibility angle because all of these are extensions.\u003C/p>\u003Cp>Speaker 2: Yeah. I get it. That's a bummer. Like, because we we strive and we always, our strength, right, is that everything is so super duper flexible that you can do anything yourself. Yeah.\u003C/p>\u003Cp>But for this, can we?\u003C/p>\u003Cp>Speaker 1: It's a question. Right? I I think when it comes to the drag and drop UI of of doing the layout of the form, if if you have a 4 grid, we have to show it as a 4 grid in line there as well in your editing experience. Like, that, I think, is is definitely something that we have to code in. But then if there's a group that has an option for number of grids, how does that how do we connect the dots?\u003C/p>\u003Cp>Right? How do we know that the grid column option in or an extension should be mapped to our editing experience for the form that makes it so that makes it work like that. Or again, maybe that there's the case that we say, well, you know, the way to handle grids is just not an extension type and there's no way for extensions to do that. It's just the native direct listing. Where we stay, okay, form layout, order, and grid, that is just a a direct as native thing.\u003C/p>\u003Cp>You can change it through extensions or anything else. You can still make a custom group, but the layouting options for that is not something that we can natively, manage on your behalf. Like, that that is also, you know, an option.\u003C/p>\u003Cp>Speaker 2: Mhmm. Yeah. Like, I I would be like, let let's let's just, you know, the, gut gut feeling is just this sounds reasonable because it's not actually concerning your data. It's just like our our, product UI. So it makes sense that we have this control of the layout.\u003C/p>\u003Cp>But I can already see, like, it's this is gonna be the first comment in that PR. It's like, oh, but I really would like to do this in my thing. Can we can we add that also? And then every time. Every content.\u003C/p>\u003Cp>Okay. Alright. So so this is the layout type of thing of that PR of that of that RC. I think it just okay. Let's you said in the beginning the other interfaces are mostly just other interfaces, so they aren't really concerned with this.\u003C/p>\u003Cp>Speaker 1: I think the difference between a checkbox and a toggle, that is an interface option or that is a new interface. I don't think that has anything to do necessarily with form rendering. So I think for the sake of this art for this discussion, we can just keep the scope to form rendering itself. I saw there there was some a couple of good points in the chat earlier right before we started with a couple of points around a little bit more general updates to forms and and interfaces, what we can do with it. 20 minutes ago, somebody was saying, it will be cool if you have, like, a 3, 4 column layout instead of just 2, expand the form width.\u003C/p>\u003Cp>So it's like the whole screen instead of just, you know, a a max width. But you could kinda do because there's, like, a full width option for an individual in the face or group, but it's I I do agree it's the whole form. It doesn't quite quite work like that. Aligning the form itself to the left or the center of the screen or maybe even the right. And then it gets into which I feel like a bit of a different feature request, but I wanna call it out because it's in all caps, so it sounds important.\u003C/p>\u003Cp>Actual relation drop downs, which I think is just make making sure that a second drop down is updated based on the value of the first drop down, which is, again, kind of not really\u003C/p>\u003Cp>Speaker 0: formed. I think it's actually I think it's actually more related to the relational interface itself right now. They always go to a drawer. I think it's more of the so like, a many to 1 or one to many.\u003C/p>\u003Cp>Speaker 1: Oh, that part of that nature drop down.\u003C/p>\u003Cp>Speaker 0: As opposed to a drawer pop. Yeah. That's an interface itself. That to me is again, I think we're kind of a little out of scope for this for what I think we want this review to cover in detail. Okay.\u003C/p>\u003Cp>Yes. There are there are dozens of things we would all like to have on the interfaces side of the house, but that's why custom extensions exist and you can't build them. So although, you know, this grouping style that we support, I have seen tab style, the group interfaces where someone has built a custom interface that actually does, like, tab styling and multiple fields and tabs and things inside their groups. So custom extensions support those kinds of things. Yes.\u003C/p>\u003Cp>Relational drop downs instead of drawers would be really nice in many use cases.\u003C/p>\u003Cp>Speaker 1: You know, it's, you know, it's funny. This is a complete sidebar, and I I wanna be cognizant that we don't end up spending 20 minutes on this because it's an easy one to slip into. But the many to 1 interface, the drop down one that opens drawer, it has the the actual drop down bits built in. It like, when we built it, it had that baked in. It's the problem was that similarly with most every other thing in direct is, like, week 2, somebody was like, I have a 100,000 items in the related\u003C/p>\u003Cp>Speaker 0: Yes. Related table and I I am now going to break your interface. Outright.\u003C/p>\u003Cp>Speaker 1: The drop down only shows the first a 100, so I cannot find the thing to select. And I'm like, yep. Yep. Yep. Yep.\u003C/p>\u003Cp>Yep.\u003C/p>\u003Cp>Speaker 0: Yep. So then\u003C/p>\u003Cp>Speaker 1: then we made the call to, like, always show it as a drawer, which works for everything, but it's it's not as nice as a little drop down. But it it used to work like that at one point in time. Yeah. Yep. Yep.\u003C/p>\u003Cp>Speaker 0: I know we've had bring that\u003C/p>\u003Cp>Speaker 1: back as a as an option to to but but the the funny thing there is, like, to do it the best way possible, we need to have an updated count of the number of related items at any point, and getting that count can be very slow if you have 100 of 1,000 of them. So we have to come up with some sort of way to cache the count our site first so we have a sort of estimate count that we can use and then update that over time because, otherwise, it's gonna be not performing enough to do you know? Anyways, long story short\u003C/p>\u003Cp>Speaker 0: Yes. Similar thing that so we did that for the actual layouts, as part of that performance improvement a year or so back, a year and a half back, where you started caching the accounts and not running the count every single time, only watching for changes or what. I'm not sure what happens behind the scenes in the caching aspects. But for those clients who had millions of rows of data and being able to present that and reflect that and not pulling\u003C/p>\u003Cp>Speaker 1: everything Something like that. Yeah.\u003C/p>\u003Cp>Speaker 0: On the counts. That's so The database running every single time you clicked was hugely performance impacting. So\u003C/p>\u003Cp>Speaker 1: Yeah. There's there's also some databases, and this is, of course, where the devil's in the details here. Some databases also have a difference between, an estimate count versus the actual count. So, like, in Postgres, there's a system table that keeps an estimate count that is not guaranteed to be accurate, but it's sort of a ballpark. So at least, you know, are we over under on 1,000, or is it just, you know, a couple?\u003C/p>\u003Cp>Yeah. So there's also a world this is again a big sidebar, but such goes in these episodes. There's also a world where we first get the estimate count, which is cheap. And then if that estimate count is less than a couple thousand, then we meet the actual account. So we can show that.\u003C/p>\u003Cp>Nice. Anyways, that is a whole different\u003C/p>\u003Cp>Speaker 0: That is a very different ballgame and Oh, okay. Another discussion.\u003C/p>\u003Cp>Speaker 2: Mhmm. Mhmm. That that's a fun one. Okay. How many items do I have?\u003C/p>\u003Cp>And you asked the database and it's saying, probably 10,000 maybe? Best I can do.\u003C/p>\u003Cp>Speaker 1: Yeah. It's it's an interesting problem though because it's one of those things where in order to know that, it's it's, what is that in COMS size? Is that one of those o n problems or an o two problem? Where you know what I mean. Right?\u003C/p>\u003Cp>Where it's like, the more items you have, the slower it gets linearly to count the number of items. So, therefore, if you have a table with with 20,000,000 rows in it, how do you know it's 20,000,000 rows efficiently? That's weird. Yeah. Oh, and, yeah, that's that's what I thought.\u003C/p>\u003Cp>It's it's clear that if not comp side. I'm still just a UX designer, guys. Take it easy. Cool. Some of some of the other stuff in the chat here before I I miss it again.\u003C/p>\u003Cp>So it says, I wanna speak with a person with a 100,000 items. I need a quick chat.\u003C/p>\u003Cp>Speaker 0: Oh, for\u003C/p>\u003Cp>Speaker 1: what it's worth, we, we even do a similar thing ourselves where we have, you know, we keep, error logs for, you know, certain cloud deployments. Those error logs have a one to many back to the project, so we can see the most recent 10 per project. Right? But that also means that the whole error logs table can be in the millions. So that one to many needs to be prepared for, you know, what that looks like if you said select existing, and now all of a sudden you have a list of 10,000,000.\u003C/p>\u003Cp>Like, how does that work? Right? It it's it's a very real thing that people do, ourselves included, which makes some of these discussions a lot more fun if you're thinking about it many to one. I am making the drop down nice and easy. Nope.\u003C/p>\u003Cp>Yep. Cool. And then on this another one says here, it feels like we could add a special component that can be defined for group interfaces where they decide on the layout for field layout. Right. Yeah.\u003C/p>\u003Cp>So this is similar. This is going back to the, how do we do inline options for groups? Right? So honest suggestion here is basically saying, well, maybe just like inner like options for interfaces, there's a way to say, let the actual form extension itself decide how to render on the settings page so we can make that optimized, which is, yep, interesting. Something along those lines.\u003C/p>\u003Cp>There's something about a half width group. That's fine. Otherwise, do it with 2 columns. I think we touched on the other stuff. Right?\u003C/p>\u003Cp>Cool. Then the second thing is around in this feature request rather, is around, where does the label go in a form? And is it something that you should be changing? Or is that something that is just not something you should care about? It's an interesting one.\u003C/p>\u003Cp>Kava is it it gets to a bit of a user experience question. Right? And and this is, again, a topic that can easily get off the reels in terms of theming and customization and how far do we wanna take it in the sense of, you know, if you give the end user infinite flexibility in this kind of stuff, you also give them infinite food guns to make it trash, right, for the for the end user. So there's a there's a very real discussion around, you know, is form labels left aligned input, right aligned? Is that good for good?\u003C/p>\u003Cp>There be opinions. Is that good for the end user or not? Right? And then the question becomes, who should be in charge of making that call? Because we make a lot of calls because it's a studio.\u003C/p>\u003Cp>Right? And it's the same, yeah. Yeah. Hans says the same now. It's a layout too.\u003C/p>\u003Cp>Once you have weird layout problems, you get a similar similar, UX problem. Right? But the question becomes, who's responsible? Right? Do we say well, because we built the studio, we have good defaults.\u003C/p>\u003Cp>We wanna make sure that everybody has a good user experience. That's what we pride ourselves on. Therefore, are we gonna limit some of these things? Or are we gonna say, go nuts, and it's your problem, which is great for some and a problem for others. Right?\u003C/p>\u003Cp>And we've seen this before. We've seen this in the past. Like, when we ship theming, which I think has been been pretty pretty good to have, generally speaking. It opens some of those questions too. Right?\u003C/p>\u003Cp>Because I I know, my very own Kevin made a, like a teenage mutant Ninja Turtles one, or or what do we call it? Something non something not trademark related, as as a sort of experiment to see where how far you can take it, but it's also objectively horrendous. It's objectively bad, right, for for user experience wise. But who who's who's responsible then? Right?\u003C/p>\u003Cp>And and where do you draw that line? I think it's an interesting question here too because, like, if we make a if we kept just if you make a 12 column grid, you can do some very powerful, easy to use layouts. You can also easily make a garbage nightmare. Just like you can make a dumpster fire. Who's then responsible for the dumpster fire part of that?\u003C/p>\u003Cp>Speaker 2: Yeah. Because the yeah. Like you said, this is an actual thing. Like, if somebody badly configures their instance, it may reflect even bad on us because, like, the users come in and say, like, oh, what what what oh, brother. Oh.\u003C/p>\u003Cp>What what happened here? You know? Like, Directus is ugly. Directus doesn't work. Oh, this is not good.\u003C/p>\u003Cp>And then it reflects bad on us. So actually, we should think about that we make I mean, you know, flexibility is nice. It is it is cool, and it is one very, very good point for us. But to what extent? Like you said, okay.\u003C/p>\u003Cp>So we we do have to so\u003C/p>\u003Cp>Speaker 1: quickly and I love it.\u003C/p>\u003Cp>Speaker 2: We do have to draw a line somewhere.\u003C/p>\u003Cp>Speaker 1: There there's an interesting part of the tech industry that people have been yelling about for decades now, which is the whole Android versus iOS thing. Right? Or Linux versus Mac OS thing, which is, like, for the longest time on iOS, you cannot you can you can reorder your app icons, and that's about as much customization as you get. Right? For the first couple of iOS, if the background was black, shut up.\u003C/p>\u003Cp>Your wallpaper on the lock screen was the was the globe. No options. Right? And then they were like, oh, maybe maybe you can have maybe you can have a wallpaper, and then you could have some fish instead of a globe, and then that was it. Right?\u003C/p>\u003Cp>But then, you know, people on on the Android side of the house have been screaming for decades. Like, oh, my wallpaper moves this fantastic life great. But, also, you can make an absolute dumpster fire of of your phone, which is whose problem is that? Right? Is that is that you're gonna make it better for the power users, but you also give a bunch of food guns to everybody else?\u003C/p>\u003Cp>And for what it's worth, Apple is now doing the same thing, I think, right, with this new iOS 18 where you can, like, tint your app callers or something, and it looks horrendously bad just just objectively. Of course, it's an opinion, but I'm right. It's objectively bad. Where because you just see the icon from, like, I don't know, Notion or something turned bright yellow because you you tinted it that way. It's just not good.\u003C/p>\u003Cp>It's just not work. But the question is, like, you you can make it good with a bit of effort, but people don't will not. Is that is that a problem? Like, is that\u003C/p>\u003Cp>Speaker 2: It it the older I get, the more I think, yes. That's a problem.\u003C/p>\u003Cp>Speaker 1: Because the So you're gonna look at an iPhone now, and you're like, man, that is ugly. It's so good and hard to use, and I don't care. But at the same time, the the people that set it up that way for themselves, they might love it. It might be their preferred Yep. You know, becomes an opinion thing.\u003C/p>\u003Cp>Right? But it's like, how do you decide where to draw a line?\u003C/p>\u003Cp>Speaker 2: Yeah. Quick. Because there was the the quote from, I think Henry Ford, was it? Like, with the car, like, you can have, the Ford in any color that you'd like as long as the color is black. Black.\u003C/p>\u003Cp>Yeah. Right? Yeah. The same for iOS. You can you can do anything you like, but as long as it's not what you like.\u003C/p>\u003Cp>Yeah.\u003C/p>\u003Cp>Speaker 0: As long as you like what we like.\u003C/p>\u003Cp>Speaker 2: Right? Exactly. Yeah. So, like, I I think I personally I mean, of course, this is just, you know, opinion piece. Careful.\u003C/p>\u003Cp>It's I think we should be for the live stream, and I posted a picture of, Tim did Ios screens. It it is something.\u003C/p>\u003Cp>Speaker 1: And these are the ones done well, mind you. Anyways yeah. So so for for the listener, it's basically, you know, 5 different iOS screenshots with, like, different color background, and then all of the front, front end, all of the the icon colors, is is the same color as the background. So, therefore, at a glance, everything looks the exact same. It's just that's that's the main issue for me.\u003C/p>\u003Cp>It's like, I don't know what app is what app anymore because they all look identical to me now. Google oh, man. This is such a sidebar again. But Google did the same thing. Right?\u003C/p>\u003Cp>When they went through the whole material design thing, now every single Google app looks the exact same. If I log in to our Google Workspace and I click on apps, I just see the exact same icon, like, 200 times, and they are all the same. It's there's a small variation in shape, and I just don't know it. Anyways, yeah, it is let's try to get that back on track. It it is an interesting discussion in general, though, for of, like, how far do you let people take it?\u003C/p>\u003Cp>And and is it a good thing, or is it a bad thing? And where do you draw the line? I think in this case, as long as we have good defaults, I wanna on the side of let them have the flexibility, but make sure that by default, for the people that don't spend the time setting it up, it looks good and it works well. Right? Mhmm.\u003C/p>\u003Cp>I think that's kinda where your earlier suggestion comes in for, like, if I just wanna go in at a con at a bunch of fields and not think about it, we need to make sure that things work out the right way at that point. It's like, what makes sense? Help the user as much as possible to have a good default. And then if you wanna go in and be like, well, I want my address field right aligned next to an email and the name field, and then the address needs to be split up between, like, street and and number, and then all this kind of more detailed stuff, they can come back in and start using grids and and nested groups and all that kind of stuff to do it. But by default, you know, we'll we'll make it as good as we can.\u003C/p>\u003Cp>Speaker 0: Yep. And it's\u003C/p>\u003Cp>Speaker 1: a very hands off approach. It's like you break it, you fix it.\u003C/p>\u003Cp>Speaker 0: My my final question before we kinda diverge back, any compliance or standards we need to consider here? WCAG,\u003C/p>\u003Cp>Speaker 1: accessible I\u003C/p>\u003Cp>Speaker 2: don't think so right now.\u003C/p>\u003Cp>Speaker 1: Always. I mean, I assume that the the the, it's funny you mentioned it because, I mean, yes and no. It's it's another question of who's responsible. Like, if if our defaults should always, yes, I think, we should always provide the tooling to make it as accessible as possible and to easy as use as possible. But at the same time, if you wanna go in and remove all of the field labels and align it in a way that turns it into a piece of art, is that allowed?\u003C/p>\u003Cp>It is. That's part of\u003C/p>\u003Cp>Speaker 0: that question. I'm more considering I think right now, we do have some issues in the space, and I don't know if it is if it's part of this that would fix that or be part of you know, if we're gonna touch some of this stuff anyway, like, tabbing. Right? Being able to tab through your item fields and, you know, be able to quickly navigate to things. Some of that doesn't work very well right now in the data studio.\u003C/p>\u003Cp>Speaker 1: Yeah. Yeah.\u003C/p>\u003Cp>Speaker 0: Or at all. Right. And so just some, I just, I, because I've been doing so much standard and security.\u003C/p>\u003Cp>Speaker 1: It it it's a very good point, though. It's it is very true. It's like if you have, you know, a a if if you went nuts, so you have a super rich grid and everything sort of aligns funky, funkily. What is the tab order, and does that make sense? And is that something that somebody needs to be able to configure?\u003C/p>\u003Cp>Do you tab in and out of groups? Do you tab in and out of individual fields? How do you make sure that the tabbing order is visually consistent with what's about to happen? It's a difficult question for sure. For sure.\u003C/p>\u003Cp>And it and it goes right back to the who's responsible. Right? Who's responsible for all of this at that point? This this could even very quickly turn political in the sense of, is it the tool builder who's at fault, or is it the tool wielder who's at fault? No.\u003C/p>\u003Cp>No. No. No. No. No.\u003C/p>\u003Cp>I think I think some good guardrails today, but, you know, let's,\u003C/p>\u003Cp>Speaker 0: let me let me try\u003C/p>\u003Cp>Speaker 1: to summarize this discussion as the only the only thing stopping a bad guy with a form is a good guy with a form. If we get it, who's responsible?\u003C/p>\u003Cp>Speaker 2: I think I\u003C/p>\u003Cp>Speaker 0: think good guardrails, with some flexibility inside the rails. Right? And I think it's Yeah. It's always worked out well for us in general. I'm okay with some level of right to to some degree.\u003C/p>\u003Cp>Right? I think what we're trying to do here is improve the current experience.\u003C/p>\u003Cp>Speaker 1: Yeah.\u003C/p>\u003Cp>Speaker 0: We don't have to give ultimate any flexibility. Right? It is our data. You you wanna do that? Build your own, you know, use the APIs, build whatever you want.\u003C/p>\u003Cp>Right?\u003C/p>\u003Cp>Speaker 1: You have you have that\u003C/p>\u003Cp>Speaker 0: flexibility today. You can build an interface in front of this or a\u003C/p>\u003Cp>Speaker 1: Sure. You can build your own direct just for like\u003C/p>\u003Cp>Speaker 2: oh, yeah. Yeah.\u003C/p>\u003Cp>Speaker 0: Yeah. And, you know, to some degree, right, web design and things that people are building, some of the applications and tooling that people will build on top of the directors APIs. They have this flex they have the ultimate flexibility to build whatever they want. You wanna use the data studio. Again, we have a reputation.\u003C/p>\u003Cp>We have our own. And and I think good guardrails, good guidelines, and, you know, just configuration options. I think there's some of that as just adding some additional configuration parameters to allow for you know, we do wanna follow good accessibility practice. In order to do that, there has to be some options for that. And we can put some default, or we can just say these are the defaults.\u003C/p>\u003Cp>Right? The the defaults are what they are. Just making it so that it actually works and meets the guidelines at a minimum. I like it. Cool.\u003C/p>\u003Cp>Alright. We've got, 8 minutes, 7 minutes. How do we wanna start wrapping up, gents?\u003C/p>\u003Cp>Speaker 1: I think I\u003C/p>\u003Cp>Speaker 2: mean, it's just okay. Go for it. Go for it.\u003C/p>\u003Cp>Speaker 1: I was gonna say circling back to the initial thing of is a grid a system thing or is it more of a group type setup? I think I'm kinda leaning towards even though it is a bit more setup, doing it the group style way. Because that way, you can start nesting things. You can start configuring it to your heart's content. You can mix and match.\u003C/p>\u003Cp>You can have a section that is a 4. You can have a section that's a 6 upwards, 2, or 1, and mix and match on the page. I think making that a sort of nestable thing feels like the right move. We can still say that the form itself by default is one of those units, right, for ease of setup. So if you just want the whole field the whole form to be a 2 up, then you're done by default.\u003C/p>\u003Cp>Absolutely. But making that a sort of thing you can nest as a section feels like a powerful thing to have. Because that's what's gonna allow for one of these things where you have a 4 up, but then in the 4th column, you have a thing that also has field side by side, right, to make that as flexible as you want. I think when it comes to form label, that feels like a very system y type of thing. Like, we render a form with or without those groups with with grids, and then maybe on the form level, maybe on the the grid group form, whatever you wanna call it level, or maybe both, you can just set, okay, left line top of line, label and we can be a bit more flexible in that.\u003C/p>\u003Cp>And the same goes for the description. Right? Show at the bottom, show at the top. Those could be be just a toggle for for the form in in general. The new styles for check boxes, those types of things, the the the making them into 1 drop down and actual drop down.\u003C/p>\u003Cp>I think that is interface options. That's just separate from from this discussion to me. And then last but not least, there's 2 things coming in from our favorite team, which is our own. Sounds like we're in the last 8 minutes. Should different interface styles be just styles in existing interfaces or new extensions or interfaces?\u003C/p>\u003Cp>Opinions. Opinions. Opinions. I think it has all to do with the user experience. So to me, a checkbox and a toggle are effectively the same thing from a user experience perspective because you clicked enable, you clicked to disable.\u003C/p>\u003Cp>They're the same. Right? So to me, a toggle is just a different visual representation of the same underlying thing. This is the pain. Don't hate me too hard.\u003C/p>\u003Cp>It's a it's a different visual style for the same thing. When it comes to and and, funnily enough, we are not always good about doing it this way either. Right? So, for example, we have a drop down single select and a drop down multi select. In our components in code, it's the same component.\u003C/p>\u003Cp>A bit hard to maintain, arguably. Shouldn't have done that. We'll probably refect it at some point. Mhmm. Because the user experience is different.\u003C/p>\u003Cp>Right? Because one is, like, you're you're rendering a list of things. You're checking off multiple. You render it. Now when it comes to a multi select as a list of checkboxes versus a drop down that then shows the list of checkboxes, that is again a different visual style for the same interaction.\u003C/p>\u003Cp>Right? But where do you draw the line? Because in that example, you could say, well, they're visually so incredibly different. And for the end user, they might expect them to be do 2 different things. So where do you draw that line?\u003C/p>\u003Cp>I think it's just an opinion in a case by case. Right? It's like in this case, I would say a list of checkboxes or a drop down where you can select multiple things. Those are so different from, like, a mindset perspective that we should make it 2 different interfaces even though they do the exact same thing. You choose you pick and choose 1 or more things from a list, and that's what you're doing.\u003C/p>\u003Cp>Speaker 2: Yeah. Especially if you have 2 different styles, like you said, right, with with the drop down or they could have different options, and then we would have to respect those also in the in the drawer, for example, depending, you know, on what you have. But this has to be configurable then also for extensions. And that also sounds like okay. Just make a new interface.\u003C/p>\u003Cp>It everything is in order. It is just like that. Deal with it.\u003C/p>\u003Cp>Speaker 0: Yeah. Go with it.\u003C/p>\u003Cp>Speaker 2: It sounds very\u003C/p>\u003Cp>Speaker 1: There's there's 2 more fun ones for the last 2 minutes here. Tim asked, make it difficult nearing the end, will it be able to configure conditions across groups and sections? I think the answer is yes. I think conditions for an individual field or group should always be able to listen to anything else on the form, just whatever nesting level you're in. Of course, there's the same responsibility things.\u003C/p>\u003Cp>Like, if you listen to something that is visually completely disconnected and related, you can make it very difficult to use for your end users. But from a technical angle, I think we should make it possible. And then the last question here now is saying, what about applying conditions on hiding or disabling fields in the relation drawer based on the state of the form? And for that, I'd like to say tune back in 2 weeks from now. That that is a bit of a different discussion around how that drawer works.\u003C/p>\u003Cp>The the relation drawer right now, you know, it renders the same layout that you use for that collection, in the main sort of layout for that collection. So, therefore, the fields that show up are are the same that you see on the layout page for that collection. It also means it's a bit tricky to dynamically change that because it is matching the other one, but that is a different moving level. It should be possible with custom CSS and a group extension. Yep.\u003C/p>\u003Cp>Yep. Yep. Yep.\u003C/p>\u003Cp>Speaker 0: So many ideas.\u003C/p>\u003Cp>Speaker 1: Anyways, with that, we're at the top of the hour. I wanna thank you all very much for tuning in once again. We'll be back at some point in the near future.\u003C/p>\u003Cp>Speaker 0: I think\u003C/p>\u003Cp>Speaker 1: we're in another one in 2 weeks from now. Make sure to find this on direct to zio slash tv. Any other closing thoughts? Dan, John?\u003C/p>\u003Cp>Speaker 2: I figured it out.\u003C/p>\u003Cp>Speaker 0: Thanks to the community and all the good feedback on these on these issues. I'll post comments here shortly and then, Greg, if we need to do a full RFC on this one, we can work it out.\u003C/p>\u003Cp>Speaker 1: Sounds good.\u003C/p>\u003Cp>Speaker 0: Alright, team. Have a wonderful rest of your day.\u003C/p>","We are covering additional form and field layout options. This is actually related to our item editing experience, and it is something that I would actually love to have. We're very we have some awesome capabilities right now, but the 2 field across kinda limitation, it would be nice to have some more flexibility there. So that's our discussion. This is discussion number 9161. I'll drop it in the chat in case anyone wants to follow along there. Oh, 4 digits. You know, it's an old one when you're in the 4 digits. Oh, yeah. This is an oldie. An oldie but a goodie. This was an October 26, 2021 Ben Haines special. Oh, damn. But it actually surprisingly, this was pre RFC, but Ben actually put in example screenshots, good description. It wasn't just a one liner. I I was actually very pleasantly surprised when I opened this up to review it. Yeah. It's it's a good day when the feature request is not a one liner. It's Yes. It's great. Yeah. So I will let you guys kick it off. Alright. Well, 4 pages. Yeah. Right. So if I understand this correctly, we are talking about having a different layout for editing entries, which we currently do in 2 columns. You can divide your editing experience into a left column, right column, or go through with the whole input field? And wouldn't it be nice if we could do something else? I guess, it's the question. What could we have? So yeah. That's the the general question is a little bit more flexibility, more feet you know, again, things like toggles. Right? Don't need even half width. They could be 25%. 3rd. You know, maybe maybe a percentage based. Some of the more the more interesting feature styles, I think, that we can do today or that are possible. So Ben's got some different examples of what you might wanna have for layout options. Although this this was actually noted a little bit further down in this request that putting the label to the side is actually negatively impacting to users' experience. It's not not a recommended practice in general, but having some flexibility and being able to do some things. I think more so just being able to add more more configuration in the layout style, and and how things get positioned It's the general my my general client feedback, community feedback that I've heard, you know, in general with meetings and talking to people is just the ability to have more flexibility in the item editing design experience. So quick question. Yeah. I was gonna I I I think you're gonna go the same way as I'm gonna go, Daniel, but I'll let you go first. Not sure. I'm I'm just, I just want to clarify a little bit because, because of the screenshot. So currently, I think we're only talking or a question. Are we only talking about the layout in and of itself? So just positioning of elements beside each other, or are we also talking about different visual styles for the same interfaces? Because, when you scroll down a little bit, for the checkboxes, for example, they look different than what we have currently. Is also part of this, idea that, for example, you can have multiple different, toggles? Let's say the this one this let's call it filled in toggle or a different toggle. What about the, like like, what is it checkboxes? Now the selects where you can only select 1, like radio buttons for example cause they are a couple of examples here right the product category for example. Because they look different. Like, are we currently just talking about the layout or are we also talking about different styles? Let's look. Okay. Oh, no. He's got interface options to add well. So he's adding additional interface optioning capabilities as well. I thought, initially, I missed that. I thought it was just the item view formatting, you know, tab styles, other kinds of capabilities potentially. It's another frequent one that we see is instead of having just a full list of fields. Right? We have detailed things currently, but like a tab style interface there as a presentation layer. Could be other things we can consider. We can decide what we want this to be. We can narrow this. We can put this into RFC spec format, when we're done. So I'm happy to, well, you know, we'll do our let's do explode and then figure out what we want this to actually cover when we're done. So primary things that clients currently right? This is your current capability. Let me grab one that's got some, do I have one with groups? Remember if I've got something with field groups in it. Top of my, those products haven't. Why? You guys I think in in the end, when we when we scope down again, in the end, we can probably, like, make a make a rough, MVP of this feature where we just say, okay, maybe this is just it. But if you wanna take it further, then it would also include different, visuals for the same interface. Yeah. So these are kind of your current options. Right? You can have field groupings. Right? And otherwise, you got it didn't half with. So to me yeah. I think we should start with with let's let's think about the I think I mean, options to existing interfaces could be discussed here. But I think in general, the way that this thing started and the way that I see this, the the biggest struggle that clients have today is you have very limited kinds of options actual form editing experience. How things can be laid out. Yeah. For sure. I think the other parts, you know, a toggle instead of a checkbox, that's a new interface. That's just a custom interface or an option or stuff like that. But it doesn't really change the way the form itself is rendered. So I think for the sake of this discussion, we can focus on that. Cool. I think some of the bigger ones that we see here in the feature request is around where does the field label and description go. I think that is sort of one bucket. Does it go top? Does it go bottom? Does it go left? Does it go right? Then around how do certain groups come together? So there's like a sort of a new group UI, like a group of the title, and it's in a gray box instead of on a white background sort of visually, you know, cluster some of these form inputs, which then made some where the descriptions go. And then the other one is around, and it's not so much in the original screenshots, funnily enough, but it is I think of an important one here to bring up is what does the grit look like if you go beyond 2? Right? And and, where I can see this discussion going quickly is what about responsive? How does that work? And what about, on the screen that is about 6 meters wide, to make that work in a way that is still user friendly? That is a good question. I this reminds me of a small little bug if we want to just take a little tangent for a story time. Because we have this little bug, where if you have a checkbox with multiple, options, we change the way how they are displayed depending on how many options you have. So if you only have 2, then they are right beside each other. But, for example, or if you have, like, I don't know, 5 or let's say 10, then we put them below each other. And we had this interesting fun little little bug is that we made this also dependent on the content of those checkboxes. So if you have long text, then we actually, you know, span the whole width so you can actually read the thing inside of the checkbox. But what this resulted in is that actually, in like languages which are very short and there are languages that which are very long, like in German words, you know, which means that you have different layouts depending on what kind of language you have. And then, there were a couple users that used Chinese characters, Mandarin characters. And this then resulted, like, if you translate it and then you got different layouts for different languages and stuff, that that was quite quite a fun thing. I think I fixed that, by the way. But, okay. Enough of that. Sorry. Yeah. Let's see. I mean, there's there's lots of perspectives. Right? Like, how many columns should that be dynamic? Do we want to provide a fixed fixed width as of right now? Like, 2. Let's just say, okay. You get 12. Is that good enough? And how do you configure the responsiveness? Then how do we have breakpoints? How many breakpoints do we have? 2, mobile, desktop, but not every screen is the same. How do you configure that? Do do we even want to configure that? Like, yes, but no. Meh. I mean, really, how much database work and actual data modeling are you interested in doing on mobile, to be honest? Like, how many people actually, editing the databases and data records on the phone? Like, how important is he's he's funny. The answer is very important. This guy does. You'd you'd be surprised by how many people use mobile or mobile adjacent stuff now too. Right? If you have the folks with flip phones and you have people with with, you know, small iPads or, yeah. Yeah. Just going by the chat. People are saying the same thing too. Mobile interface, main point, which isn't direct is people editing videos on their phones. The people do everything on their phones nowadays, and I'm one of them too for what it's worth. So when it comes to grit and responsive, this is this is one of the reasons why, there's a lot of apps that are sort of, like, app builders, like a read tool, for example, that opt to make it a scrollable window when you go smaller for this exact reason so it doesn't have to do any sort of weird new reflowing. There is tools out there that I won't name by name that just straight up say there's no native there's no responsive design at all. There's no mobile version. There is different ways of of handling that. The way Directus does it right now is in the in the sort of 2 grid in the 2 up, the screen gets too small, becomes a one up. And that an easy easy enough sort of reflow to make. Right? Because whatever used to be side by side is now beneath each other, and that is good enough. Right? It it's it's what you'd sort of expect to happen, and it doesn't really cause anything too strange, from happening. If you're in a 6 column grid or so, like, if I'm scrolling down this feature request a little bit more, there were some screenshots from a tool called They have, like, a a sort of rich layout, which is roughly 4 columns. But then within, you know, one of the columns, there's another sort of 6 column y thing nested. And now I'm like, okay. Well, if you're responsibly squishing that down, weird things will happen. Like, what goes where? How does it flow? How does it grow? Do you expect, like, the 4th column to become, 3 columns of white when it goes to the next one? Do you intend it to still be blocked, but then you have 3 and 1 sort of weirdly underneath it? Or does it switch forward to a 2 grid? There's there's weird questions that happen at that point when you go down. And all so how does it interact with other fields that are then further down the page? Right? So right now, because every field is basically just in the same, same list of fields, It would start showing up side by side with other fields in that same grid, which could get funky and sort of unintentional. So one way around that potentially is to instead of doing a grid, let me do it now where it is based always one column, but there's a group type for creating grid sections in your form. Right? Because that way, it will always wrap within just that group. You don't your unintended interactions with other fields further down the page. And then that also means that you can start nesting those in whatever way you want. So if you're trying to re replicate that sort of 4 knocks set up where you have 4 columns, where the 4th column itself is like a a 6 column grid or something, you could because you can start nesting those those grid forms. Right? And it it kinda starts responsively matching the column size rather than the form size. Hannes in the chat says, additional groups feel cumbersome to set up. Yeah. Fair. Although at the same time, you know, to achieve the same thing that we have now, you could have one group and just put everything in it. Doesn't necessarily, you know is that is that what the price of admission get for, flexibility in the new layouts? And then on that same note, you know, the the some of the other layout settings, like, is the field name on the left or on the top, the description on the top or on the bottom, that kind of stuff could be settings of a group. Like, it doesn't have to be, settings of the whole form at once. Right? We could also say that the form, by definition, just has one root group, and therefore, it's always there, but it uses the same same system. Alright. I can see that work in my hand. Like, is there a leaner way with less clicking? Currently trying to, like because if for me for me personally, the I I want I would want it to be as least intrusive as it can be because because I just wanna set up my thing and I wanna keep going. Right? Like I do not want to spend my time with designing, you know, layout. Like like this is like, I'm not sure how to say it. Like I I want to model stuff, I want to make like this this is how it how it works now. Like I just want to model stuff left, right, things and move on, you know. And I have other stuff to do. I have problems to solve as a administrator, let's say, of an instance, and I just wanna put some stuff in and keep going. So if you then have to jump through hoops and and, you know, like with all the, oh, but then on mobile, because I didn't, click on the full width. Now on mobile it is only half and it looks bad. And then I have to click this again and then the drawer opens again and I have to go into specific settings of a thing and then close the drawer again and choose the other. And that's that that feels icky. Like, I'm not sure if if we could design it in a way maybe with just small little toggles, like, without, specific options for those interfaces, when, like, the drawer opens, maybe we can make them just, small little toggles that you quickly go through just just without leaving the modeling page. Maybe maybe I don't know, like, it did did that make sense? It does. It it's a, you know, it's a tricky thing because on the one hand, it's like if you wanna do it sort of quick and dirty, so to speak, then that's fine. That should be possible. At the same time, if you wanna make the best user experience for your end user so so let me back up a little bit. I think there's a difference in, flow when you're first setting it up and you're doing the data modeling versus when your data modeling is done and sort of finalized and you go into the details to make it a nicer user experience for your end user. At which point, you might set up, you know, I wanna use monospace for an input and add a little icon to make it, you know, friendlier for the end user, that kind of stuff. Right? I think that is also where this whole gridding stuff comes in. It's like, do you care about grids and how it responsibly shows up side by side instead of ordered top to bottom? Well, if you're doing the data modeling, possibly, probably not. It's just like you need to have the fields to check if it works, build the integration, move on. Right? Only then when your data modeling piece is done, can you circle back and be like, okay. Now I'm gonna spend an hour or so to just really make this form the best form it can possibly be for the use case that I have. I wanna conditionally show and hide some things. I wanna do it in certain sections have to be like a 4 up grid or a half half width group where, I wanna order it differently, etcetera, etcetera. Right? So I think there's 2 different points in time and 2 different, user flows that that are related. So to your point, I do agree. It's like for that first one, I mean, you're just setting up the data modeling, experimenting with what fields and what names and everything else. Quick and dirty. You don't wanna be slowed down by having to think about, is it 2 or 4 or 6 columns? Like, who cares? Just go quick. Right? Make it work. But I do think that is where we can introduce that additional flexibility that we're talking about as part of this this feature request to saying, well, if we hard code this form to be 4 columns instead of 2, we're gonna have the same discussion a month from now where it's like, okay. What about 6? Right? Yeah. And we're gonna have the same discussion a month from now where it's like, okay. Somebody wants 12. So by doing it as a group extension type where we say, okay. The group is just the thing that makes it x number of columns and we don't care. We allow that flexibility in a sort of opt in type of fashion rather than us having to predefine, okay, a direct this form is always x. Like, it is now. We say it's always to deal with it. Right? Yeah. For for me, priority would be, just looking at at the screen right now, let's see, let's look at the theming group, right, or the SEO group also. I would like to avoid, or it would be it is near and dear to my heart, you know. Like, if I now want to split the theming group, I don't, like, I don't want to be the kind of back end where you have to click on the, 3 dots, then a dialogue or, like, a popover opens, then you have to click on edit fields, then the drawer opens, then you have to go inside of that, and then you have to configure some type of grid system and break points and stuff and then the whole thing closes and then, oops, I forgot one thing, I have to go through the entire thing again like this. Like I really want to avoid that. So I'm like, okay, And we maybe make sure that this doesn't happen. Maybe we can include some controls that are maybe enough already on the screen right now. So like, side the three points where the options would be, maybe there could be quick toggles where you can very quickly just with one click, like, boop, and then it's half view. And, you can configure it and then another click, boop, it's it's it's the mobile view. And then you can configure it again. Yeah. How about that? So the reason why it has to be a drawer now is that those groups and interfaces themselves are an extension type. So, therefore, we don't know what those options are. Right? So if somebody makes a new custom grid group now, which you could theoretically, the options for that group is like a an open ended question mark. It's just a set of fields, and we don't know what they are. And we don't know how to, you know we we know how to render them because we ask you we ask the extensions, like, what options do you wanna render? And it's basically just another view component. Right? So it's like a black we just anything goes into that drawer and have have at it. So we can do that. We'll have to come up with some sort of standardized syntax for those plugins to say, here is the 2 or 3 things I wanna be able to edit in line that makes sense for this type of thing that I'm doing. Or we have to go the other way and say, well, we just built more of an Apple approach. That's who it where we say, well, the direct extensions are special and they get to do some of these inline things, but regular extensions are back to the old drawer style. You know what I mean? It's just that that flexibility angle because all of these are extensions. Yeah. I get it. That's a bummer. Like, because we we strive and we always, our strength, right, is that everything is so super duper flexible that you can do anything yourself. Yeah. But for this, can we? It's a question. Right? I I think when it comes to the drag and drop UI of of doing the layout of the form, if if you have a 4 grid, we have to show it as a 4 grid in line there as well in your editing experience. Like, that, I think, is is definitely something that we have to code in. But then if there's a group that has an option for number of grids, how does that how do we connect the dots? Right? How do we know that the grid column option in or an extension should be mapped to our editing experience for the form that makes it so that makes it work like that. Or again, maybe that there's the case that we say, well, you know, the way to handle grids is just not an extension type and there's no way for extensions to do that. It's just the native direct listing. Where we stay, okay, form layout, order, and grid, that is just a a direct as native thing. You can change it through extensions or anything else. You can still make a custom group, but the layouting options for that is not something that we can natively, manage on your behalf. Like, that that is also, you know, an option. Mhmm. Yeah. Like, I I would be like, let let's let's just, you know, the, gut gut feeling is just this sounds reasonable because it's not actually concerning your data. It's just like our our, product UI. So it makes sense that we have this control of the layout. But I can already see, like, it's this is gonna be the first comment in that PR. It's like, oh, but I really would like to do this in my thing. Can we can we add that also? And then every time. Every content. Okay. Alright. So so this is the layout type of thing of that PR of that of that RC. I think it just okay. Let's you said in the beginning the other interfaces are mostly just other interfaces, so they aren't really concerned with this. I think the difference between a checkbox and a toggle, that is an interface option or that is a new interface. I don't think that has anything to do necessarily with form rendering. So I think for the sake of this art for this discussion, we can just keep the scope to form rendering itself. I saw there there was some a couple of good points in the chat earlier right before we started with a couple of points around a little bit more general updates to forms and and interfaces, what we can do with it. 20 minutes ago, somebody was saying, it will be cool if you have, like, a 3, 4 column layout instead of just 2, expand the form width. So it's like the whole screen instead of just, you know, a a max width. But you could kinda do because there's, like, a full width option for an individual in the face or group, but it's I I do agree it's the whole form. It doesn't quite quite work like that. Aligning the form itself to the left or the center of the screen or maybe even the right. And then it gets into which I feel like a bit of a different feature request, but I wanna call it out because it's in all caps, so it sounds important. Actual relation drop downs, which I think is just make making sure that a second drop down is updated based on the value of the first drop down, which is, again, kind of not really formed. I think it's actually I think it's actually more related to the relational interface itself right now. They always go to a drawer. I think it's more of the so like, a many to 1 or one to many. Oh, that part of that nature drop down. As opposed to a drawer pop. Yeah. That's an interface itself. That to me is again, I think we're kind of a little out of scope for this for what I think we want this review to cover in detail. Okay. Yes. There are there are dozens of things we would all like to have on the interfaces side of the house, but that's why custom extensions exist and you can't build them. So although, you know, this grouping style that we support, I have seen tab style, the group interfaces where someone has built a custom interface that actually does, like, tab styling and multiple fields and tabs and things inside their groups. So custom extensions support those kinds of things. Yes. Relational drop downs instead of drawers would be really nice in many use cases. You know, it's, you know, it's funny. This is a complete sidebar, and I I wanna be cognizant that we don't end up spending 20 minutes on this because it's an easy one to slip into. But the many to 1 interface, the drop down one that opens drawer, it has the the actual drop down bits built in. It like, when we built it, it had that baked in. It's the problem was that similarly with most every other thing in direct is, like, week 2, somebody was like, I have a 100,000 items in the related Yes. Related table and I I am now going to break your interface. Outright. The drop down only shows the first a 100, so I cannot find the thing to select. And I'm like, yep. Yep. Yep. Yep. Yep. Yep. So then then we made the call to, like, always show it as a drawer, which works for everything, but it's it's not as nice as a little drop down. But it it used to work like that at one point in time. Yeah. Yep. Yep. I know we've had bring that back as a as an option to to but but the the funny thing there is, like, to do it the best way possible, we need to have an updated count of the number of related items at any point, and getting that count can be very slow if you have 100 of 1,000 of them. So we have to come up with some sort of way to cache the count our site first so we have a sort of estimate count that we can use and then update that over time because, otherwise, it's gonna be not performing enough to do you know? Anyways, long story short Yes. Similar thing that so we did that for the actual layouts, as part of that performance improvement a year or so back, a year and a half back, where you started caching the accounts and not running the count every single time, only watching for changes or what. I'm not sure what happens behind the scenes in the caching aspects. But for those clients who had millions of rows of data and being able to present that and reflect that and not pulling everything Something like that. Yeah. On the counts. That's so The database running every single time you clicked was hugely performance impacting. So Yeah. There's there's also some databases, and this is, of course, where the devil's in the details here. Some databases also have a difference between, an estimate count versus the actual count. So, like, in Postgres, there's a system table that keeps an estimate count that is not guaranteed to be accurate, but it's sort of a ballpark. So at least, you know, are we over under on 1,000, or is it just, you know, a couple? Yeah. So there's also a world this is again a big sidebar, but such goes in these episodes. There's also a world where we first get the estimate count, which is cheap. And then if that estimate count is less than a couple thousand, then we meet the actual account. So we can show that. Nice. Anyways, that is a whole different That is a very different ballgame and Oh, okay. Another discussion. Mhmm. Mhmm. That that's a fun one. Okay. How many items do I have? And you asked the database and it's saying, probably 10,000 maybe? Best I can do. Yeah. It's it's an interesting problem though because it's one of those things where in order to know that, it's it's, what is that in COMS size? Is that one of those o n problems or an o two problem? Where you know what I mean. Right? Where it's like, the more items you have, the slower it gets linearly to count the number of items. So, therefore, if you have a table with with 20,000,000 rows in it, how do you know it's 20,000,000 rows efficiently? That's weird. Yeah. Oh, and, yeah, that's that's what I thought. It's it's clear that if not comp side. I'm still just a UX designer, guys. Take it easy. Cool. Some of some of the other stuff in the chat here before I I miss it again. So it says, I wanna speak with a person with a 100,000 items. I need a quick chat. Oh, for what it's worth, we, we even do a similar thing ourselves where we have, you know, we keep, error logs for, you know, certain cloud deployments. Those error logs have a one to many back to the project, so we can see the most recent 10 per project. Right? But that also means that the whole error logs table can be in the millions. So that one to many needs to be prepared for, you know, what that looks like if you said select existing, and now all of a sudden you have a list of 10,000,000. Like, how does that work? Right? It it's it's a very real thing that people do, ourselves included, which makes some of these discussions a lot more fun if you're thinking about it many to one. I am making the drop down nice and easy. Nope. Yep. Cool. And then on this another one says here, it feels like we could add a special component that can be defined for group interfaces where they decide on the layout for field layout. Right. Yeah. So this is similar. This is going back to the, how do we do inline options for groups? Right? So honest suggestion here is basically saying, well, maybe just like inner like options for interfaces, there's a way to say, let the actual form extension itself decide how to render on the settings page so we can make that optimized, which is, yep, interesting. Something along those lines. There's something about a half width group. That's fine. Otherwise, do it with 2 columns. I think we touched on the other stuff. Right? Cool. Then the second thing is around in this feature request rather, is around, where does the label go in a form? And is it something that you should be changing? Or is that something that is just not something you should care about? It's an interesting one. Kava is it it gets to a bit of a user experience question. Right? And and this is, again, a topic that can easily get off the reels in terms of theming and customization and how far do we wanna take it in the sense of, you know, if you give the end user infinite flexibility in this kind of stuff, you also give them infinite food guns to make it trash, right, for the for the end user. So there's a there's a very real discussion around, you know, is form labels left aligned input, right aligned? Is that good for good? There be opinions. Is that good for the end user or not? Right? And then the question becomes, who should be in charge of making that call? Because we make a lot of calls because it's a studio. Right? And it's the same, yeah. Yeah. Hans says the same now. It's a layout too. Once you have weird layout problems, you get a similar similar, UX problem. Right? But the question becomes, who's responsible? Right? Do we say well, because we built the studio, we have good defaults. We wanna make sure that everybody has a good user experience. That's what we pride ourselves on. Therefore, are we gonna limit some of these things? Or are we gonna say, go nuts, and it's your problem, which is great for some and a problem for others. Right? And we've seen this before. We've seen this in the past. Like, when we ship theming, which I think has been been pretty pretty good to have, generally speaking. It opens some of those questions too. Right? Because I I know, my very own Kevin made a, like a teenage mutant Ninja Turtles one, or or what do we call it? Something non something not trademark related, as as a sort of experiment to see where how far you can take it, but it's also objectively horrendous. It's objectively bad, right, for for user experience wise. But who who's who's responsible then? Right? And and where do you draw that line? I think it's an interesting question here too because, like, if we make a if we kept just if you make a 12 column grid, you can do some very powerful, easy to use layouts. You can also easily make a garbage nightmare. Just like you can make a dumpster fire. Who's then responsible for the dumpster fire part of that? Yeah. Because the yeah. Like you said, this is an actual thing. Like, if somebody badly configures their instance, it may reflect even bad on us because, like, the users come in and say, like, oh, what what what oh, brother. Oh. What what happened here? You know? Like, Directus is ugly. Directus doesn't work. Oh, this is not good. And then it reflects bad on us. So actually, we should think about that we make I mean, you know, flexibility is nice. It is it is cool, and it is one very, very good point for us. But to what extent? Like you said, okay. So we we do have to so quickly and I love it. We do have to draw a line somewhere. There there's an interesting part of the tech industry that people have been yelling about for decades now, which is the whole Android versus iOS thing. Right? Or Linux versus Mac OS thing, which is, like, for the longest time on iOS, you cannot you can you can reorder your app icons, and that's about as much customization as you get. Right? For the first couple of iOS, if the background was black, shut up. Your wallpaper on the lock screen was the was the globe. No options. Right? And then they were like, oh, maybe maybe you can have maybe you can have a wallpaper, and then you could have some fish instead of a globe, and then that was it. Right? But then, you know, people on on the Android side of the house have been screaming for decades. Like, oh, my wallpaper moves this fantastic life great. But, also, you can make an absolute dumpster fire of of your phone, which is whose problem is that? Right? Is that is that you're gonna make it better for the power users, but you also give a bunch of food guns to everybody else? And for what it's worth, Apple is now doing the same thing, I think, right, with this new iOS 18 where you can, like, tint your app callers or something, and it looks horrendously bad just just objectively. Of course, it's an opinion, but I'm right. It's objectively bad. Where because you just see the icon from, like, I don't know, Notion or something turned bright yellow because you you tinted it that way. It's just not good. It's just not work. But the question is, like, you you can make it good with a bit of effort, but people don't will not. Is that is that a problem? Like, is that It it the older I get, the more I think, yes. That's a problem. Because the So you're gonna look at an iPhone now, and you're like, man, that is ugly. It's so good and hard to use, and I don't care. But at the same time, the the people that set it up that way for themselves, they might love it. It might be their preferred Yep. You know, becomes an opinion thing. Right? But it's like, how do you decide where to draw a line? Yeah. Quick. Because there was the the quote from, I think Henry Ford, was it? Like, with the car, like, you can have, the Ford in any color that you'd like as long as the color is black. Black. Yeah. Right? Yeah. The same for iOS. You can you can do anything you like, but as long as it's not what you like. Yeah. As long as you like what we like. Right? Exactly. Yeah. So, like, I I think I personally I mean, of course, this is just, you know, opinion piece. Careful. It's I think we should be for the live stream, and I posted a picture of, Tim did Ios screens. It it is something. And these are the ones done well, mind you. Anyways yeah. So so for for the listener, it's basically, you know, 5 different iOS screenshots with, like, different color background, and then all of the front, front end, all of the the icon colors, is is the same color as the background. So, therefore, at a glance, everything looks the exact same. It's just that's that's the main issue for me. It's like, I don't know what app is what app anymore because they all look identical to me now. Google oh, man. This is such a sidebar again. But Google did the same thing. Right? When they went through the whole material design thing, now every single Google app looks the exact same. If I log in to our Google Workspace and I click on apps, I just see the exact same icon, like, 200 times, and they are all the same. It's there's a small variation in shape, and I just don't know it. Anyways, yeah, it is let's try to get that back on track. It it is an interesting discussion in general, though, for of, like, how far do you let people take it? And and is it a good thing, or is it a bad thing? And where do you draw the line? I think in this case, as long as we have good defaults, I wanna on the side of let them have the flexibility, but make sure that by default, for the people that don't spend the time setting it up, it looks good and it works well. Right? Mhmm. I think that's kinda where your earlier suggestion comes in for, like, if I just wanna go in at a con at a bunch of fields and not think about it, we need to make sure that things work out the right way at that point. It's like, what makes sense? Help the user as much as possible to have a good default. And then if you wanna go in and be like, well, I want my address field right aligned next to an email and the name field, and then the address needs to be split up between, like, street and and number, and then all this kind of more detailed stuff, they can come back in and start using grids and and nested groups and all that kind of stuff to do it. But by default, you know, we'll we'll make it as good as we can. Yep. And it's a very hands off approach. It's like you break it, you fix it. My my final question before we kinda diverge back, any compliance or standards we need to consider here? WCAG, accessible I don't think so right now. Always. I mean, I assume that the the the, it's funny you mentioned it because, I mean, yes and no. It's it's another question of who's responsible. Like, if if our defaults should always, yes, I think, we should always provide the tooling to make it as accessible as possible and to easy as use as possible. But at the same time, if you wanna go in and remove all of the field labels and align it in a way that turns it into a piece of art, is that allowed? It is. That's part of that question. I'm more considering I think right now, we do have some issues in the space, and I don't know if it is if it's part of this that would fix that or be part of you know, if we're gonna touch some of this stuff anyway, like, tabbing. Right? Being able to tab through your item fields and, you know, be able to quickly navigate to things. Some of that doesn't work very well right now in the data studio. Yeah. Yeah. Or at all. Right. And so just some, I just, I, because I've been doing so much standard and security. It it it's a very good point, though. It's it is very true. It's like if you have, you know, a a if if you went nuts, so you have a super rich grid and everything sort of aligns funky, funkily. What is the tab order, and does that make sense? And is that something that somebody needs to be able to configure? Do you tab in and out of groups? Do you tab in and out of individual fields? How do you make sure that the tabbing order is visually consistent with what's about to happen? It's a difficult question for sure. For sure. And it and it goes right back to the who's responsible. Right? Who's responsible for all of this at that point? This this could even very quickly turn political in the sense of, is it the tool builder who's at fault, or is it the tool wielder who's at fault? No. No. No. No. No. No. I think I think some good guardrails today, but, you know, let's, let me let me try to summarize this discussion as the only the only thing stopping a bad guy with a form is a good guy with a form. If we get it, who's responsible? I think I think good guardrails, with some flexibility inside the rails. Right? And I think it's Yeah. It's always worked out well for us in general. I'm okay with some level of right to to some degree. Right? I think what we're trying to do here is improve the current experience. Yeah. We don't have to give ultimate any flexibility. Right? It is our data. You you wanna do that? Build your own, you know, use the APIs, build whatever you want. Right? You have you have that flexibility today. You can build an interface in front of this or a Sure. You can build your own direct just for like oh, yeah. Yeah. Yeah. And, you know, to some degree, right, web design and things that people are building, some of the applications and tooling that people will build on top of the directors APIs. They have this flex they have the ultimate flexibility to build whatever they want. You wanna use the data studio. Again, we have a reputation. We have our own. And and I think good guardrails, good guidelines, and, you know, just configuration options. I think there's some of that as just adding some additional configuration parameters to allow for you know, we do wanna follow good accessibility practice. In order to do that, there has to be some options for that. And we can put some default, or we can just say these are the defaults. Right? The the defaults are what they are. Just making it so that it actually works and meets the guidelines at a minimum. I like it. Cool. Alright. We've got, 8 minutes, 7 minutes. How do we wanna start wrapping up, gents? I think I mean, it's just okay. Go for it. Go for it. I was gonna say circling back to the initial thing of is a grid a system thing or is it more of a group type setup? I think I'm kinda leaning towards even though it is a bit more setup, doing it the group style way. Because that way, you can start nesting things. You can start configuring it to your heart's content. You can mix and match. You can have a section that is a 4. You can have a section that's a 6 upwards, 2, or 1, and mix and match on the page. I think making that a sort of nestable thing feels like the right move. We can still say that the form itself by default is one of those units, right, for ease of setup. So if you just want the whole field the whole form to be a 2 up, then you're done by default. Absolutely. But making that a sort of thing you can nest as a section feels like a powerful thing to have. Because that's what's gonna allow for one of these things where you have a 4 up, but then in the 4th column, you have a thing that also has field side by side, right, to make that as flexible as you want. I think when it comes to form label, that feels like a very system y type of thing. Like, we render a form with or without those groups with with grids, and then maybe on the form level, maybe on the the grid group form, whatever you wanna call it level, or maybe both, you can just set, okay, left line top of line, label and we can be a bit more flexible in that. And the same goes for the description. Right? Show at the bottom, show at the top. Those could be be just a toggle for for the form in in general. The new styles for check boxes, those types of things, the the the making them into 1 drop down and actual drop down. I think that is interface options. That's just separate from from this discussion to me. And then last but not least, there's 2 things coming in from our favorite team, which is our own. Sounds like we're in the last 8 minutes. Should different interface styles be just styles in existing interfaces or new extensions or interfaces? Opinions. Opinions. Opinions. I think it has all to do with the user experience. So to me, a checkbox and a toggle are effectively the same thing from a user experience perspective because you clicked enable, you clicked to disable. They're the same. Right? So to me, a toggle is just a different visual representation of the same underlying thing. This is the pain. Don't hate me too hard. It's a it's a different visual style for the same thing. When it comes to and and, funnily enough, we are not always good about doing it this way either. Right? So, for example, we have a drop down single select and a drop down multi select. In our components in code, it's the same component. A bit hard to maintain, arguably. Shouldn't have done that. We'll probably refect it at some point. Mhmm. Because the user experience is different. Right? Because one is, like, you're you're rendering a list of things. You're checking off multiple. You render it. Now when it comes to a multi select as a list of checkboxes versus a drop down that then shows the list of checkboxes, that is again a different visual style for the same interaction. Right? But where do you draw the line? Because in that example, you could say, well, they're visually so incredibly different. And for the end user, they might expect them to be do 2 different things. So where do you draw that line? I think it's just an opinion in a case by case. Right? It's like in this case, I would say a list of checkboxes or a drop down where you can select multiple things. Those are so different from, like, a mindset perspective that we should make it 2 different interfaces even though they do the exact same thing. You choose you pick and choose 1 or more things from a list, and that's what you're doing. Yeah. Especially if you have 2 different styles, like you said, right, with with the drop down or they could have different options, and then we would have to respect those also in the in the drawer, for example, depending, you know, on what you have. But this has to be configurable then also for extensions. And that also sounds like okay. Just make a new interface. It everything is in order. It is just like that. Deal with it. Yeah. Go with it. It sounds very There's there's 2 more fun ones for the last 2 minutes here. Tim asked, make it difficult nearing the end, will it be able to configure conditions across groups and sections? I think the answer is yes. I think conditions for an individual field or group should always be able to listen to anything else on the form, just whatever nesting level you're in. Of course, there's the same responsibility things. Like, if you listen to something that is visually completely disconnected and related, you can make it very difficult to use for your end users. But from a technical angle, I think we should make it possible. And then the last question here now is saying, what about applying conditions on hiding or disabling fields in the relation drawer based on the state of the form? And for that, I'd like to say tune back in 2 weeks from now. That that is a bit of a different discussion around how that drawer works. The the relation drawer right now, you know, it renders the same layout that you use for that collection, in the main sort of layout for that collection. So, therefore, the fields that show up are are the same that you see on the layout page for that collection. It also means it's a bit tricky to dynamically change that because it is matching the other one, but that is a different moving level. It should be possible with custom CSS and a group extension. Yep. Yep. Yep. Yep. So many ideas. Anyways, with that, we're at the top of the hour. I wanna thank you all very much for tuning in once again. We'll be back at some point in the near future. I think we're in another one in 2 weeks from now. Make sure to find this on direct to zio slash tv. Any other closing thoughts? Dan, John? I figured it out. Thanks to the community and all the good feedback on these on these issues. I'll post comments here shortly and then, Greg, if we need to do a full RFC on this one, we can work it out. Sounds good. Alright, team. Have a wonderful rest of your day.","f5bdab73-98c5-4b82-82cd-d08babe50bca",[398,399,400],"f89c7bab-7b50-4e16-ba47-6c56fd82cf60","13cd4775-d2d1-4305-967e-7282174f4af3","d512e3fc-2b28-4f38-8f0d-25b7041c22bf",[],{"id":133,"number":134,"show":122,"year":135,"episodes":403},[137,138,139,140,141,142,143,144,145,146,147,148,149],{"id":148,"slug":405,"vimeo_id":406,"description":407,"tile":408,"length":409,"resources":410,"people":8,"episode_number":413,"published":414,"title":415,"video_transcript_html":416,"video_transcript_text":417,"content":8,"seo":418,"status":130,"episode_people":419,"recommendations":422,"season":423},"17853","1008857977","In this recording of our live event on September 12th 2024, Nils, Jonathan, and Rijk discuss Optionally Delete Unused Files.","0a141eae-c91d-4519-bec4-1faf19b7ef37",45,[411],{"name":304,"url":412},"https://github.com/directus/directus/discussions/17853",12,"2024-10-07","Optionally Delete Unused Files","\u003Cp>Speaker 0: Welcome back, everybody. Welcome to another request review. We have a very special guest here today. Welcome, Niels. He's 7 of our usual host, Daniel of the day.\u003C/p>\u003Cp>Jonathan, what are we gonna be talking about?\u003C/p>\u003Cp>Speaker 1: Today, we are going to talk about discussion number 17, 853. That is going to be about\u003C/p>\u003Cp>Speaker 0: My favorite.\u003C/p>\u003Cp>Speaker 1: File deletion and management. So this is primarily around the relational, file deletes. If you delete a file from a record or you delete a file from the file system or from the direct to files library, what are some better options for managing that relational delete. So currently, we do a do not delete on the file. It's kind of the default configuration.\u003C/p>\u003Cp>There are some cascading rules and things you can configure in some cases. But because files can be associated with so many different collections and records, this particular request is around, are there some additional options or features that we could add around improving that file management? Right. So that's the that's the general I'll drop a link just in case people didn't get it.\u003C/p>\u003Cp>Speaker 0: Yeah. So to kick that out right away, the, the important thing to note here, of course, is that direct to files, you both have this sort of, you know, physical file on disk, and you have a row in direct to files, the system table that contains additional metadata we cannot store on the file itself. Right? So think about, we store information about, the some of the exit data for easier retrieval. We store, things like width and height, file duration for for movies, I think, and audio files.\u003C/p>\u003Cp>We have some additional fields, focal points. Yeah. Exactly. Some location text, some optional metadata that's human configurable. And, of course, some information about what direct this user created, updated, and modified it, whatever.\u003C/p>\u003Cp>So we have a record in the relational database in the system stuff for for more information. So it also means that when it comes to automatically deleting those files, what we're talking about here is effectively a, you know, sort of cascade delete or a cascade update whenever that relational record is getting destroyed. Right? So from a usual database management perspective, this is a very standard task thing where it's like, okay. The ID of the file gets removed.\u003C/p>\u003Cp>I want there any record that uses it to be destroyed as well. Let's do the other way around. Right? The the foreign key gets removed, destroy the file. Now in this feature request, what which way is it going?\u003C/p>\u003Cp>Because I believe it's saying that they wanna delete the file when they delete the record where it's used rather than the other way around. Right?\u003C/p>\u003Cp>Speaker 1: Yeah. In this case, yes. They've mentioned it both directions or it's mentioned somewhere in here. But if you're deselecting or removing an item from a a record association. Right?\u003C/p>\u003Cp>So if you've got something simple like articles with a file associated, one of the option requests discussed here is if I delete or remove the file from here, that the user either automatically deletes the file from the file system, removes it from direct to files, ideally cleans it off the drive. But alternate options were to actually prompt the user for, do you wanna delete the file? And if yes, go ahead. Yeah. Lots of complexities that come with all of that.\u003C/p>\u003Cp>Right? Because file the file could be in use by another record. The other big thing with files, because files can be embedded inside of things like WYSIWYSIWYSIWYGs and block editors as relational. Right now, and this isn't this isn't necessarily a direct to specific issue. This is a SQL issue.\u003C/p>\u003Cp>Right? Unless you're maintaining dual relationals all over the place with everything related back into the file system or some mechanism to track because files can be associated with any number of collections and be embedded inside of rich text fields. How do we manage or understand those kinds of things as well? So there's a a number of factors, I think, that make this complex. But for now, at least what they're asking for is if I delete the file from the record, automatically delete the file or prompt the user, with an option to keep or delete the file.\u003C/p>\u003Cp>Speaker 0: So it's an interesting one there because the so so both those points, the first one to your point, this is this is a problem that has been as old as any sort of content management system on the planet is if you have a link to a file in a piece of text, is that a relational record? No. Is that a relationship in a database you can easily track? Also, no. So now on file delete, are you gonna be scanning through all of those blobs of text all over the place to sort of pseudo find relationships that is hella inefficient?\u003C/p>\u003Cp>Right? So how do you deal with that? That's that's a good one. The second one that is interesting is that this is kind of the going the wrong way, so to speak, if you compare it to how regular relationships work in a database. Right?\u003C/p>\u003Cp>So usually, when you say when you do a cascade delete, it would be the moment you delete the file, you delete all of the rows where it has been used in a foreign key. Am I saying that right? Or am I making this up? I was getting too confused, to be honest.\u003C/p>\u003Cp>Speaker 1: I think it goes the other way because the foreign key, at least in that case, like in my article case, the foreign key reference is actually here on this record. So we actually store the foreign key. So I believe the cascade is actually going the other way. So if I delete it from here and I tell it to cascade, it should cascade and delete the file. And I believe that actually does.\u003C/p>\u003Cp>So we can actually double check the settings, article because\u003C/p>\u003Cp>Speaker 0: we do some article in both ways in direct as I was just trying to remember if I wrote like myself which way the default is.\u003C/p>\u003Cp>Speaker 1: So the relationship in this case is directional from direct as follows. Right?\u003C/p>\u003Cp>Speaker 0: It was the rate that I said. It's like the moment you delete the file, you get to choose what you wanna do, with the forward key field. Right? Do you wanna nullify it, or do you wanna destroy the whole row that uses that forwarding key? So so that's why I meant with sort of like the feature request going the opposite way.\u003C/p>\u003Cp>Right? Because by a database and default, you're saying, okay, the moment you delete the file, delete everything where the file is used. But it feels like this feature request is going the other way. Right? They're saying the moment I deselect the file from a gallery post or something, I also want to trigger a deletion of the related file.\u003C/p>\u003Cp>Speaker 1: Yeah.\u003C/p>\u003Cp>Speaker 0: Yes. Key.\u003C/p>\u003Cp>Speaker 1: So now you're actually you are actually correct. It does go the other way. So if you delete the file, it's actually cleaning up the foreign key, right, is what we're technically do. Yep. My mistake.\u003C/p>\u003Cp>Speaker 0: So this and this is welcome back to the beauty of request review. If you haven't been here before, we always like to diverge as much as we can before we come back down to the notes at the top of the hour. The immediate question to me here becomes, is this a file specific thing, or is this just a directed data thing? Right? Is this something that you should be able to set up for everything where you're like, okay.\u003C/p>\u003Cp>The moment I I delete this record or deselect this relationship, I wanna be able to remove the thing on the other end. Is that a thing that we just wanna support as a more generic option or is this something that is inherently specific to files? Because it kinda sounds like that this is that this person was mentioning files just because that's the use case for this particular person and this website that they're building. But I could see this as be a relationship thing. Yep.\u003C/p>\u003Cp>Speaker 2: At least implementation wise, it's like equal, I would say. There should be no diff like, no technical difficulties to make it more advanced in a sense or more capable.\u003C/p>\u003Cp>Speaker 1: Yeah. No. I actually like that. I I think, especially as we move towards, you know, our our our future concepts of we want to support non sequel kinds of things. This means, to some degree, direct us needs to understand where things are being used and keep track of that so that otherwise, we can end up with a, you know, an even bigger mess.\u003C/p>\u003Cp>Right? Sync beyond files to records to data and content. I don't I've been trying to think about this because this comes up quite a bit. There's there's also things like one of the things that I've seen a number of times recently is, can I tell what the file is associated? Can it can can you show me what else you know, where is this file being used?\u003C/p>\u003Cp>Right? So that comes back to in particular, this is problematic for things like where it's embedded as a text, you know, inside of a rich text. My brain goes, how do we we would have to, in some way, keep track of the relationals as part of Directus. Because I did some searches on, like, SQL databases. How can you do this in c e?\u003C/p>\u003Cp>Yeah.\u003C/p>\u003Cp>Speaker 0: It's not really you you would have to pull up what are all of the foreign key constraints that go back to this table and then go search through all of those tables to find foreign keys with the ID, I guess. That's really the only way to do it.\u003C/p>\u003Cp>Speaker 1: Yeah. It is. And you can do some view things. You can do but you have to you know, it's it's complex. It's not something that's just simple to say, where is this?\u003C/p>\u003Cp>But if Directus in some way was actually keeping track in some way of, you know, think of some kind of an indexing or a mechanism of keeping track that when it gets associated, we track that it got associated in some way. Right? Call it a table. Call it a\u003C/p>\u003Cp>Speaker 0: The the difficulty there, of course, is that data could be live updating through all sorts of sources that's not direct us. So how do we keep that index up to date? Or is that something that we have to periodically re scrape to regenerate, which sounds tricky, or tricky to keep that, you know, consistent. Keep that keep that data integrity alive. This is also a feature request that immediately reminds me of be because of this connection, it reminds me of the one around, how do we warn people, about where stuff is used when you delete it?\u003C/p>\u003Cp>Because right now, you can set up the form keys to nullify a file, but if somebody deletes a file, they might not know where they're gonna be nullifying things automatically. Right? It's a very similar, where is this being used question except during delete.\u003C/p>\u003Cp>Speaker 1: Yep. And that's the that's the common request is I you know, at least I would like to know where this, you know, where this thing is where all this thing is being used. You know, what what all is it associated with in that sense\u003C/p>\u003Cp>Speaker 2: Yeah.\u003C/p>\u003Cp>Speaker 1: For tracking it down? Because if I yeah. You know, I wanna understand the impacts of me deleting a file or me deleting a record, what are the Right. Relational impacts?\u003C/p>\u003Cp>Speaker 0: Now looking up all those foreign keys is a pretty heavy thing. But in Directus, we do store that relational information already. So we should have the ability to say what are the relationships that have this collection in it, and then do a sort of aggregate search that says, okay. What is the count of items that have a foreign key to this item? Which should be a relatively e like, not easy, but a cheap operation to do rather.\u003C/p>\u003Cp>I mean, it depends on table size. There's always an asterisk, but we could, you know, do a what's the kind of items that are using the current primary key as a foreign key in the, related tables and then present that as well, right, where we say, okay. We know, this collection is being used in well, in this example's case, direct this files is being used in, photo albums. And therefore, we can say, when you delete this file, you're gonna set it to null in these in 3 different photo album records. Right?\u003C/p>\u003Cp>Is this something you wanna do? Yes or no? So at least be a little bit more helpful about that.\u003C/p>\u003Cp>Speaker 2: Yeah. I really like the idea of, like, having a Oh, sorry.\u003C/p>\u003Cp>Speaker 0: Oh, no. Go ahead. Go ahead, please, dude.\u003C/p>\u003Cp>Speaker 2: Yeah. I really like the idea of having, like, a graph view. Like, just in general, that would show you, okay, this would be deleted. This would be, like, nullified. This would be this this in-depth, that happened with on a delete.\u003C/p>\u003Cp>And, like, the data is already there in the API in the app. We just have to then visualize it with, like, a graph view or a list of things that get deleted, a list of things that get nullified. We aren't we kinda doing something with creating when creating, for example, relational stuff, we already say what we create. Like, do you know this yellow text list that we have on the data data model creation? We can just do the same for the deletion process, basically.\u003C/p>\u003Cp>If you delete an item, go through the whole schema of relations and see what links to what, and that's basically just recursively checking against each nested collection. And the fancy part then would be how to visualize this. And in in terms of, like, do we run it in a list? Do we run it in a fancy graph where it's like, this collection links to that collection, and this field in that collection would then delete another collection or something like that? Or would we just run it as a list very stupidly?\u003C/p>\u003Cp>Speaker 0: And to make that one slightly more complicated, what do you do if there is user input required? So, for example, if the default cascade is make it null, but the field is not nullable, then what? Right? Are we gonna Then\u003C/p>\u003Cp>Speaker 2: you get an escape.\u003C/p>\u003Cp>Speaker 0: Are we gonna tell them you cannot delete it because it's in use, Or are we gonna tell them, what do you wanna do with the 5 places where you're using this? You wanna replace it with something else? And is that something we wanna do in line? Or is it enough if we sell if we just say you cannot delete it right now, go fix the other stuff first? Like, which is also, you know, a flow that would be enough.\u003C/p>\u003Cp>I don't know if it's as useful.\u003C/p>\u003Cp>Speaker 1: Yeah. I think at least indicated that it exists somewhere and then saying, go clean it up before you can actually delete the file. That seems okay. You could give the option to say nullify where I'm at or place with something else where I'm at. Interesting.\u003C/p>\u003Cp>Interesting.\u003C/p>\u003Cp>Speaker 2: I'm I'm also wondering, is it is it is it not really, like, configuration error if you set the relation to nullify something that can't be null? That sounds like somebody has messed up things in that case, which we should also protect people from doing. But\u003C/p>\u003Cp>Speaker 0: Fair enough. Yeah. That that is that is fair. But the the default behavior for foreign key like that is to prevent the deletion, I think. So even if you don't set it to set nil, but you just leave it at the default, which is prevent the deletion, it'll just throw an error.\u003C/p>\u003Cp>Because I throw right now, we don't throw a SQL error that says I cannot delete form keeps Yeah.\u003C/p>\u003Cp>Speaker 2: Exactly. And then we should probably even, like, protect when setting up the relations that you shouldn't be able to set it to nullify something it can't be nullified to.\u003C/p>\u003Cp>Speaker 0: Yeah. But I think it's all the settings. Even the the mistake setup and the the default case. There's a case to be made that we wanna have some sort of user input moment in during the delete that says, okay. We're gonna be either nullifying if that's the setting, or we're gonna try to nullify if that's the setting, across 15 items in your your 12 collections.\u003C/p>\u003Cp>Or if it is a, prevent the deletion, the question could be, do you wanna replace where this is used with something else before you can delete it? Right? That would be a pretty helpful thing. I know we're getting a bit of trend for this particular feature request, but these are all kind of part of the bigger part of the same, sort of questions and user stories.\u003C/p>\u003Cp>Speaker 1: Agreed. And, again, I think he's got he's got some of those cases covered. They they've got some of those cases covered here. Right? So they know to delete the file, keep the file, prompt the user.\u003C/p>\u003Cp>I must\u003C/p>\u003Cp>Speaker 0: delete it\u003C/p>\u003Cp>Speaker 1: in the collection.\u003C/p>\u003Cp>Speaker 0: Well, to to get it back on track for this particular feature request though Yeah. Because the what we just described is, you know, if you wanna follow just a regular foreign key constraint, and we wanna inform the user of what's about to happen, that's part 1. We wanna allow them to take some action if they have to make some changes for it to go through. But then the third one, and that's the new thing in this feature, requested the question, do we wanna do it the other way around as well? Where unlike in a database, we allow a secondary foreign key constraint type of thing where we say, if you delete the the the record that holds the foreign key, delete the related thing.\u003C/p>\u003Cp>And that then has a sort of recursive compound effect where it's like, do we now show any other foreign keys that might exist on the thing that you're deleting through the foreign key that you just deleted? What?\u003C/p>\u003Cp>Speaker 1: Yeah.\u003C/p>\u003Cp>Speaker 0: I think that's probably one of the reasons why, you know, databases don't sort of recursive, like, have that way of doing it both ways because that really feels like, you know, you're you're quickly ending in a in a in a sort of infinite loop type of deal.\u003C/p>\u003Cp>Speaker 1: Yeah. And that might be where maybe you don't show them that. You just simply know that is still being so if they choose, say, the delete option to say, you know, I do wanna delete the file, or the the record in this case, then you could provide an indication that there are existing relationships. Are you really sure? And then it'll affect those other you know, it will affect other things, you know, and number of other things or just the fact that it exists, that it is actually related to other active items.\u003C/p>\u003Cp>So instead of and not try to show them what all because that could be a large number of things. I don't know that you'd want to try and show that in a dialogue box, but you could show this is related to any number of other things or this is related to other things. And therefore, you know, this could have catastrophic effects. Yes or no? And maybe even making an option that, you know, a toggle config flag or something on the settings of that says, if this is still related to other things, then they're not allowed to do that from a permissioning standpoint kind of thing.\u003C/p>\u003Cp>Then, you know, the option is, no, you can't delete this because this is related to other things. Go to the source record and clean it up and do whatever. Right? The whatever workflow. So I think you can go that route, maybe.\u003C/p>\u003Cp>Speaker 2: On another note, I'm also wondering if we should that it's it goes in a similar direction, but, like, protecting the users from making mistakes, would be like a feature where you have a protected collection, that basically says, okay, you have to, for example, enter the, the name or ID or some type of validation before you can actually delete the, the item in the collection. For example, if you're managing users and you don't want to mess up have, your managers mess up the user's collection because that could be catastrophic or something similar, where they would have to then, for example, enter something. And that would also tie into this, like, what happens on the delete part where it's like, okay. This collection is related to other collection that is protected, and we should also, in this collection, mind you that you're deleting something from another collection that is protected. Right?\u003C/p>\u003Cp>Speaker 0: Yes. Yes. Yes. Yes. This old man now this makes me think from a technical perspective.\u003C/p>\u003Cp>We're gonna dive a little deep here. But from a technical perspective, this makes me wonder right now, We rely on the database foreign key constraints for all this. Right? That we say, okay. You said it's a set null.\u003C/p>\u003Cp>That is literally a database foreign key index with a cascade set null. Right? Yeah. But that also means that from a Directus perspective, we're not triggering any logic or hooks or or anything necessarily on the Directus side for those nested deletes because we're just relying on the database to do it. Right?\u003C/p>\u003Cp>Which is a technically performant way, but at the same time, that does raise newer questions around, you know, if you have a flow that handles something on file, delete to clean something up. Right? And that file gets deleted through. Well, I guess a file is actually a bad example, ironically enough, because it's on the disk and not on the database. But if you have a flow that cleans up something, on a database change, but it is changed directly from a foreign key constraint that changes it.\u003C/p>\u003Cp>We're not triggering it as an event. Right?\u003C/p>\u003Cp>Speaker 2: Yeah. I think that was also one of the problems a lot of people had with working with flows that it wasn't, like, cascading these, like, deviate events to, to flows, basically, I think, which would also solve that problem in a sense, I think. Although, I don't remember exactly what the problem there was in detail because it's quite a long time ago, which where I had read through these issues. But I do still like the idea of, like, this this type of protected collection. I I do think that could I'm not sure.\u003C/p>\u003Cp>I haven't seen many press on that idea, but I do think it could be a nice enhancement just from on the side of, like, making sure you don't do anything. But, I mean, aren't we doing something sim I guess, no. We're not. But, for example, on the director's collection, you could technically delete those from the app. Right?\u003C/p>\u003Cp>But we somehow oh, oh, at least Yeah. No. In a sense, we also do some sort of protection there because, like, yeah, sure. You can do that technically, but you really shouldn't.\u003C/p>\u003Cp>Speaker 0: No. No. I'm pretty sure we're we're preventing any any direct to stable modification from the product itself. Yeah. Yeah.\u003C/p>\u003Cp>I mean, you can add custom fields and remove those, but you cannot mess with the the system ones, which I think is a separate feature request, actually, funnily enough. I don't know if we we I forgot if we did one of those, an episode of one of those, but there's a feature request to be able to update, you know, the locked system fields because some people are rightfully so saying, I don't use a description field on files. Can I just delete it? And I'm like, no. Right.\u003C/p>\u003Cp>Not at the moment.\u003C/p>\u003Cp>Speaker 1: Well, I think it was that was actually a permissioning thing. They wanted to be able to not show it. Right? Be able to deselect that as a visible option to the user.\u003C/p>\u003Cp>Speaker 0: That should be fine.\u003C/p>\u003Cp>Speaker 1: So that there there were some key things there. That was actually related to the permissioning. I remember that one because that was I was like, oh, you can't. Different description. There\u003C/p>\u003Cp>Speaker 2: are there\u003C/p>\u003Cp>Speaker 1: are things that you can't remove from the user view. Right? So, again, we do lock the fields, and I think we should we should allow it to have these. But on the access policy side for that particular one, it was, you know, if I'm in the content manager policy here that\u003C/p>\u003Cp>Speaker 0: called app access permission set has you can see your own user, but then that c includes some of those system fields that you may or may not care about. That's Yep.\u003C/p>\u003Cp>Speaker 1: Yep. Yep. So that was all related to this of, you know, if I'm in my directest users on the permissioning side of the app and those kinds of things in the read permissions here. Yeah. Custom coming down into the field permission, I can't deselect.\u003C/p>\u003Cp>So if I don't want to show, you know, the location of the title or the description, because we're not using them or whatever. There's only certain things you can deselect from the key fields.\u003C/p>\u003Cp>Speaker 0: So Yeah. No. That makes sense. That makes sense. That was a little bit.\u003C/p>\u003Cp>Speaker 2: Let's not get I\u003C/p>\u003Cp>Speaker 0: I recognize how bug big of his detour this is from what we're talking about. But\u003C/p>\u003Cp>Speaker 1: I guess the other thing that would be nice, the the one thing that our our locks currently prevent is, like, reordering the fields. Right? So, like, we stick the roll and some of the configuration details at the very bottom. Well, what if I wanted to roll up at the top in the item form to see it Yeah. In in a certain way?\u003C/p>\u003Cp>Speaker 0: I think our founders sells the topic for the next one of these.\u003C/p>\u003Cp>Speaker 1: Yeah. Sometimes. But back to file delete. What was I taking notes on? Larger configuration.\u003C/p>\u003Cp>Speaker 0: Now here's another very real question. I know there's, of course, enough upvotes for us to warn discussing this, but there's also a very real question of, is this something we want? Like, the whole flow of warning people for a cascade delete and doing it one way as per the database the way we do it now. Sure. That that feels like an obvious one.\u003C/p>\u003Cp>That that part, obvious to me. But this one is interesting where it's like I deselect a file from a relationship. Do I wanna be able to delete the file, or is that confusing?\u003C/p>\u003Cp>Speaker 1: For content user for the user experience, yes, I would like that option because the user doesn't want to the the user workflow wouldn't necessarily be I now have to go to the direct to file library, find that file. Once again, how do I find the file? Do I remember the file name? Do I do those things? How do I go and find and now delete that file?\u003C/p>\u003Cp>That I think is the the key thing from a content editors perspective. Yes or no?\u003C/p>\u003Cp>Speaker 2: Yeah. I'm I'm thinking about 80, 20\u003C/p>\u003Cp>Speaker 1: here we have to think about, but from a content editors experience, right, we find it we all find it very annoying if I have to go do 3 more steps to go delete something. Right? If I have to go now, remember to go back to the file library, go search and find the file, and then delete the file, only to find out that the file can't be deleted because it is being used. Or Right. Accidentally now not know that deleting the file has now removed it from some place that I didn't know about or didn't even have access to.\u003C/p>\u003Cp>That's the other permissioning adds another level of complexity to this. Right? So my ability to delete that file, well, it might be in use somewhere else. And that's another reason I think we shouldn't show the items or try to show items necessarily because they may not have access or permissions to where that file is being used. Mhmm.\u003C/p>\u003Cp>And so you get back to the concept of, well, how do I, you know, how do we deal with that? What do we what do we allow or not allow? I think it's a nice workflow, because commonly, right, it's not so much that we're I I think in most of these kind this this particular use case. Right? The file is only being used in the record that it was uploaded for, you know, you know, it's a gallery.\u003C/p>\u003Cp>It's something that they're doing in the, you know, the content users adding that for that specific thing. And then when they're done, they just want it cleaned up. We don't wanna have gigabytes of files laying around in our file storage and in our file systems that we're not using. Mhmm. Two questions.\u003C/p>\u003Cp>Just a thought.\u003C/p>\u003Cp>Speaker 0: One one thought. Two questions. One technical interesting difficulty is nested relational staged changes. As in, if I'm on an item where the file field is required and I choose to delete the file instead of deselect, is that file immediately deleted, or is that file only deleted the moment I hit save on the parent that I'm clicking the delete on? I think that is that is a question.\u003C/p>\u003Cp>And that is mostly around if you're in content versioning, for example. Right? And you make a new version of an existing thing and it uses the same file. If I click delete the file in the version, I now destroy the published one. You know what I mean?\u003C/p>\u003Cp>So that file should only be deleted the moment I publish the staged versions item. I think that's an interesting interesting little problem. But then how is that presented in the UI? Because if you have marked the file as deleted and then you select a different one, do we keep that as a state? Do we show a little indicator that you have 5 things scheduled to be deleted?\u003C/p>\u003Cp>Or how does that work? I think that's a difficult question. And then\u003C/p>\u003Cp>Speaker 1: That's how we're doing it. So that's how we do it today. Right? So we do show that indicator. Right?\u003C/p>\u003Cp>So if you go to I have that will work for that. On most of our relational kinds of things, some of the relational interfaces, we do indicate that you are deleting and adding. Right? So we're removing this. Right?\u003C/p>\u003Cp>We have that indicator there. We don't actually delete until you commit the record. Right? We don't actually propagate any of the changes until we\u003C/p>\u003Cp>Speaker 0: I'm I'm supposed to think of it right in a in a file picker, a deselect and a and a delete is very similar. You deselect with the intent to select a different one. Right? But if I deleted with the intent of selecting a different one, now I'm effectively presented with 2 changes that I made. We don't really have a UI pattern for that, yet, which is something what was it to think about when I left the ad.\u003C/p>\u003Cp>It's just like a regular drop down. It's all the same same problem. The second thing that popped to mind, and this is a bit of a bigger just think out loud type of thing, would it make more sense for a use case like this to make your own custom direct these files collection where there is no relationship to direct to files. There's a relationship just directly to the file. So you would have to store some of the required fields for that to work, like where is it on disk, what disk is it on.\u003C/p>\u003Cp>Is that a thing? Because technically speaking for direct test files, the only required columns to turn that into file management would be what adapter is this on and what is the the file path to find it. Everything else is is metadata that we use to enrich the platform, but not necessarily required to do file management.\u003C/p>\u003Cp>Speaker 1: Good. Then you've got to handle I mean, again, some of the key issues that we run into, right, with how does the file when and where does the file get uploaded? How is that managed? Or are you assuming that the file exists on that file system? Right?\u003C/p>\u003Cp>The the file interfaces do a whole lot of or the APIs. Right? The direct to these APIs do a whole lot of things for you. And we've, you know, some of those new enhancements around file streaming and restarting where you left off. And, you know, these capabilities, when you're dealing with files, it gets, you know, there's a lot of complexity there.\u003C/p>\u003Cp>And I don't think a lot of folks are gonna want to take that on as a I when I wanted to manage a custom extension that's doing these things for me or, you know, replicating the capabilities of the direct to SAP application. Flows is an option. Right? So that is something that there's actually a link. Someone else put a link in here on how they kind of configured a flow to do some of this.\u003C/p>\u003Cp>Speaker 0: Right. Right.\u003C/p>\u003Cp>Speaker 1: Down here. So this thread here, there's actually an example of a flow. Right? So we do have on hook. You can action based on file upload, based on item update, create, delete.\u003C/p>\u003Cp>So you can apply whatever custom logic. I think the main issue there is you don't get a user prompt per se in those cases.\u003C/p>\u003Cp>Speaker 2: I have I have another probably probably a bit of side of like, side topic idea. That like, not not side topic, but, what is it called? Going outside of the the main road. We could have something like reference counted tiles where it's like, okay. This file exists as long as there are any uses of it.\u003C/p>\u003Cp>And when there are no uses of it anymore, it automatically gets deleted, which then we could also look into something where it's like, okay. If I upload the same image twice, we do, like, a hash of the image to compare if we already have that file somewhere, and some fancy fancy things, which in the end should just make it easier to manage all these files. Like, with 500 people uploading separate files, you get the files collection in, like, a giant amount of people having stuff there. And, like, a reference counter thing could just make it a lot easier to manage all these different file or, like, deduplicate files and get rid of, like, unused ones because that's a thing I've run into even by just myself using directors.\u003C/p>\u003Cp>Speaker 1: Mhmm. Yeah. When you don't have direct file store access, which many times in SAS slash cloud slash whatever.\u003C/p>\u003Cp>Speaker 0: Very interesting to start. So my brain is immediately in 12 places with that comment.\u003C/p>\u003Cp>Speaker 2: But it's the\u003C/p>\u003Cp>Speaker 0: an additional piece of functionality around relational data files and otherwise is the show me where the stuff that is not used anywhere.\u003C/p>\u003Cp>Speaker 2: I think it's a very Yeah. That's a good point. Yeah.\u003C/p>\u003Cp>Speaker 0: Right. And this is something on on a layout level where it's like, okay, filter down by stuff that is not used anywhere else, which is, it does make me think of a comment that was on the chat a little earlier from our our own team that was like, hey. I'm already looking forward to the technical complexity of tracking references within text and JSON blobs in a barrel. Right? Which is very, very, very, very, very, very, very, very, pretty true.\u003C/p>\u003Cp>But\u003C/p>\u003Cp>Speaker 2: Yeah. And in that case, it definitely has to be restrained to things that, again, we can, like, check where it's, like, on JSON blobs or, like, repeat us. That will be very, very difficult and probably not feasible. But at least we, like, at least at least we make the option to if you want to have a feature like reference counted files, then there is a way to have it easily and without any manual labor, basically. You could still do a repeater, but then you won't have the fancy it's basically like the idea of a repeater.\u003C/p>\u003Cp>A repeater, you can slap on really quickly to have just any list of data, but it's nothing fancy. You can't fancy query that. I mean, now you can, but a long time\u003C/p>\u003Cp>Speaker 0: you couldn't.\u003C/p>\u003Cp>Speaker 1: Alright. Are we approaching a what do we think is actually achievable? What we would actually like it to do?\u003C/p>\u003Cp>Speaker 0: Oh, what do you want? I love it. I'm I'm still a little bit in two minds of this whole going doing doing for keeping strange whole place. And and the main reason there is because it kinda strays away from the database as the source of truth for this stuff, which could be a good thing because it unlocks other things, but it's quite a big breaking change in how we handle relationships just in general. Right?\u003C/p>\u003Cp>Because right now, foreign keys and direct relations are 1 to 1 the exact same. And we're reaching a point now with this where we're saying, well, we'll use foreign key constraints on the database for performance reasons because they're they're indexed, but we will not rely on them for this sort of behavior on foreign key changes. So, like, for things like, I wanna delete the related thing when I deselect the current thing, that is not a database thing anymore. That's the directest thing. We're just fine.\u003C/p>\u003Cp>It's just a little bigger change.\u003C/p>\u003Cp>Speaker 2: Or not, don't we have to anyways implement it in the future on the server side and not the database side on these constraints? Because when no supporting relations between databases, we can't have that anymore anyways. So we\u003C/p>\u003Cp>Speaker 0: Great.\u003C/p>\u003Cp>Speaker 2: Have to implement it ourselves anyway. So it's just on the road anyway. Yeah. Just a thing you have to pick up and then do, which is not as easy as it sounds. But Mhmm.\u003C/p>\u003Cp>Speaker 0: So with that in mind, I think some of the stuff that we talked about around, you know, warning and informing the user when a form key constraint is about to delete a bunch of stuff or set null to a bunch of stuff. I think that's an obvious thing. Definitely, it's something we wanna have. That would be a big quality of life improvement. I think doing the relationship the other way around, I think if something happened, it'd probably be a longer term thing just because it is a very big breaking change and how we handle relationships today that I wanna do a bit carefully and just more more planned out.\u003C/p>\u003Cp>The whole idea around custom tables for direct to files, I'm not feeling that one. I think that was a oh, you know, a bit of a brain fart. Just thinking that wrong. That's what these specials are for, but it doesn't feel like the right move right here. Because of all the the system logic that's going on under the hood, we we have to keep that in in control.\u003C/p>\u003Cp>What else was on the was Jonathan? You've been taking notes furiously. What am I missing?\u003C/p>\u003Cp>Speaker 1: I'm trying to keep up some of the workflow options, relationship existence, tracking kind of graph style or being able to understand the that was one thing that Nils mentioned just from a UX perspective. I think that's that almost feels more like the admin side and the data model having ERD style visibility and understanding that, oh, there is a relationship to files from x number of collections and being aware of those things. Taking it away from, you know, embedded inside of rich text or repeaters or weird things, but just the actual ERD, the understanding the graph of what is actually related to my content. From an admin perspective, that would be useful. I do really like the idea of at least understanding files is one of the most common things that I see around this, but we can also think, I was talking to Alex and, Antonio on our team this morning.\u003C/p>\u003Cp>They mentioned that, you know, many to any is another one that has this kind of weird thing where there's not an actual relationship. We do manage that in app. It applies to many to any though in the sense of I can go delete a component that might actually be in use somewhere and you don't get a warning of, hey, this is, you know, you you're you're impacting other things, or impacting something.\u003C/p>\u003Cp>Speaker 0: Deleting it from the relationship. You're not deleting the related item as of today rather. Like, that would be a similar to your point though. That's a similar thing with this feature request where if we add delete as a proper delete the related thing, then you're in a whole new world of how do you display that and how does that work? Does that happen to you sync or do the hood or yeah.\u003C/p>\u003Cp>Speaker 1: And I think a lot of this is probably considerations that need to be handled as part of, you know, the new abstraction layers and things where, as Nils mentioned. Right? Longer term, this is not going to you know, as we move to data federation next year, we're gonna need to be able to handle these things as Directus. Right? Understanding that now it's not just it's data in 2 different databases, right, that we've created a virtual relation for.\u003C/p>\u003Cp>We need to understand and track, I think, against I I think as you've said, isn't just a files thing. This really becomes a more kind of global direct us handling logic around how content can be connected to one another. Right? I'll take relationship out. It's just it's connected.\u003C/p>\u003Cp>It's there's there's some form of tracking that needs to be maintained. And I think as as you said, one of the problems that we have today is, well, if someone's doing stuff direct sequel, you know, we try to support all of that and make sure that we're aware of that. But I think as we move towards, you know, as you move towards something like this, well, if you choose to create or do things under the hood, you may not get them. It's the same thing that we do with activity and revision logging. You're not gonna get that.\u003C/p>\u003Cp>If you're doing something outside of the APIs, you don't get those benefits that exist within the Directus application. Now it could be that there's ways to crawl and find that they've done something and add that or indicate that there's something that then needs to be configured. But I think as we move towards Directus doing some of this logic in the abstraction layers, it's going to require that we handle these use cases in a in a comprehensive way.\u003C/p>\u003Cp>Speaker 0: Mhmm. Cool. Well, I think that probably concludes our our little discussion here around feature request 17 853. Any other last closing thoughts here, Neil's, Jonathan? Nope.\u003C/p>\u003Cp>Awesome. Well, cool. Well, thanks everybody for tuning in. As per usual, this will be up on direct us that a o slash TV. I hope you tune in next time about something else.\u003C/p>\u003Cp>Interesting, I'm sure. But until then, thank you for watching. Like and subscribe.\u003C/p>\u003Cp>Speaker 1: Subscribe. Thanks, team. Get in. Cheers.\u003C/p>","Welcome back, everybody. Welcome to another request review. We have a very special guest here today. Welcome, Niels. He's 7 of our usual host, Daniel of the day. Jonathan, what are we gonna be talking about? Today, we are going to talk about discussion number 17, 853. That is going to be about My favorite. File deletion and management. So this is primarily around the relational, file deletes. If you delete a file from a record or you delete a file from the file system or from the direct to files library, what are some better options for managing that relational delete. So currently, we do a do not delete on the file. It's kind of the default configuration. There are some cascading rules and things you can configure in some cases. But because files can be associated with so many different collections and records, this particular request is around, are there some additional options or features that we could add around improving that file management? Right. So that's the that's the general I'll drop a link just in case people didn't get it. Yeah. So to kick that out right away, the, the important thing to note here, of course, is that direct to files, you both have this sort of, you know, physical file on disk, and you have a row in direct to files, the system table that contains additional metadata we cannot store on the file itself. Right? So think about, we store information about, the some of the exit data for easier retrieval. We store, things like width and height, file duration for for movies, I think, and audio files. We have some additional fields, focal points. Yeah. Exactly. Some location text, some optional metadata that's human configurable. And, of course, some information about what direct this user created, updated, and modified it, whatever. So we have a record in the relational database in the system stuff for for more information. So it also means that when it comes to automatically deleting those files, what we're talking about here is effectively a, you know, sort of cascade delete or a cascade update whenever that relational record is getting destroyed. Right? So from a usual database management perspective, this is a very standard task thing where it's like, okay. The ID of the file gets removed. I want there any record that uses it to be destroyed as well. Let's do the other way around. Right? The the foreign key gets removed, destroy the file. Now in this feature request, what which way is it going? Because I believe it's saying that they wanna delete the file when they delete the record where it's used rather than the other way around. Right? Yeah. In this case, yes. They've mentioned it both directions or it's mentioned somewhere in here. But if you're deselecting or removing an item from a a record association. Right? So if you've got something simple like articles with a file associated, one of the option requests discussed here is if I delete or remove the file from here, that the user either automatically deletes the file from the file system, removes it from direct to files, ideally cleans it off the drive. But alternate options were to actually prompt the user for, do you wanna delete the file? And if yes, go ahead. Yeah. Lots of complexities that come with all of that. Right? Because file the file could be in use by another record. The other big thing with files, because files can be embedded inside of things like WYSIWYSIWYSIWYGs and block editors as relational. Right now, and this isn't this isn't necessarily a direct to specific issue. This is a SQL issue. Right? Unless you're maintaining dual relationals all over the place with everything related back into the file system or some mechanism to track because files can be associated with any number of collections and be embedded inside of rich text fields. How do we manage or understand those kinds of things as well? So there's a a number of factors, I think, that make this complex. But for now, at least what they're asking for is if I delete the file from the record, automatically delete the file or prompt the user, with an option to keep or delete the file. So it's an interesting one there because the so so both those points, the first one to your point, this is this is a problem that has been as old as any sort of content management system on the planet is if you have a link to a file in a piece of text, is that a relational record? No. Is that a relationship in a database you can easily track? Also, no. So now on file delete, are you gonna be scanning through all of those blobs of text all over the place to sort of pseudo find relationships that is hella inefficient? Right? So how do you deal with that? That's that's a good one. The second one that is interesting is that this is kind of the going the wrong way, so to speak, if you compare it to how regular relationships work in a database. Right? So usually, when you say when you do a cascade delete, it would be the moment you delete the file, you delete all of the rows where it has been used in a foreign key. Am I saying that right? Or am I making this up? I was getting too confused, to be honest. I think it goes the other way because the foreign key, at least in that case, like in my article case, the foreign key reference is actually here on this record. So we actually store the foreign key. So I believe the cascade is actually going the other way. So if I delete it from here and I tell it to cascade, it should cascade and delete the file. And I believe that actually does. So we can actually double check the settings, article because we do some article in both ways in direct as I was just trying to remember if I wrote like myself which way the default is. So the relationship in this case is directional from direct as follows. Right? It was the rate that I said. It's like the moment you delete the file, you get to choose what you wanna do, with the forward key field. Right? Do you wanna nullify it, or do you wanna destroy the whole row that uses that forwarding key? So so that's why I meant with sort of like the feature request going the opposite way. Right? Because by a database and default, you're saying, okay, the moment you delete the file, delete everything where the file is used. But it feels like this feature request is going the other way. Right? They're saying the moment I deselect the file from a gallery post or something, I also want to trigger a deletion of the related file. Yeah. Yes. Key. So now you're actually you are actually correct. It does go the other way. So if you delete the file, it's actually cleaning up the foreign key, right, is what we're technically do. Yep. My mistake. So this and this is welcome back to the beauty of request review. If you haven't been here before, we always like to diverge as much as we can before we come back down to the notes at the top of the hour. The immediate question to me here becomes, is this a file specific thing, or is this just a directed data thing? Right? Is this something that you should be able to set up for everything where you're like, okay. The moment I I delete this record or deselect this relationship, I wanna be able to remove the thing on the other end. Is that a thing that we just wanna support as a more generic option or is this something that is inherently specific to files? Because it kinda sounds like that this is that this person was mentioning files just because that's the use case for this particular person and this website that they're building. But I could see this as be a relationship thing. Yep. At least implementation wise, it's like equal, I would say. There should be no diff like, no technical difficulties to make it more advanced in a sense or more capable. Yeah. No. I actually like that. I I think, especially as we move towards, you know, our our our future concepts of we want to support non sequel kinds of things. This means, to some degree, direct us needs to understand where things are being used and keep track of that so that otherwise, we can end up with a, you know, an even bigger mess. Right? Sync beyond files to records to data and content. I don't I've been trying to think about this because this comes up quite a bit. There's there's also things like one of the things that I've seen a number of times recently is, can I tell what the file is associated? Can it can can you show me what else you know, where is this file being used? Right? So that comes back to in particular, this is problematic for things like where it's embedded as a text, you know, inside of a rich text. My brain goes, how do we we would have to, in some way, keep track of the relationals as part of Directus. Because I did some searches on, like, SQL databases. How can you do this in c e? Yeah. It's not really you you would have to pull up what are all of the foreign key constraints that go back to this table and then go search through all of those tables to find foreign keys with the ID, I guess. That's really the only way to do it. Yeah. It is. And you can do some view things. You can do but you have to you know, it's it's complex. It's not something that's just simple to say, where is this? But if Directus in some way was actually keeping track in some way of, you know, think of some kind of an indexing or a mechanism of keeping track that when it gets associated, we track that it got associated in some way. Right? Call it a table. Call it a The the difficulty there, of course, is that data could be live updating through all sorts of sources that's not direct us. So how do we keep that index up to date? Or is that something that we have to periodically re scrape to regenerate, which sounds tricky, or tricky to keep that, you know, consistent. Keep that keep that data integrity alive. This is also a feature request that immediately reminds me of be because of this connection, it reminds me of the one around, how do we warn people, about where stuff is used when you delete it? Because right now, you can set up the form keys to nullify a file, but if somebody deletes a file, they might not know where they're gonna be nullifying things automatically. Right? It's a very similar, where is this being used question except during delete. Yep. And that's the that's the common request is I you know, at least I would like to know where this, you know, where this thing is where all this thing is being used. You know, what what all is it associated with in that sense Yeah. For tracking it down? Because if I yeah. You know, I wanna understand the impacts of me deleting a file or me deleting a record, what are the Right. Relational impacts? Now looking up all those foreign keys is a pretty heavy thing. But in Directus, we do store that relational information already. So we should have the ability to say what are the relationships that have this collection in it, and then do a sort of aggregate search that says, okay. What is the count of items that have a foreign key to this item? Which should be a relatively e like, not easy, but a cheap operation to do rather. I mean, it depends on table size. There's always an asterisk, but we could, you know, do a what's the kind of items that are using the current primary key as a foreign key in the, related tables and then present that as well, right, where we say, okay. We know, this collection is being used in well, in this example's case, direct this files is being used in, photo albums. And therefore, we can say, when you delete this file, you're gonna set it to null in these in 3 different photo album records. Right? Is this something you wanna do? Yes or no? So at least be a little bit more helpful about that. Yeah. I really like the idea of, like, having a Oh, sorry. Oh, no. Go ahead. Go ahead, please, dude. Yeah. I really like the idea of having, like, a graph view. Like, just in general, that would show you, okay, this would be deleted. This would be, like, nullified. This would be this this in-depth, that happened with on a delete. And, like, the data is already there in the API in the app. We just have to then visualize it with, like, a graph view or a list of things that get deleted, a list of things that get nullified. We aren't we kinda doing something with creating when creating, for example, relational stuff, we already say what we create. Like, do you know this yellow text list that we have on the data data model creation? We can just do the same for the deletion process, basically. If you delete an item, go through the whole schema of relations and see what links to what, and that's basically just recursively checking against each nested collection. And the fancy part then would be how to visualize this. And in in terms of, like, do we run it in a list? Do we run it in a fancy graph where it's like, this collection links to that collection, and this field in that collection would then delete another collection or something like that? Or would we just run it as a list very stupidly? And to make that one slightly more complicated, what do you do if there is user input required? So, for example, if the default cascade is make it null, but the field is not nullable, then what? Right? Are we gonna Then you get an escape. Are we gonna tell them you cannot delete it because it's in use, Or are we gonna tell them, what do you wanna do with the 5 places where you're using this? You wanna replace it with something else? And is that something we wanna do in line? Or is it enough if we sell if we just say you cannot delete it right now, go fix the other stuff first? Like, which is also, you know, a flow that would be enough. I don't know if it's as useful. Yeah. I think at least indicated that it exists somewhere and then saying, go clean it up before you can actually delete the file. That seems okay. You could give the option to say nullify where I'm at or place with something else where I'm at. Interesting. Interesting. I'm I'm also wondering, is it is it is it not really, like, configuration error if you set the relation to nullify something that can't be null? That sounds like somebody has messed up things in that case, which we should also protect people from doing. But Fair enough. Yeah. That that is that is fair. But the the default behavior for foreign key like that is to prevent the deletion, I think. So even if you don't set it to set nil, but you just leave it at the default, which is prevent the deletion, it'll just throw an error. Because I throw right now, we don't throw a SQL error that says I cannot delete form keeps Yeah. Exactly. And then we should probably even, like, protect when setting up the relations that you shouldn't be able to set it to nullify something it can't be nullified to. Yeah. But I think it's all the settings. Even the the mistake setup and the the default case. There's a case to be made that we wanna have some sort of user input moment in during the delete that says, okay. We're gonna be either nullifying if that's the setting, or we're gonna try to nullify if that's the setting, across 15 items in your your 12 collections. Or if it is a, prevent the deletion, the question could be, do you wanna replace where this is used with something else before you can delete it? Right? That would be a pretty helpful thing. I know we're getting a bit of trend for this particular feature request, but these are all kind of part of the bigger part of the same, sort of questions and user stories. Agreed. And, again, I think he's got he's got some of those cases covered. They they've got some of those cases covered here. Right? So they know to delete the file, keep the file, prompt the user. I must delete it in the collection. Well, to to get it back on track for this particular feature request though Yeah. Because the what we just described is, you know, if you wanna follow just a regular foreign key constraint, and we wanna inform the user of what's about to happen, that's part 1. We wanna allow them to take some action if they have to make some changes for it to go through. But then the third one, and that's the new thing in this feature, requested the question, do we wanna do it the other way around as well? Where unlike in a database, we allow a secondary foreign key constraint type of thing where we say, if you delete the the the record that holds the foreign key, delete the related thing. And that then has a sort of recursive compound effect where it's like, do we now show any other foreign keys that might exist on the thing that you're deleting through the foreign key that you just deleted? What? Yeah. I think that's probably one of the reasons why, you know, databases don't sort of recursive, like, have that way of doing it both ways because that really feels like, you know, you're you're quickly ending in a in a in a sort of infinite loop type of deal. Yeah. And that might be where maybe you don't show them that. You just simply know that is still being so if they choose, say, the delete option to say, you know, I do wanna delete the file, or the the record in this case, then you could provide an indication that there are existing relationships. Are you really sure? And then it'll affect those other you know, it will affect other things, you know, and number of other things or just the fact that it exists, that it is actually related to other active items. So instead of and not try to show them what all because that could be a large number of things. I don't know that you'd want to try and show that in a dialogue box, but you could show this is related to any number of other things or this is related to other things. And therefore, you know, this could have catastrophic effects. Yes or no? And maybe even making an option that, you know, a toggle config flag or something on the settings of that says, if this is still related to other things, then they're not allowed to do that from a permissioning standpoint kind of thing. Then, you know, the option is, no, you can't delete this because this is related to other things. Go to the source record and clean it up and do whatever. Right? The whatever workflow. So I think you can go that route, maybe. On another note, I'm also wondering if we should that it's it goes in a similar direction, but, like, protecting the users from making mistakes, would be like a feature where you have a protected collection, that basically says, okay, you have to, for example, enter the, the name or ID or some type of validation before you can actually delete the, the item in the collection. For example, if you're managing users and you don't want to mess up have, your managers mess up the user's collection because that could be catastrophic or something similar, where they would have to then, for example, enter something. And that would also tie into this, like, what happens on the delete part where it's like, okay. This collection is related to other collection that is protected, and we should also, in this collection, mind you that you're deleting something from another collection that is protected. Right? Yes. Yes. Yes. Yes. This old man now this makes me think from a technical perspective. We're gonna dive a little deep here. But from a technical perspective, this makes me wonder right now, We rely on the database foreign key constraints for all this. Right? That we say, okay. You said it's a set null. That is literally a database foreign key index with a cascade set null. Right? Yeah. But that also means that from a Directus perspective, we're not triggering any logic or hooks or or anything necessarily on the Directus side for those nested deletes because we're just relying on the database to do it. Right? Which is a technically performant way, but at the same time, that does raise newer questions around, you know, if you have a flow that handles something on file, delete to clean something up. Right? And that file gets deleted through. Well, I guess a file is actually a bad example, ironically enough, because it's on the disk and not on the database. But if you have a flow that cleans up something, on a database change, but it is changed directly from a foreign key constraint that changes it. We're not triggering it as an event. Right? Yeah. I think that was also one of the problems a lot of people had with working with flows that it wasn't, like, cascading these, like, deviate events to, to flows, basically, I think, which would also solve that problem in a sense, I think. Although, I don't remember exactly what the problem there was in detail because it's quite a long time ago, which where I had read through these issues. But I do still like the idea of, like, this this type of protected collection. I I do think that could I'm not sure. I haven't seen many press on that idea, but I do think it could be a nice enhancement just from on the side of, like, making sure you don't do anything. But, I mean, aren't we doing something sim I guess, no. We're not. But, for example, on the director's collection, you could technically delete those from the app. Right? But we somehow oh, oh, at least Yeah. No. In a sense, we also do some sort of protection there because, like, yeah, sure. You can do that technically, but you really shouldn't. No. No. I'm pretty sure we're we're preventing any any direct to stable modification from the product itself. Yeah. Yeah. I mean, you can add custom fields and remove those, but you cannot mess with the the system ones, which I think is a separate feature request, actually, funnily enough. I don't know if we we I forgot if we did one of those, an episode of one of those, but there's a feature request to be able to update, you know, the locked system fields because some people are rightfully so saying, I don't use a description field on files. Can I just delete it? And I'm like, no. Right. Not at the moment. Well, I think it was that was actually a permissioning thing. They wanted to be able to not show it. Right? Be able to deselect that as a visible option to the user. That should be fine. So that there there were some key things there. That was actually related to the permissioning. I remember that one because that was I was like, oh, you can't. Different description. There are there are things that you can't remove from the user view. Right? So, again, we do lock the fields, and I think we should we should allow it to have these. But on the access policy side for that particular one, it was, you know, if I'm in the content manager policy here that called app access permission set has you can see your own user, but then that c includes some of those system fields that you may or may not care about. That's Yep. Yep. Yep. So that was all related to this of, you know, if I'm in my directest users on the permissioning side of the app and those kinds of things in the read permissions here. Yeah. Custom coming down into the field permission, I can't deselect. So if I don't want to show, you know, the location of the title or the description, because we're not using them or whatever. There's only certain things you can deselect from the key fields. So Yeah. No. That makes sense. That makes sense. That was a little bit. Let's not get I I recognize how bug big of his detour this is from what we're talking about. But I guess the other thing that would be nice, the the one thing that our our locks currently prevent is, like, reordering the fields. Right? So, like, we stick the roll and some of the configuration details at the very bottom. Well, what if I wanted to roll up at the top in the item form to see it Yeah. In in a certain way? I think our founders sells the topic for the next one of these. Yeah. Sometimes. But back to file delete. What was I taking notes on? Larger configuration. Now here's another very real question. I know there's, of course, enough upvotes for us to warn discussing this, but there's also a very real question of, is this something we want? Like, the whole flow of warning people for a cascade delete and doing it one way as per the database the way we do it now. Sure. That that feels like an obvious one. That that part, obvious to me. But this one is interesting where it's like I deselect a file from a relationship. Do I wanna be able to delete the file, or is that confusing? For content user for the user experience, yes, I would like that option because the user doesn't want to the the user workflow wouldn't necessarily be I now have to go to the direct to file library, find that file. Once again, how do I find the file? Do I remember the file name? Do I do those things? How do I go and find and now delete that file? That I think is the the key thing from a content editors perspective. Yes or no? Yeah. I'm I'm thinking about 80, 20 here we have to think about, but from a content editors experience, right, we find it we all find it very annoying if I have to go do 3 more steps to go delete something. Right? If I have to go now, remember to go back to the file library, go search and find the file, and then delete the file, only to find out that the file can't be deleted because it is being used. Or Right. Accidentally now not know that deleting the file has now removed it from some place that I didn't know about or didn't even have access to. That's the other permissioning adds another level of complexity to this. Right? So my ability to delete that file, well, it might be in use somewhere else. And that's another reason I think we shouldn't show the items or try to show items necessarily because they may not have access or permissions to where that file is being used. Mhmm. And so you get back to the concept of, well, how do I, you know, how do we deal with that? What do we what do we allow or not allow? I think it's a nice workflow, because commonly, right, it's not so much that we're I I think in most of these kind this this particular use case. Right? The file is only being used in the record that it was uploaded for, you know, you know, it's a gallery. It's something that they're doing in the, you know, the content users adding that for that specific thing. And then when they're done, they just want it cleaned up. We don't wanna have gigabytes of files laying around in our file storage and in our file systems that we're not using. Mhmm. Two questions. Just a thought. One one thought. Two questions. One technical interesting difficulty is nested relational staged changes. As in, if I'm on an item where the file field is required and I choose to delete the file instead of deselect, is that file immediately deleted, or is that file only deleted the moment I hit save on the parent that I'm clicking the delete on? I think that is that is a question. And that is mostly around if you're in content versioning, for example. Right? And you make a new version of an existing thing and it uses the same file. If I click delete the file in the version, I now destroy the published one. You know what I mean? So that file should only be deleted the moment I publish the staged versions item. I think that's an interesting interesting little problem. But then how is that presented in the UI? Because if you have marked the file as deleted and then you select a different one, do we keep that as a state? Do we show a little indicator that you have 5 things scheduled to be deleted? Or how does that work? I think that's a difficult question. And then That's how we're doing it. So that's how we do it today. Right? So we do show that indicator. Right? So if you go to I have that will work for that. On most of our relational kinds of things, some of the relational interfaces, we do indicate that you are deleting and adding. Right? So we're removing this. Right? We have that indicator there. We don't actually delete until you commit the record. Right? We don't actually propagate any of the changes until we I'm I'm supposed to think of it right in a in a file picker, a deselect and a and a delete is very similar. You deselect with the intent to select a different one. Right? But if I deleted with the intent of selecting a different one, now I'm effectively presented with 2 changes that I made. We don't really have a UI pattern for that, yet, which is something what was it to think about when I left the ad. It's just like a regular drop down. It's all the same same problem. The second thing that popped to mind, and this is a bit of a bigger just think out loud type of thing, would it make more sense for a use case like this to make your own custom direct these files collection where there is no relationship to direct to files. There's a relationship just directly to the file. So you would have to store some of the required fields for that to work, like where is it on disk, what disk is it on. Is that a thing? Because technically speaking for direct test files, the only required columns to turn that into file management would be what adapter is this on and what is the the file path to find it. Everything else is is metadata that we use to enrich the platform, but not necessarily required to do file management. Good. Then you've got to handle I mean, again, some of the key issues that we run into, right, with how does the file when and where does the file get uploaded? How is that managed? Or are you assuming that the file exists on that file system? Right? The the file interfaces do a whole lot of or the APIs. Right? The direct to these APIs do a whole lot of things for you. And we've, you know, some of those new enhancements around file streaming and restarting where you left off. And, you know, these capabilities, when you're dealing with files, it gets, you know, there's a lot of complexity there. And I don't think a lot of folks are gonna want to take that on as a I when I wanted to manage a custom extension that's doing these things for me or, you know, replicating the capabilities of the direct to SAP application. Flows is an option. Right? So that is something that there's actually a link. Someone else put a link in here on how they kind of configured a flow to do some of this. Right. Right. Down here. So this thread here, there's actually an example of a flow. Right? So we do have on hook. You can action based on file upload, based on item update, create, delete. So you can apply whatever custom logic. I think the main issue there is you don't get a user prompt per se in those cases. I have I have another probably probably a bit of side of like, side topic idea. That like, not not side topic, but, what is it called? Going outside of the the main road. We could have something like reference counted tiles where it's like, okay. This file exists as long as there are any uses of it. And when there are no uses of it anymore, it automatically gets deleted, which then we could also look into something where it's like, okay. If I upload the same image twice, we do, like, a hash of the image to compare if we already have that file somewhere, and some fancy fancy things, which in the end should just make it easier to manage all these files. Like, with 500 people uploading separate files, you get the files collection in, like, a giant amount of people having stuff there. And, like, a reference counter thing could just make it a lot easier to manage all these different file or, like, deduplicate files and get rid of, like, unused ones because that's a thing I've run into even by just myself using directors. Mhmm. Yeah. When you don't have direct file store access, which many times in SAS slash cloud slash whatever. Very interesting to start. So my brain is immediately in 12 places with that comment. But it's the an additional piece of functionality around relational data files and otherwise is the show me where the stuff that is not used anywhere. I think it's a very Yeah. That's a good point. Yeah. Right. And this is something on on a layout level where it's like, okay, filter down by stuff that is not used anywhere else, which is, it does make me think of a comment that was on the chat a little earlier from our our own team that was like, hey. I'm already looking forward to the technical complexity of tracking references within text and JSON blobs in a barrel. Right? Which is very, very, very, very, very, very, very, very, pretty true. But Yeah. And in that case, it definitely has to be restrained to things that, again, we can, like, check where it's, like, on JSON blobs or, like, repeat us. That will be very, very difficult and probably not feasible. But at least we, like, at least at least we make the option to if you want to have a feature like reference counted files, then there is a way to have it easily and without any manual labor, basically. You could still do a repeater, but then you won't have the fancy it's basically like the idea of a repeater. A repeater, you can slap on really quickly to have just any list of data, but it's nothing fancy. You can't fancy query that. I mean, now you can, but a long time you couldn't. Alright. Are we approaching a what do we think is actually achievable? What we would actually like it to do? Oh, what do you want? I love it. I'm I'm still a little bit in two minds of this whole going doing doing for keeping strange whole place. And and the main reason there is because it kinda strays away from the database as the source of truth for this stuff, which could be a good thing because it unlocks other things, but it's quite a big breaking change in how we handle relationships just in general. Right? Because right now, foreign keys and direct relations are 1 to 1 the exact same. And we're reaching a point now with this where we're saying, well, we'll use foreign key constraints on the database for performance reasons because they're they're indexed, but we will not rely on them for this sort of behavior on foreign key changes. So, like, for things like, I wanna delete the related thing when I deselect the current thing, that is not a database thing anymore. That's the directest thing. We're just fine. It's just a little bigger change. Or not, don't we have to anyways implement it in the future on the server side and not the database side on these constraints? Because when no supporting relations between databases, we can't have that anymore anyways. So we Great. Have to implement it ourselves anyway. So it's just on the road anyway. Yeah. Just a thing you have to pick up and then do, which is not as easy as it sounds. But Mhmm. So with that in mind, I think some of the stuff that we talked about around, you know, warning and informing the user when a form key constraint is about to delete a bunch of stuff or set null to a bunch of stuff. I think that's an obvious thing. Definitely, it's something we wanna have. That would be a big quality of life improvement. I think doing the relationship the other way around, I think if something happened, it'd probably be a longer term thing just because it is a very big breaking change and how we handle relationships today that I wanna do a bit carefully and just more more planned out. The whole idea around custom tables for direct to files, I'm not feeling that one. I think that was a oh, you know, a bit of a brain fart. Just thinking that wrong. That's what these specials are for, but it doesn't feel like the right move right here. Because of all the the system logic that's going on under the hood, we we have to keep that in in control. What else was on the was Jonathan? You've been taking notes furiously. What am I missing? I'm trying to keep up some of the workflow options, relationship existence, tracking kind of graph style or being able to understand the that was one thing that Nils mentioned just from a UX perspective. I think that's that almost feels more like the admin side and the data model having ERD style visibility and understanding that, oh, there is a relationship to files from x number of collections and being aware of those things. Taking it away from, you know, embedded inside of rich text or repeaters or weird things, but just the actual ERD, the understanding the graph of what is actually related to my content. From an admin perspective, that would be useful. I do really like the idea of at least understanding files is one of the most common things that I see around this, but we can also think, I was talking to Alex and, Antonio on our team this morning. They mentioned that, you know, many to any is another one that has this kind of weird thing where there's not an actual relationship. We do manage that in app. It applies to many to any though in the sense of I can go delete a component that might actually be in use somewhere and you don't get a warning of, hey, this is, you know, you you're you're impacting other things, or impacting something. Deleting it from the relationship. You're not deleting the related item as of today rather. Like, that would be a similar to your point though. That's a similar thing with this feature request where if we add delete as a proper delete the related thing, then you're in a whole new world of how do you display that and how does that work? Does that happen to you sync or do the hood or yeah. And I think a lot of this is probably considerations that need to be handled as part of, you know, the new abstraction layers and things where, as Nils mentioned. Right? Longer term, this is not going to you know, as we move to data federation next year, we're gonna need to be able to handle these things as Directus. Right? Understanding that now it's not just it's data in 2 different databases, right, that we've created a virtual relation for. We need to understand and track, I think, against I I think as you've said, isn't just a files thing. This really becomes a more kind of global direct us handling logic around how content can be connected to one another. Right? I'll take relationship out. It's just it's connected. It's there's there's some form of tracking that needs to be maintained. And I think as as you said, one of the problems that we have today is, well, if someone's doing stuff direct sequel, you know, we try to support all of that and make sure that we're aware of that. But I think as we move towards, you know, as you move towards something like this, well, if you choose to create or do things under the hood, you may not get them. It's the same thing that we do with activity and revision logging. You're not gonna get that. If you're doing something outside of the APIs, you don't get those benefits that exist within the Directus application. Now it could be that there's ways to crawl and find that they've done something and add that or indicate that there's something that then needs to be configured. But I think as we move towards Directus doing some of this logic in the abstraction layers, it's going to require that we handle these use cases in a in a comprehensive way. Mhmm. Cool. Well, I think that probably concludes our our little discussion here around feature request 17 853. Any other last closing thoughts here, Neil's, Jonathan? Nope. Awesome. Well, cool. Well, thanks everybody for tuning in. As per usual, this will be up on direct us that a o slash TV. I hope you tune in next time about something else. Interesting, I'm sure. But until then, thank you for watching. Like and subscribe. Subscribe. Thanks, team. Get in. Cheers.","b7827b99-c9e6-4cd5-8e67-6331a3670b63",[420,421],"9d8800a8-d3c8-4530-bdee-c67734a7cffc","4497c8ce-8792-4586-b4d1-7df91c3b4b02",[],{"id":133,"number":134,"show":122,"year":135,"episodes":424},[137,138,139,140,141,142,143,144,145,146,147,148,149],{"id":149,"slug":426,"vimeo_id":427,"description":428,"tile":429,"length":430,"resources":431,"people":8,"episode_number":434,"published":414,"title":435,"video_transcript_html":436,"video_transcript_text":437,"content":8,"seo":438,"status":130,"episode_people":439,"recommendations":443,"season":444},"20594","1013663375","In this recording of our live event on September 12th 2024, Nils, Jonathan, and Hannes discuss Field locking and notifications.","18984108-11ac-467c-b8a1-44c264c8dac4",53,[432],{"name":304,"url":433},"https://github.com/directus/directus/discussions/20594",13,"Field Locking and Notifications","\u003Cp>Speaker 0: Let's rock and roll. I think this fundamentally comes down to something that we've been talking about off and on for a couple of years now is the ability to have things like collaborative editing, at least some level of notification somebody else is working a record as our as we all as as we all here know very well that it's a first save wins at the moment, and you have no idea if anybody else is editing a record that you happen to be editing. Generally, it works out. I don't think it's a frequent occurrence, but it's probably it is something that I think we would all like to see solved. And I'm hopeful that I think I see BrainSlug is in the audience as well.\u003C/p>\u003Cp>That's good because I think he's actually got a custom extension that actually uses websites to actually do this, for, like, live chat and other things. But I think he actually did something as a test, and we'll we'll get through that. But that's what I think this generally is, and we'll get this thing kicked off. I'll turn it to the brains of the operation, and let's roll through this thing. Shout if you need me to show something or pop over to somewhere, and we'll go.\u003C/p>\u003Cp>Speaker 1: Yeah. Tim is disappearing. Yes. I think\u003C/p>\u003Cp>Speaker 0: this was\u003C/p>\u003Cp>Speaker 1: actually a fairly easy feature request, you know, in of itself if you don't consider, like, all the possibilities you could evolve evolve to. Because in the end, it's just asking for, hey. We need a notification if someone is editing something, and that doesn't really it needs some kind of real time possibility, but it doesn't really need any collaborative editing efforts. It enhances it by already. If you put where WordPress does as well.\u003C/p>\u003Cp>Haven't used WordPress in a long, long time, but I think it had something to do with where I told you, hey. This is, this part is embedded by someone else, which is basically what this feature is asking for, just to give them heads up and just to improve the experience. But I think the author of the Hippo Trust, should also be in the audience. Maybe you can raise your hand or something, say hi, to see what you envisioned there. Oh, yeah.\u003C/p>\u003Cp>There he is. Because I know it's, like, just reading it, it seems like a fairly easy thing to implement and to consider. It just we just need to figure out, like, what are the extended use cases we wanna have with it. Is it enough to show that occasion as a starter? Who we able to wanna evolve it into collaborative editing and all of that?\u003C/p>\u003Cp>Because we already had a discussion on real time. I think I just went through a couple of discussions almost October last year, so there have been some discussions about that in general as well. And this feels like an obvious feature to merge into that as well. But I see that Uwe, Uwe. So, excuse me for butchering your name.\u003C/p>\u003Cp>He's typing right now, and he has some additional insight that he collected over last year that this feature request has been up and being voted by the community.\u003C/p>\u003Cp>Speaker 2: Yeah. And and to just give a bit more context from what I remember, I think this was, like, in the talks. Like, then when we started, like, working on WebSocket support and stuff like that, that's was, like, one of the, like, key things we looked at for, like, WebSockets and stuff. But as you mentioned, like, it doesn't really necessarily need WebSockets. You could also, like, pull, like, a get request each second in if you would want to go without WebSockets.\u003C/p>\u003Cp>Like, there's always, like, the possibility to implement this. It's just, like, about what do we want to have this as a real scope in terms of, like, we just implementing this is probably there's more to it in the end, basically. There's more we can do, more we can, like, find out before we go implement this feature. And yeah.\u003C/p>\u003Cp>Speaker 1: Also something to consider is can we implement it as an extension? Does it have to be in core, or is it something that could be a presentation interface, for example, which can, utilize the real time WebSocket API to figure out, like, is there anyone else editing it right now, maybe through a system collection or something that, along those lines where you write an item as soon as somebody is there and you kind of keep it alive, had it write a time stamp when it was last visited or something, and then you could figure out based on that if there currently is one editing it. I can certainly see going that route with an extension as well. It doesn't really need to be a core feature even though it could be nice to have as a core feature. Tim said that one thing he recalls about being difficult is that what do you show about the other user if editing, what the other user that is editing it?\u003C/p>\u003Cp>If you don't have the permissions for other users, I think you would just say, hey. There's one other user editing or something. It doesn't really it's nice to have a name and to have a thumbnail and profile picture and all of that, but it doesn't necessarily need it to function in the 1st place, I would say.\u003C/p>\u003Cp>Speaker 0: So that that was the question that I just wrote down is what's considered editing. Right? Is it just someone has the item record open and they have edit permissions, and therefore that's considered editing or they've actually made a change and that's considered editing. Just something that\u003C/p>\u003Cp>Speaker 1: Or step in between is have they focus on input, for example, if like a step towards editing.\u003C/p>\u003Cp>Speaker 2: Yep. Yeah. That's just another thing we, like, probably have to, like, decide on first for something like this could be implemented because that is like a known edge case. And, like, for example, if we would go with the locking route, where, like, an item gets locked if a user edits, then the real important question is, like, with that system, somebody could just, like, lock us, like, an item forever and not release it, and at any point of time in the future, and that would be a big problem because then you have, like, oh, my my colleague from work is not, giving me access to this item right now. I can't do my job, and that that is not an option, really.\u003C/p>\u003Cp>Speaker 1: So RCS, which is an ancient, vision control version control system from, like, the eighties, like, eighties, nineties from Unix. And they have this concept of locking a file. So if somebody locks a file, you're not able to edit it anymore, and you can, like, force unlock a file. So they certainly use that possibility as well. But Right.\u003C/p>\u003Cp>There is always gets overtook this kind of locking approach, where you're trying to negotiate and take these afterwards. I mean, in this case, I think, as well as the author of the PR, feature, I guess, sorry, said the notification itself should be the better option. Also, seems I wanna say simpler implementation wise because both of them kind of require either, some state on the server or requires some, entries in the database. Having the item page feels easier.\u003C/p>\u003Cp>Speaker 0: Yeah. Because you also have so as as Mills mentioned, right, you have the ability to potentially so we got a lock record route then how long do you allow that lock to remain held? And you automatically time it out and just, you know, that person loses their edits.\u003C/p>\u003Cp>Speaker 1: Mhmm.\u003C/p>\u003Cp>Speaker 0: You know? Or is there an admin way to force specific out of whack and now you got a record block that can't be accessed by the users in any way, shape, or form, even the original user that, you know, initiated the lock. So that means we need some admin, ways of managing and releasing force releasing and resetting locks.\u003C/p>\u003Cp>Speaker 1: Oh, Pedro brings up a very good point. We we have relations in directors, so you're not always just editing a single item, but you can basically walk a whole tree of changes and go 7 drawers deep and start editing, items that don't that aren't actually your item page. That is a very good call, which I haven't considered myself so far.\u003C/p>\u003Cp>Speaker 2: That that's yeah. And that in that sense, locking will probably be, like, very difficult to implement because then the question like, the real question is what even do we lock? Not only, like, when do we lock, but how and what and why. So that's way more tricky than just giving you the information of somebody. Like, in a perfect world, we would have to, like, live collaboration that basically solves the problem out of the box, but that's not really feasible, I think, at the moment in the core implementation of our app.\u003C/p>\u003Cp>So, like, some way of not like, not an either a notification bar or, like, a, like, a schedule to request to see if there's somebody editing your current item and then update it or something like that. That would be like a, I would say, trade off between what we can do right now with your time and what should improve the experience by, like, the minimum, at least. Like, the minimum, of, like, to yeah. Basically, to have some way of knowing that somebody is working on this cost right now, there isn't. I mean, I guess there is on the user because the user table has the records on the last edited item.\u003C/p>\u003Cp>So there is currently already the information stored in directors.\u003C/p>\u003Cp>Speaker 1: Well, the last page, which, gets terribly confusing if you have multiple tabs open. Right? And as soon as you start True.\u003C/p>\u003Cp>Speaker 2: In that case yeah.\u003C/p>\u003Cp>Speaker 1: The information gets up because that's a single entry.\u003C/p>\u003Cp>Speaker 2: But that would be, like, I would say, like, a good start to use that information that we already have to work on that week. Although, we if we were to, want to go for it, we could also make it, like, fully fetched then. Yeah. That's, like, that's also true. Yeah.\u003C/p>\u003Cp>Speaker 1: The problem with the last page is, like, it isn't very it it isn't really, like, a secure information on what is the user what the user is currently doing, because they might open 1 page, might open another page, and it not, like, might open the item page and then tab out, go to a different tab, and navigate in there. And suddenly, you lose all the information because it's really only intended as a way to basically bring the user back to the last page they open once they log out and log back in. That is the intention of page, to have like a more fluent experience when you revisit the same director's instance. So using that really doesn't seem like the right option, but Tim linked his experimental, live collaboration interface extension, which live collaboration really is a big word for it, I wouldn't say, because right now it's just a presentational interface that can notify you if somebody else is, working on the same item. And I just peruse that the code, Tim, please correct me, but it seem it seems like it's using our real time WebSocket, and it just sends custom messages over it.\u003C/p>\u003Cp>I don't know if it needs some does, the WebSocket implementation automatically fan it out to all connected clients, or is there some sort of a component as well in there that is necessary? I'm not able to use that one. I'm thinking, like, not while doing that, let's read some chats. Joshua, she's she's it suggests lock timeouts.\u003C/p>\u003Cp>Speaker 0: It's\u003C/p>\u003Cp>Speaker 1: certainly an option, 100%. Still leaves you with the possibility. What is a lock time out? Is it 5 minutes? Somebody might be editing longer than 5 minutes.\u003C/p>\u003Cp>Is it an hour you might wanna add it to an item sooner than an hour after your colleague left? So if we were to go to the lock route, there certainly has to be a mechanism for you. Yes. I'm sure I wanna override this lock. I wanna take the over this page, mechanism kind of.\u003C/p>\u003Cp>Yeah. I'm with, Pedro's on this, notification that is shown once the user starts editing a record should be great, And it's just a simple avatar of as a fallback, as we said, if the user currently editing the item doesn't have any information about other users or something that doesn't have the permissions.\u003C/p>\u003Cp>Speaker 2: Yeah. And another thing I am wondering right now, or thinking about is, regarding where we would want to store that information, who is currently editing what item. We could, like, store it somewhere in the user collection. We could store it somewhere on the item. So what I was thinking, for example, would be a custom interface that basically makes a request to the, API, on, like, somebody opened this item, a request goes like, because interface interface gets loaded, the interface lets the API know that, like, the value of this field gets then sent to the user's name.\u003C/p>\u003Cp>And, others visiting the same page, the basically, the data gets fetched from the API. And in that field will be the name of the current user who's editing that item, and that interface could then display that information. And that would also, like, require no real time WebSocket connections, and that would also be a very straightforward in that sense that it is very similar to the created or updated on or modified on, interface, which, like, could also make this as an extension because then we are not like, we can just flop, I mean, you're gonna have to edit your schema for that feature to work, and it is not like, it is basically an opt in feature in that case. But it would be very straightforward to implement even as an extension, and that could also be another interesting approach to this problem, basically.\u003C/p>\u003Cp>Speaker 1: So, basically, either extending your current items to a user, or you can even introduce a whole new table that is just a, a lookup table kind of, like, this user, this item timestamp could work. And then, basically, once a user opens the page, it looks up, and the user would have to refresh their page in order to for that information to update. Right? So it wouldn't live update.\u003C/p>\u003Cp>Speaker 2: Yeah. If somebody would leave it and would set it again to null, it wouldn't like, it there's no live update, but it is it allows you to give a get a hint of or if already somebody else opened it recently, basically. I think it\u003C/p>\u003Cp>Speaker 1: should be\u003C/p>\u003Cp>Speaker 2: This quite, like, quite nicely solves the problem in a very stupid way, I would say, and, like like, a very straightforward and simple way. And that might already be enough for, like, most people who want to have this feature. Although, like, the big drawback of this still is that you're basically editing your schema, and that's in that point, and that like, it is an opt in per collection and not just something that works out of the box, except you usually would create a separate table for that. Then it would be for all collections at once. Okay.\u003C/p>\u003Cp>Speaker 1: That is actually fine because you can just add a new field. It doesn't have to be a presentational field, but you can add, like, a\u003C/p>\u003Cp>Speaker 2: Yeah. Exactly. Yeah. We can just add a field that's a string, basically, and that gets set by the interface to the user's name who last opened it if there's none already in it. And that kinda could, like, trick around, like, real time and stuff and just, very, like, get to the point of there's just a name in there and or maybe concatenate even multiple names to each other.\u003C/p>\u003Cp>Speaker 1: The field could be reset. So I would I wouldn't just save the user, but it would also add a current timestamp as well. Okay. Just just for the problem Tim mentions. Like, for example, if your browser crashes, like, for example Yep.\u003C/p>\u003Cp>Normally, you would update the field actually with real time. That is kind of a necess null. That isn't really a necessity since you can send out beacon requests. I don't know if beacons can be post requests. I'm not a 100% sure, but there's a mechanism in a browser that is, like, even if the tab closes, please send out this request to this URL, which would kind of allow us to reset this field whenever a top uploads.\u003C/p>\u003Cp>It just leaves us with the additional problem of if your router crashes. Yeah. They are risky. They're not guaranteed to be a little bit all of our shenanigans that, time attribute, basically. Basically,\u003C/p>\u003Cp>Speaker 2: that's what we've got in the browser, I would say. Yeah. Regarding that disconnects, yeah.\u003C/p>\u003Cp>Speaker 1: WebSocket, but then you would have to go browser, like a module sorry. A bundle route where you also have some server side thing. Because right now we are just thinking, of terms how to implement it in extensions. But certainly, if you're going for implementing any core, there's more possibility to detect if a user has left a page because we can just continuously, we could just continuously monitor which WebSockets are connected, and we could send live updates as soon as the user navigates from there. So very certainly, it was a bit I'm just trying to, like, imagine if there's a possibility to do it, not in core so we can fast track it because, as you know, we have a director's left extension program, where we have extension experts currently developing a lot of features that are that have open feature requests, for example, but never get never really have been implemented in core so far, which is kind of like our experimentation program for figuring out, hey.\u003C/p>\u003Cp>These could be features that could let into core, but let's see if we can use bring them to users quicker by, getting the extension route just because as soon as you'll have a feature in core, you we always wanna make sure it works for 99% of the users, maybe not 99, but a lot of the users. So the process of bringing something to a core always, as you see with all these feature requests, is a lot more involved than just dropping quick extensions saying, hey. This is something experimental.\u003C/p>\u003Cp>Speaker 2: That's correct.\u003C/p>\u003Cp>Speaker 0: It's actually a trigger for me. Alex Vandervalk and I created a we've we had a use case from a client where they wanted to be able to do some relation they wanted to be able to do some enforcement on, or they wanted to know that someone had a current, like, project design. So or a technical design document. It was the one that they were working on right now. And so they wanted to because of that, they wanted to auto filter for those things and be able to indicate that for the user.\u003C/p>\u003Cp>It also then did relational enforcement, through the relational hierarchy of the technical design document, where you had software components and relationals and many to any's and all kinds of things going on. So what we actually did was we used because Directus is actually always you know, the the Directus application is always watching, you know, user actions and saving last page and all those things. We actually intercept that as part of a flow operation, And we if they change to a different technical design document, we auto update the current design document so that it it does the relational enforcement through the permissions and things like that.\u003C/p>\u003Cp>Speaker 2: So very weak.\u003C/p>\u003Cp>Speaker 0: Yeah. So this this actually does that. So this flow actually so this is kind of along Nils' lines of if you add a field or you add a collection that you wanna keep track of and that, you know, provide notification to the user, where you do those kinds of updates. Then in this case, we're actually updating. In this case, it's the direct user table.\u003C/p>\u003Cp>We're setting that to the current TDD that they're working on. So when they change TDDs, it automatically updates this, and therefore, we have that field throughout the relational enforcement. We've got that field, you know, and we can then with many of the filters or your field filters or your policy filters or whatever you wanna apply, we can then enforce that you can't add software components that are part of another TDD. And it was one of those kinds of use cases that we're actually solving. But I think it actually, in some degree, fits this use case as well.\u003C/p>\u003Cp>Speaker 1: That still leaves you with, like, the edge cases of multiple tabs, which wreak havoc with that or could potentially wreak havoc with that. Because right now, we don't really have, like, a possibility to try.\u003C/p>\u003Cp>Speaker 0: Do a bad job. It's actually gonna just do it based on whichever tab you have open and when you're navigating back. Yeah. The the multi tab is a problem anyway. Directus does weird stuff with this particular page save issue anyway.\u003C/p>\u003Cp>I've I've learned never to have multiple tabs of a directus instance open because it just it will wreck havoc on your stuff.\u003C/p>\u003Cp>Speaker 1: I love do a duveis or however you pronounce it, please let me know. Work around right now. They basically have a dedicated Slack channel where they message, I'm editing this, hands off.\u003C/p>\u003Cp>Speaker 2: I love it, damn that's most straightforward, just do it solution, I love it.\u003C/p>\u003Cp>Speaker 0: Out of band, out of band, SS7 messaging. Keep your hand up, miss.\u003C/p>\u003Cp>Speaker 1: That's beautiful.\u003C/p>\u003Cp>Speaker 0: I think\u003C/p>\u003Cp>Speaker 1: we have a solution. I had it short here. Thank you for attending.\u003C/p>\u003Cp>Speaker 0: So so you could use the flow in this case to do that. You could actually automate that and send this send the Slack message to say, hey. I've got this item open. Now, again, it comes back to, am I editing it, not editing it, that kind of thing. But Yeah.\u003C/p>\u003Cp>You could at least have a flow so you don't have to be the one going and typing in the channel that I'm in this record right now.\u003C/p>\u003Cp>Speaker 1: Coming back to, like, how it actually could be implemented, I think there is a viable route to have this implemented as an extension just because, we provide you with all the necessities to do it. We there is real time once you enable WebSockets. So you could potentially even life update the like, life update in a way of, the user who was currently editing the field just left, and you basically subscribe to the changes on that item if you go with the route to have it on this. On one eye like, on a, on the same item or if you introduce, like, Joshua or like I've been talking about, like, a separate table that contains all the locks or not locks, but the current edits or the user presence kind of, I think in collaborative adding new all these presence indication, which basically tells you like this user can get this item, which also allows you to have multiple, which also allows you at some point oh, yeah. Because you would have to so thinking out loud here.\u003C/p>\u003Cp>Coming back to the problem that, Petros mentioned, we have relation items. So we we can traverse an item to different items. And as soon as all of them have this tracking interface, all the necessary, hey. This item is being edited notifications would be there, and they would automatically, oh, they would automatically be gone. That is might be a problem.\u003C/p>\u003Cp>Well, anyways, so the the there is, like, a possibility to have that as an extension. That's kind of what I'm trying to say. And, yep. Because I'm kind of having\u003C/p>\u003Cp>Speaker 0: things for relational, so it's just does a relational edit because just because I'm editing this item doesn't mean I'm editing the relationship right around Oh,\u003C/p>\u003Cp>Speaker 1: yeah. No. No. No. They they would, for example, be loaded as soon as you start opening a drawer, for example, that interface would also be loaded.\u003C/p>\u003Cp>It knows where it's knows\u003C/p>\u003Cp>Speaker 0: and it would do the update and tag that. Yeah. The\u003C/p>\u003Cp>Speaker 1: only problem is the only problem is with that, you would typically use an unmount trigger or something. As soon as that interface is unmounted, you would say, hey. I'm not editing this item anymore. But if you're editing through another item, all those changes would be staged. So if you close the drawer, it actually would tell somebody else, hey, it's not being edited right now or anymore.\u003C/p>\u003Cp>But in fact, it is because in fact, you just made an edit and staged it, and it's only gonna be committed or saved to the database when you save the paradigm.\u003C/p>\u003Cp>Speaker 2: Yeah. That's a good point. With relational data, that that would be tricky to get right in the yeah. Although, it like, at least the the the the one way, the the setting, the username correctly works on relational items if you go for the route of having a field on the separate item, like, on each collection on based on adding a field for tracking, who's currently editing what.\u003C/p>\u003Cp>Speaker 1: But when do you, like, release that information? When do\u003C/p>\u003Cp>Speaker 2: you release That's a good question, which I not yet know the answer to.\u003C/p>\u003Cp>Speaker 1: Like, you would do it on an unknown trigger for the interface or something. Right. Tim says the way he's done it in his, experiment extension is that he only notifies if it has been saved in in the meantime so people can concurrently edit it. Ah. Not that they just notify, hey.\u003C/p>\u003Cp>This has been saved while you are still on this page, which certainly is an option as well. Just doesn't feel as nice, but it feels a lot simpler to implement with some resolving options. Okay. So, like, hey. Take my changes, override it, or take their changes kind of deal.\u003C/p>\u003Cp>Right?\u003C/p>\u003Cp>Speaker 0: Which is commented on the version control. Right? As the you get notified that someone else has made a change, the changes get merged into you can either choose to merge those changes or throw them away and lose out.\u003C/p>\u003Cp>Speaker 1: Which is more along the lines of, like, resolving a conflict and not really and notifying you of a conflict ahead, but not trying to prevent the, conflict before it actually happens, I guess, which is, like, true process or the same kind of thing. I'm honestly divided on which one is better. It won't be, like, trying to prevent the conflict before it's happening. It feels like the nicer user experience to me.\u003C/p>\u003Cp>Speaker 2: Yeah. Like, I I would always go for the user experience, though, in that you want to know in advance that somebody's editing something, not when somebody then actually did their changes and saved them. Because then you can, for example, communicate something with somebody who's working on the same project, on the same item in that sense. Are you editing fields that I'm editing too? Yes.\u003C/p>\u003Cp>No. And depending on that, they can either just continue working on it together or, like, wait for that other person to then actually do the changes and then the next person. Basically, they have the option of, do we have to do it in series, or can we make it in parallel, basically? Like, via Slack or something, like, like, basically talking that out. At least they know that somebody has had has the intent to do changes on this item in the future.\u003C/p>\u003Cp>Speaker 1: There is a Twitter account well, x account, whatever, that explores hideous, design decisions, UX design decisions. We could also add a button, boot this per pay $5 to boot this person out of that item or something.\u003C/p>\u003Cp>Speaker 2: I like it. Though yeah. That would be another option instead of going like the okay. We do it automatically when the user joins in these, we make it like an basically, like an option where it's like you opt in now to mark this item as you're currently editing, or you can leave it if you maybe, for example, like to even make the opt in optional in a sense, which is, like, even then more work to do. And it's probably nicer to make it automatically set to the current user by when editing.\u003C/p>\u003Cp>But, again, like, that opt in makes it also that you have to opt out of it kinda thing where where if it's automatic opt in, you expect to have it automatically, like, put your like, basically know when you're done editing. But if you manually opt it in, then you also have the expectation of you have to manually opt out again of editing this item, if that makes sense.\u003C/p>\u003Cp>Speaker 1: It might be automatic. Otherwise, it's just a hassle like an introduce additional hassle and nobody will start actually.\u003C/p>\u003Cp>Speaker 2: I mean, it's it's less of a hassle than going through Slack conversation and seeing if somebody has the same item name somewhere.\u003C/p>\u003Cp>Speaker 1: Yeah. It's still it's still not as nice as it could be if it's automatic. As that said, editing some editing field should be disabled for others, which introduces another possibility or option or\u003C/p>\u003Cp>Speaker 2: That would be possible through the field by, making filters. That that is if the if there's already text in that field where the name would be saved, that all other items are although that would make it different good for the person actually editing it themselves because then these figures would probably also apply for the same person. Although maybe you can fill it out by the user username and the username matching the in the field. I'm not sure how how crazy good our filter or, like, our, things for that are are that might also work, like I'm not sure.\u003C/p>\u003Cp>Speaker 1: I was actually thinking more along the lines of enhancing the notification, possibilities that basically saying this field has been modified by another user. So I have it in line with all the fields and have a notification for all the fields that have been edited in the meantime, which certainly is possible again with real time. It might introduce another permission hell because people might not be able to see some fields. And if we just send them over WebSocket, anybody can read it, which, yeah, introduces problems again. But from UX perspective, again, it's super, super nice to have the possibility to, being able to tell, hey.\u003C/p>\u003Cp>They edited the event name. They edited the Slack. They edited whatever, as an enhancement to the original request of just shown in banner on my like, for the full item, which then again already puts you more into the collaborative editing experience where you have presence markers on all your fields and, know who's currently doing live edits on the page and seeing the edits and all of that, which is would be amazing to have. But as you already said in the beginning, it's a long ways away with the current architecture of, directors just showing you what's in the database because effectively, that's just what we're doing. Right?\u003C/p>\u003Cp>As soon as something is in the database, you see the most recent data, present in there. We don't really have any mechanisms on top of that for distributing life changes and all that that aren't already committed to the database.\u003C/p>\u003Cp>Speaker 2: Oh, another interesting approach regarding the like, when is a user done with editing an item? This is, like, a crazy solution and probably not really feasible. I still want to go with it because it sounds quite fun. Instead of subscribing and unsubscribing from an item, we could go the road as long as a user is continuously pinging an endpoint, that he's currently editing. This was which also tackles the who which tab is currently open because only the active tab will then ping that endpoint basically ping a certain endpoint to let, the basically, back end know who where the user is currently editing something.\u003C/p>\u003Cp>And we just do it like a automatic opt out after a minute of not receiving a ping from that person. That would also be another interesting approach regarding the when is a user ready like, done with editing an item or something like that. But also that that also has edge cases in a lot of senses, like, in a lot of ways.\u003C/p>\u003Cp>Speaker 1: Yeah. Also, you can, like, you can do that through WebSockets as well since you just\u003C/p>\u003Cp>Speaker 2: Yeah. Track. I mean, yeah. I'm sure. I'm just thinking of, like, would it how tricky would it be to get this working without WebSockets?\u003C/p>\u003Cp>Because that's like, WebSockets makes it also a bit more, like, advanced in a lot of sense. Like, the the I I think we have, like, a ton of good documentation on how to do rest request with like, indirect us with extensions, but on WebSockets, I don't think there's a lot of documentation yet, which makes it difficult for, like, community members to implement features like that. There's always a way, but it's a lot more tricky, and that's I would assume. I'm not sure yet though.\u003C/p>\u003Cp>Speaker 1: We put a couple of guides on how to use the real time SDK, which provides you with a lot of options to use that already in base starting point of Tim's extension as well, for example.\u003C/p>\u003Cp>Speaker 2: Yeah. That's that's we have Tim's example. That's a good starting point.\u003C/p>\u003Cp>Speaker 1: Yeah. But yeah. So I think we agree it's a very good idea. We just aren't sure if it should be in core or if it can be extend an extension because if it can be an extension, let's try to go throughout first and then see it where it breaks and if there are things that have to be implemented for, just because of this many possibilities and flavors to implement this. And if we wanna tackle it, I feel like we should put it in line with presence indications and collaborative editing or at least some way of collaborative editing experience, and that is, like, the next step kind of.\u003C/p>\u003Cp>And I don't know if you wanna have a future in core which will be replacing the not just in future, for example.\u003C/p>\u003Cp>Speaker 2: Yeah. Sure. Not no. Yeah. Right.\u003C/p>\u003Cp>In yeah. I I am definitely on the side of, like, let's make this as an extension, and then people like, even people can go with different ways of implementation depending on their preferences. Like, maybe somebody prefers the way of doing it per item where it's like, we add a field to a collection, and that field stores the current user who's editing it. Maybe some people would prefer that solution, and there would be may maybe somebody else implements another solution where it's stored in a separate collection or where it's done on the WebSocket depending what the requirements or, like, where the interests are. And, having this an extension basically allows us also to explore what people prefer as an implementation and see, like, what implementation of this gets favored over time, and also helps us guide, like, in the next iterations of directors to to find out the right way to do this basically in advance.\u003C/p>\u003Cp>Speaker 1: Which is the exact pitch for directors' lab extensions, I wanna say. It allows us to experiment with features to figure out, like, what is correct, what sticks, what are the things we wanna see, once they might be coming to core. Another great example is the command palette, etcetera, which has been released a couple of\u003C/p>\u003Cp>Speaker 0: weeks ago.\u003C/p>\u003Cp>Speaker 2: I wonder by whom?\u003C/p>\u003Cp>Speaker 1: Because that explores a lot of concepts of, global extensions and everything that can be implemented in core at some point. But for now, there's ways around it, and we can use it to prototype features, and we can use it to prototype\u003C/p>\u003Cp>Speaker 2: stuff\u003C/p>\u003Cp>Speaker 1: like the editing notifications, for example, as well. Jonathan, you've been terribly silent while we've been chugging along here.\u003C/p>\u003Cp>Speaker 0: Yes. I'm just trying to keep up with you guys from writing notes over here. I actually like I I like the VIM style option that you guys have discussed here where you would actually say, just add a toggle at the top, and you can do this in your current data model. Right? You can use roles and permissions that restrict its read only unless you've actually toggled it to say, I wanna edit this item.\u003C/p>\u003Cp>Therefore, I can put the notification and update the notification to say, this user is currently editing. So you could have the flow and the hook and, extensions doing those things. But simply adding a field to the top of your item that says toggle on or off that I'm updating. Right? So VIM, you know, d I, whatever, you know, Linux editing editors who have always been that way where if I'm updating, I have to actually explicitly enter edit mode, and then I have to explicitly exit edit mode.\u003C/p>\u003Cp>So as long as I'm in edit mode, I have it locked. Now that means that I want the ability, you know, to give a flow manual button or other things where you could say, you know, I and it could be a flow button, right, that just says, I wanna enable edit on this. Therefore, send notification to the team that also is responsible.\u003C/p>\u003Cp>Speaker 2: Right. Yeah.\u003C/p>\u003Cp>Speaker 0: You'd send an email. You could send an in app notification. Or, again, just update another field next to it that says, I'm editing this. Therefore, if the administrators need to go in and override you, they could. But at that point, you can use role and policy permissions to say the policy permission is gonna say based on the toggle being an edit, I now have edit permissions on the appropriate fields that I'm allowed access to.\u003C/p>\u003Cp>I can make my edits, save my changes, and you could even make it so that if on save, if you wanted to, right, make your edits, if on save, that automatically toggles it back to unedit. Right? So you could do something like that for the users, and you'd have some control over the workflow there. So I like that idea.\u003C/p>\u003Cp>Speaker 1: Problem with that is it sounds terribly manual.\u003C/p>\u003Cp>Speaker 0: Sure.\u003C/p>\u003Cp>Speaker 2: It's Have the design just behind that. Yeah.\u003C/p>\u003Cp>Speaker 1: Having to have all the hands conditions, and also, additionally, I don't I'm not a 100% sure. I don't think so, to be honest, that it is possible with the current policies because policies are additive. So if you add like a policy, you can't edit this item except for this, and you have another policy which allows the user to edit certain fields in that item. They still will be will be able to edit, edit some fields on those items.\u003C/p>\u003Cp>Speaker 2: Although we don't have the option to make, like, fields disabled depending on other fields, like, these like, depending on things and Yeah.\u003C/p>\u003Cp>Speaker 1: You can\u003C/p>\u003Cp>Speaker 2: make it, like, if the the field has a certain value, other fields get disabled some or something like that. And, like, that's the point where I'm not certain that this would work because we have to make it relative to the user's name. But that could be, like, an option to have it like a no code basically, where you don't have to implement any extension and can get this running in a matter of, like, minute or, like, hours, config by just configuring directors in the end, basically. Hours as\u003C/p>\u003Cp>Speaker 1: soon as you start adding another field or another collection with 10 or 20 fields because you will have to go into every single field and apply that condition to it, because those are fields that you\u003C/p>\u003Cp>Speaker 2: will be horribly manual, but it will get the job done, basically. And for some people, that might already be enough. That's what I'm thinking. Like, a proper solution is always better than just doing it manually in a hacky way, but maybe that's better than writing single things in Slack. So Always better than Slack.\u003C/p>\u003Cp>Speaker 0: You know, it's definitely better than a than a Slack manual. I'm working on this item kind of. So that's that's a lot of work. That's a brutal thing. So\u003C/p>\u003Cp>Speaker 2: But, you know, you're terrific. Right? And then it would be a giant mess of configuration that would that you would have to go through, like, an giant effort for a simple feature that could be implemented with an extension. But on the other side, not everybody is an extension developer and hiring one could also be expensive. Like, I'm not sure.\u003C/p>\u003Cp>So that's maybe, like, you want to just have this and without any, like, effort input like, any large effort put into that and kick that configuration, that might be the way to go using, like, flows and, custom fields or something like that.\u003C/p>\u003Cp>Speaker 1: You still would have to have the user toggle that field and save it. Like, save the item, then only then once somebody else opens the item, you will be able to see it. So there's a lot of, like,\u003C/p>\u003Cp>Speaker 2: user flaws. Yeah.\u003C/p>\u003Cp>Speaker 1: It seems like there's more user error involved than writing a Slack message, because the fields will start appearing, as editable as soon as you toggle it, but you need to remember to save it before. Otherwise, nobody else would see it. So\u003C/p>\u003Cp>Speaker 2: Yeah.\u003C/p>\u003Cp>Speaker 1: Certainly is an option. Certainly isn't the route I would go for.\u003C/p>\u003Cp>Speaker 2: No. I probably neither, but I'm also like an I I I'm also able to develop my own extension. So that also solves the problem for me of, like, would I go the extension route? But, yeah, like, custom extensions, I think that's a great place to for that. Like, that's a powerful way to use, custom extensions, and to just basically extend Reactors without having to con like, to commit to a certain solution that we will decide on.\u003C/p>\u003Cp>Like, if we would now decide on this solution as the best, like, maybe for us right now at the moment, but maybe, like, we don't know of any of certain use cases where people would prefer another solution and, like, going the extension or, like, the lab route, that's definitely sounds like the best solution at the moment, to like, for everybody that people can try this feature out without having to, like, have it in core. And, then, like, depending on how this develops, people can then, like, we can then start looking into how does this get used and how often and how much, like, interest is behind that after it's gets in after it's get gets implemented as a custom extension, and then we can iterate on the next versions of directors to see what we want to have this rigging call just to make it, like, the setup a lot easier for people. Right?\u003C/p>\u003Cp>Speaker 1: And since we still have the original author of that feature request in the chat, I really wanna ask him to, like, as a closing thought kind of deal, because we're doing quarter like, 45 minutes usually for you, your entry, feature request. Right? Or is it a full hour?\u003C/p>\u003Cp>Speaker 0: It's technically a full hour, but we're well, I think we're just about there. I'm putting in some final notes here. But, yes, if they if they offer some ideas, I'd love to hear.\u003C/p>\u003Cp>Speaker 1: Have we covered whatever we were thinking about? Have we outlined the thoughts behind why it's currently not in core or how it could be implemented as an extension? And maybe, like, future options for collaborative editing, which kind of overtake this or replace it at some point. Jonathan, you will have to tell a story while he's telling chat, I think.\u003C/p>\u003Cp>Speaker 0: Yep. Nope. I'm just quickly I'm quickly scanning back through here to see if there was anything that we missed. I think we've covered the general requirements here. And I agree that longer term, I think, you know, ideally collaborative editing solves this problem outright.\u003C/p>\u003Cp>Right? Because then you've got field level notification of who's making changes, when they're making changes. It's real time. You see the changes in real time. But that's a story for another day.\u003C/p>\u003Cp>This this particular use case, I really like the idea of we can potentially put some solutions out into the wild, help us identify what are the edge cases. Because even with collaborative editing, what are the edge cases we're gonna run into? What are things that can happen or will happen? You know, relational always creates the complexity. Right?\u003C/p>\u003Cp>When you start digging into relationals and, you know, at what point are you locking or not locking, what points are you notifying, not notifying, handling some of those cases. And collaborative may just make that all go away. There may not be edge cases other than speed and performance of getting notifications back and forth, for the users. But,\u003C/p>\u003Cp>Speaker 1: Tim isn't allowed to participate in these\u003C/p>\u003Cp>Speaker 0: Oh, versions.\u003C/p>\u003Cp>Speaker 1: Versions. Should be fun. Yeah. Versions. We haven't really talked about versions in this whole thing.\u003C/p>\u003Cp>Right? That is yeah. You're not allowed to participate. I don't think so. You also versions.\u003C/p>\u003Cp>There's a thing like versions.\u003C/p>\u003Cp>Speaker 2: Yeah. That would make it a lot more difficult. Although I'm\u003C/p>\u003Cp>Speaker 1: sorry though. Do\u003C/p>\u003Cp>Speaker 0: for for the for the extensions, you can build your own. Right? That's an option. You can start with that today.\u003C/p>\u003Cp>Speaker 1: You bring it to a very good point. We as\u003C/p>\u003Cp>Speaker 0: the core team, I will get this in as a request into the Directus Labs extensions group. So that there is a core team that is working custom extensions as part of the marketplace. That's where things like yeah. You may have seen it today, but I have this I actually have this one installed. I love this one.\u003C/p>\u003Cp>The spreadsheet. Right? The spreadsheet layout, this ability to edit these things live right here. Fantastic. Love it.\u003C/p>\u003Cp>This has been one that was that's been asked for since the day I joined. I've I've heard people asking for spreadsheet style layout. So I\u003C/p>\u003Cp>Speaker 2: think I remember, Ben asking for this feature, like, in 2,000 well, at 2,021 or something, like, or even before that. So, yeah, it has been on a long road of, like, when will this come? When will this come?\u003C/p>\u003Cp>Speaker 1: When will\u003C/p>\u003Cp>Speaker 2: this get implemented?\u003C/p>\u003Cp>Speaker 1: But doom is bringing up a very good point because, yeah, sure. You don't use versions, but the reason why it's taking us so long to bring new stuff like this into core sometimes is you don't use versions, other people might. So everything that is in core has to work for all the features that we already support.\u003C/p>\u003Cp>Speaker 2: Didn't he set the other way around? Because it's like double negation. Is it like who does not use versions in a sense that, like, everybody use versions? Or am I misunderstanding his message?\u003C/p>\u003Cp>Speaker 0: No. Content versioning is\u003C/p>\u003Cp>Speaker 1: I would think Unless we have\u003C/p>\u003Cp>Speaker 0: fixed the permissioning problem, we still it it's it's very, very limited in its use case options and where you can actually today, because of publishing and editing permissions. So if I wanna main should technically be read only and locked, which is published state. But as soon as you create a content version, if you've got the main record locked, all content versions are locked without changing main. So there are permissioning issues, policy issues right now on the permissioning side that make content versioning difficult to use if not impossible. What's that?\u003C/p>\u003Cp>Speaker 1: Do we have an issue for that? I have to ask now because I was the one\u003C/p>\u003Cp>Speaker 0: Yep.\u003C/p>\u003Cp>Speaker 1: We had is it is it if you have a problem?\u003C/p>\u003Cp>Speaker 0: We've got open feature request for it. Yes.\u003C/p>\u003Cp>Speaker 1: What is feature request?\u003C/p>\u003Cp>Speaker 0: So it's a again, this comes back to, you know, the way the policies are implemented currently. It relies on the main permissioning rather than the version permission version having its own permissioning. Yeah. So you can lock things like I can prevent promoting. I can do things around.\u003C/p>\u003Cp>Can they create or not create, you know, versions? Can they promote or not promote versions? But the ability to edit that version is dependent on the permissions of main, and therefore, I can't do things like lock main, which means now a user, if they've got the permission, they can edit the published record live without doing it inside of a version. So there's some things that are problematic there.\u003C/p>\u003Cp>Speaker 1: That's a very good point. Yeah.\u003C/p>\u003Cp>Speaker 0: Neither here nor there. Just for the folks here, if you see anything in this particular project, this is kind of core team provided. It's not guaranteed that it's maintained long term, but you have if you see these in the marketplace, right, so Directus marketplace here, if you see those in this particular layout and if you see anyone with the let me put an AI space here. If you see anyone with this little check mark here, that tends to be core team. They've been approved, so you can at least trust that it's coming from a reliable source, in that sense, generally.\u003C/p>\u003Cp>But marketplace extensions is where this will would show up. So if we get the team to agree that they wanna take this on, you'll see that show up at some point in the next 2 to 4 months, generally. We tend to try and get these we're we're tend to roll out, these lab extensions on a monthly basis. So we've got well, again, no guarantees, but, hopefully, the team will decide that this is worthwhile. I'll put the feedback in to say that this seems like a really cool one to actually have out there in the wild to get this haptic feedback so that we know what we need to watch out for as we continue to implement these kinds of features in Directus\u003C/p>\u003Cp>Speaker 1: Core. So\u003C/p>\u003Cp>Speaker 2: so,\u003C/p>\u003Cp>Speaker 0: Petros, give it a give it an upvote or you're not finding the ticket, open a ticket. Yep. The this is\u003C/p>\u003Cp>Speaker 2: a I\u003C/p>\u003Cp>Speaker 0: ran into it. It was what the the first week that we rolled content versioning out, I had a client reach out. I need to be able to do I'm trying to do x y z, and it doesn't seem to be working. And I tried I tried flows. I tried work around.\u003C/p>\u003Cp>I tried all kinds of hacks. I could not get around the fact that main is driving permissions for the version. So it's, it is the there's a slight problem there. Although I guess you could with a flow, you could watch on main if main's in published, you could just prevent. But it's a it's a it's a bit hacky in the sense of the user can make a whole bunch of changes.\u003C/p>\u003Cp>Now try to save that and realize that they were in main to be blocked. But you can at least you could put some validation in place that force prevents that save.\u003C/p>\u003Cp>Speaker 1: Feels like a very good discussion topic for another feature request. So\u003C/p>\u003Cp>Speaker 2: Yeah. Absolutely. The point.\u003C/p>\u003Cp>Speaker 1: Straight to the point. Yeah. Of having versions and promoting and demoting versions, versions. Where we get those permissions from since, like, you correctly said all the permissions are determined by the main items since we have one, like, one permissioning engine in core. And it just looks at the main item, and it actually does it actually has a database evaluate all those permissions for you, which makes it easier in a lot of senses, but makes stuff like this where versions are actually separately maintained JSON blobs of that item a lot more difficult.\u003C/p>\u003Cp>Yeah.\u003C/p>\u003Cp>Speaker 0: Very true. But we're off topic. Any final parting thoughts on editing, notification?\u003C/p>\u003Cp>Speaker 1: Sounds cool.\u003C/p>\u003Cp>Speaker 2: It's like\u003C/p>\u003Cp>Speaker 1: there's an extension. There those are my final words I wanna say. Yeah. Because I definitely see the US improvement. I see the value in it.\u003C/p>\u003Cp>I'm just not a 100% sure if we can get it into core properly while keeping all the features we currently already have in mind in a reasonable time frame. Yep. It's\u003C/p>\u003Cp>Speaker 2: always the goddamn time.\u003C/p>\u003Cp>Speaker 0: Well, no.\u003C/p>\u003Cp>Speaker 2: Yeah. But let's let's see what we can do. Put it. Yeah.\u003C/p>\u003Cp>Speaker 1: And, I mean, we can also, like, put it out here. If you feel like, hey, that is an extension I'm gonna develop, reach out to us. Maybe we can help you.\u003C/p>\u003Cp>Speaker 2: That would be awesome. Yeah. I would love to hear people getting just their hands dirty in this.\u003C/p>\u003Cp>Speaker 1: Because in the end, anyone can develop an extension for directors. We try to make it as open and easy as possible. So if you feel like that is something you wanna try, reach out to any of us, and we'll see what the options are.\u003C/p>\u003Cp>Speaker 0: Actually, reach out via the ticket. So post your comments, thoughts, work, other things that you're doing. Let's make sure it gets back to this ticket so that we can actually track that progress. And Yeah. We'll try and do the same.\u003C/p>\u003Cp>We'll, again, when we we do these kinds of extension developments, we'll tag that back into this ticket. So if it gets accepted and committed and delivered, we'll we'll try to remember to populate that back into the ticket. Alright. Cool. Well,\u003C/p>\u003Cp>Speaker 1: well, honest sales.\u003C/p>\u003Cp>Speaker 0: Wonderful having you guys join on short notice.\u003C/p>\u003Cp>Speaker 2: Yeah. Was this last of the year?\u003C/p>\u003Cp>Speaker 1: As usual.\u003C/p>\u003Cp>Speaker 0: It's exciting. Team, thanks everyone for joining. Have a wonderful rest of your week. And as always, reach out through Discord or through the ticketing systems, and we're here to\u003C/p>\u003Cp>Speaker 1: help us find out. October 15th for the next change log that covers all the changes that will be released in the new version. If you're there.\u003C/p>\u003Cp>Speaker 0: And as always, this will be posted in the request review channel of the Directus IO TV.\u003C/p>\u003Cp>Speaker 1: Chat out everyone. Last chat message. All the feedback from this call is has actually been typed up by Jonathan while we were talking until Thursday.\u003C/p>\u003Cp>Speaker 0: I will see. Yeah. Well, I did. You guys feel free\u003C/p>\u003Cp>Speaker 1: to add\u003C/p>\u003Cp>Speaker 0: if I missed anything. Cheers, everyone.\u003C/p>\u003Cp>Speaker 2: Cheers. Cheers. Bye bye.\u003C/p>","Let's rock and roll. I think this fundamentally comes down to something that we've been talking about off and on for a couple of years now is the ability to have things like collaborative editing, at least some level of notification somebody else is working a record as our as we all as as we all here know very well that it's a first save wins at the moment, and you have no idea if anybody else is editing a record that you happen to be editing. Generally, it works out. I don't think it's a frequent occurrence, but it's probably it is something that I think we would all like to see solved. And I'm hopeful that I think I see BrainSlug is in the audience as well. That's good because I think he's actually got a custom extension that actually uses websites to actually do this, for, like, live chat and other things. But I think he actually did something as a test, and we'll we'll get through that. But that's what I think this generally is, and we'll get this thing kicked off. I'll turn it to the brains of the operation, and let's roll through this thing. Shout if you need me to show something or pop over to somewhere, and we'll go. Yeah. Tim is disappearing. Yes. I think this was actually a fairly easy feature request, you know, in of itself if you don't consider, like, all the possibilities you could evolve evolve to. Because in the end, it's just asking for, hey. We need a notification if someone is editing something, and that doesn't really it needs some kind of real time possibility, but it doesn't really need any collaborative editing efforts. It enhances it by already. If you put where WordPress does as well. Haven't used WordPress in a long, long time, but I think it had something to do with where I told you, hey. This is, this part is embedded by someone else, which is basically what this feature is asking for, just to give them heads up and just to improve the experience. But I think the author of the Hippo Trust, should also be in the audience. Maybe you can raise your hand or something, say hi, to see what you envisioned there. Oh, yeah. There he is. Because I know it's, like, just reading it, it seems like a fairly easy thing to implement and to consider. It just we just need to figure out, like, what are the extended use cases we wanna have with it. Is it enough to show that occasion as a starter? Who we able to wanna evolve it into collaborative editing and all of that? Because we already had a discussion on real time. I think I just went through a couple of discussions almost October last year, so there have been some discussions about that in general as well. And this feels like an obvious feature to merge into that as well. But I see that Uwe, Uwe. So, excuse me for butchering your name. He's typing right now, and he has some additional insight that he collected over last year that this feature request has been up and being voted by the community. Yeah. And and to just give a bit more context from what I remember, I think this was, like, in the talks. Like, then when we started, like, working on WebSocket support and stuff like that, that's was, like, one of the, like, key things we looked at for, like, WebSockets and stuff. But as you mentioned, like, it doesn't really necessarily need WebSockets. You could also, like, pull, like, a get request each second in if you would want to go without WebSockets. Like, there's always, like, the possibility to implement this. It's just, like, about what do we want to have this as a real scope in terms of, like, we just implementing this is probably there's more to it in the end, basically. There's more we can do, more we can, like, find out before we go implement this feature. And yeah. Also something to consider is can we implement it as an extension? Does it have to be in core, or is it something that could be a presentation interface, for example, which can, utilize the real time WebSocket API to figure out, like, is there anyone else editing it right now, maybe through a system collection or something that, along those lines where you write an item as soon as somebody is there and you kind of keep it alive, had it write a time stamp when it was last visited or something, and then you could figure out based on that if there currently is one editing it. I can certainly see going that route with an extension as well. It doesn't really need to be a core feature even though it could be nice to have as a core feature. Tim said that one thing he recalls about being difficult is that what do you show about the other user if editing, what the other user that is editing it? If you don't have the permissions for other users, I think you would just say, hey. There's one other user editing or something. It doesn't really it's nice to have a name and to have a thumbnail and profile picture and all of that, but it doesn't necessarily need it to function in the 1st place, I would say. So that that was the question that I just wrote down is what's considered editing. Right? Is it just someone has the item record open and they have edit permissions, and therefore that's considered editing or they've actually made a change and that's considered editing. Just something that Or step in between is have they focus on input, for example, if like a step towards editing. Yep. Yeah. That's just another thing we, like, probably have to, like, decide on first for something like this could be implemented because that is like a known edge case. And, like, for example, if we would go with the locking route, where, like, an item gets locked if a user edits, then the real important question is, like, with that system, somebody could just, like, lock us, like, an item forever and not release it, and at any point of time in the future, and that would be a big problem because then you have, like, oh, my my colleague from work is not, giving me access to this item right now. I can't do my job, and that that is not an option, really. So RCS, which is an ancient, vision control version control system from, like, the eighties, like, eighties, nineties from Unix. And they have this concept of locking a file. So if somebody locks a file, you're not able to edit it anymore, and you can, like, force unlock a file. So they certainly use that possibility as well. But Right. There is always gets overtook this kind of locking approach, where you're trying to negotiate and take these afterwards. I mean, in this case, I think, as well as the author of the PR, feature, I guess, sorry, said the notification itself should be the better option. Also, seems I wanna say simpler implementation wise because both of them kind of require either, some state on the server or requires some, entries in the database. Having the item page feels easier. Yeah. Because you also have so as as Mills mentioned, right, you have the ability to potentially so we got a lock record route then how long do you allow that lock to remain held? And you automatically time it out and just, you know, that person loses their edits. Mhmm. You know? Or is there an admin way to force specific out of whack and now you got a record block that can't be accessed by the users in any way, shape, or form, even the original user that, you know, initiated the lock. So that means we need some admin, ways of managing and releasing force releasing and resetting locks. Oh, Pedro brings up a very good point. We we have relations in directors, so you're not always just editing a single item, but you can basically walk a whole tree of changes and go 7 drawers deep and start editing, items that don't that aren't actually your item page. That is a very good call, which I haven't considered myself so far. That that's yeah. And that in that sense, locking will probably be, like, very difficult to implement because then the question like, the real question is what even do we lock? Not only, like, when do we lock, but how and what and why. So that's way more tricky than just giving you the information of somebody. Like, in a perfect world, we would have to, like, live collaboration that basically solves the problem out of the box, but that's not really feasible, I think, at the moment in the core implementation of our app. So, like, some way of not like, not an either a notification bar or, like, a, like, a schedule to request to see if there's somebody editing your current item and then update it or something like that. That would be like a, I would say, trade off between what we can do right now with your time and what should improve the experience by, like, the minimum, at least. Like, the minimum, of, like, to yeah. Basically, to have some way of knowing that somebody is working on this cost right now, there isn't. I mean, I guess there is on the user because the user table has the records on the last edited item. So there is currently already the information stored in directors. Well, the last page, which, gets terribly confusing if you have multiple tabs open. Right? And as soon as you start True. In that case yeah. The information gets up because that's a single entry. But that would be, like, I would say, like, a good start to use that information that we already have to work on that week. Although, we if we were to, want to go for it, we could also make it, like, fully fetched then. Yeah. That's, like, that's also true. Yeah. The problem with the last page is, like, it isn't very it it isn't really, like, a secure information on what is the user what the user is currently doing, because they might open 1 page, might open another page, and it not, like, might open the item page and then tab out, go to a different tab, and navigate in there. And suddenly, you lose all the information because it's really only intended as a way to basically bring the user back to the last page they open once they log out and log back in. That is the intention of page, to have like a more fluent experience when you revisit the same director's instance. So using that really doesn't seem like the right option, but Tim linked his experimental, live collaboration interface extension, which live collaboration really is a big word for it, I wouldn't say, because right now it's just a presentational interface that can notify you if somebody else is, working on the same item. And I just peruse that the code, Tim, please correct me, but it seem it seems like it's using our real time WebSocket, and it just sends custom messages over it. I don't know if it needs some does, the WebSocket implementation automatically fan it out to all connected clients, or is there some sort of a component as well in there that is necessary? I'm not able to use that one. I'm thinking, like, not while doing that, let's read some chats. Joshua, she's she's it suggests lock timeouts. It's certainly an option, 100%. Still leaves you with the possibility. What is a lock time out? Is it 5 minutes? Somebody might be editing longer than 5 minutes. Is it an hour you might wanna add it to an item sooner than an hour after your colleague left? So if we were to go to the lock route, there certainly has to be a mechanism for you. Yes. I'm sure I wanna override this lock. I wanna take the over this page, mechanism kind of. Yeah. I'm with, Pedro's on this, notification that is shown once the user starts editing a record should be great, And it's just a simple avatar of as a fallback, as we said, if the user currently editing the item doesn't have any information about other users or something that doesn't have the permissions. Yeah. And another thing I am wondering right now, or thinking about is, regarding where we would want to store that information, who is currently editing what item. We could, like, store it somewhere in the user collection. We could store it somewhere on the item. So what I was thinking, for example, would be a custom interface that basically makes a request to the, API, on, like, somebody opened this item, a request goes like, because interface interface gets loaded, the interface lets the API know that, like, the value of this field gets then sent to the user's name. And, others visiting the same page, the basically, the data gets fetched from the API. And in that field will be the name of the current user who's editing that item, and that interface could then display that information. And that would also, like, require no real time WebSocket connections, and that would also be a very straightforward in that sense that it is very similar to the created or updated on or modified on, interface, which, like, could also make this as an extension because then we are not like, we can just flop, I mean, you're gonna have to edit your schema for that feature to work, and it is not like, it is basically an opt in feature in that case. But it would be very straightforward to implement even as an extension, and that could also be another interesting approach to this problem, basically. So, basically, either extending your current items to a user, or you can even introduce a whole new table that is just a, a lookup table kind of, like, this user, this item timestamp could work. And then, basically, once a user opens the page, it looks up, and the user would have to refresh their page in order to for that information to update. Right? So it wouldn't live update. Yeah. If somebody would leave it and would set it again to null, it wouldn't like, it there's no live update, but it is it allows you to give a get a hint of or if already somebody else opened it recently, basically. I think it should be This quite, like, quite nicely solves the problem in a very stupid way, I would say, and, like like, a very straightforward and simple way. And that might already be enough for, like, most people who want to have this feature. Although, like, the big drawback of this still is that you're basically editing your schema, and that's in that point, and that like, it is an opt in per collection and not just something that works out of the box, except you usually would create a separate table for that. Then it would be for all collections at once. Okay. That is actually fine because you can just add a new field. It doesn't have to be a presentational field, but you can add, like, a Yeah. Exactly. Yeah. We can just add a field that's a string, basically, and that gets set by the interface to the user's name who last opened it if there's none already in it. And that kinda could, like, trick around, like, real time and stuff and just, very, like, get to the point of there's just a name in there and or maybe concatenate even multiple names to each other. The field could be reset. So I would I wouldn't just save the user, but it would also add a current timestamp as well. Okay. Just just for the problem Tim mentions. Like, for example, if your browser crashes, like, for example Yep. Normally, you would update the field actually with real time. That is kind of a necess null. That isn't really a necessity since you can send out beacon requests. I don't know if beacons can be post requests. I'm not a 100% sure, but there's a mechanism in a browser that is, like, even if the tab closes, please send out this request to this URL, which would kind of allow us to reset this field whenever a top uploads. It just leaves us with the additional problem of if your router crashes. Yeah. They are risky. They're not guaranteed to be a little bit all of our shenanigans that, time attribute, basically. Basically, that's what we've got in the browser, I would say. Yeah. Regarding that disconnects, yeah. WebSocket, but then you would have to go browser, like a module sorry. A bundle route where you also have some server side thing. Because right now we are just thinking, of terms how to implement it in extensions. But certainly, if you're going for implementing any core, there's more possibility to detect if a user has left a page because we can just continuously, we could just continuously monitor which WebSockets are connected, and we could send live updates as soon as the user navigates from there. So very certainly, it was a bit I'm just trying to, like, imagine if there's a possibility to do it, not in core so we can fast track it because, as you know, we have a director's left extension program, where we have extension experts currently developing a lot of features that are that have open feature requests, for example, but never get never really have been implemented in core so far, which is kind of like our experimentation program for figuring out, hey. These could be features that could let into core, but let's see if we can use bring them to users quicker by, getting the extension route just because as soon as you'll have a feature in core, you we always wanna make sure it works for 99% of the users, maybe not 99, but a lot of the users. So the process of bringing something to a core always, as you see with all these feature requests, is a lot more involved than just dropping quick extensions saying, hey. This is something experimental. That's correct. It's actually a trigger for me. Alex Vandervalk and I created a we've we had a use case from a client where they wanted to be able to do some relation they wanted to be able to do some enforcement on, or they wanted to know that someone had a current, like, project design. So or a technical design document. It was the one that they were working on right now. And so they wanted to because of that, they wanted to auto filter for those things and be able to indicate that for the user. It also then did relational enforcement, through the relational hierarchy of the technical design document, where you had software components and relationals and many to any's and all kinds of things going on. So what we actually did was we used because Directus is actually always you know, the the Directus application is always watching, you know, user actions and saving last page and all those things. We actually intercept that as part of a flow operation, And we if they change to a different technical design document, we auto update the current design document so that it it does the relational enforcement through the permissions and things like that. So very weak. Yeah. So this this actually does that. So this flow actually so this is kind of along Nils' lines of if you add a field or you add a collection that you wanna keep track of and that, you know, provide notification to the user, where you do those kinds of updates. Then in this case, we're actually updating. In this case, it's the direct user table. We're setting that to the current TDD that they're working on. So when they change TDDs, it automatically updates this, and therefore, we have that field throughout the relational enforcement. We've got that field, you know, and we can then with many of the filters or your field filters or your policy filters or whatever you wanna apply, we can then enforce that you can't add software components that are part of another TDD. And it was one of those kinds of use cases that we're actually solving. But I think it actually, in some degree, fits this use case as well. That still leaves you with, like, the edge cases of multiple tabs, which wreak havoc with that or could potentially wreak havoc with that. Because right now, we don't really have, like, a possibility to try. Do a bad job. It's actually gonna just do it based on whichever tab you have open and when you're navigating back. Yeah. The the multi tab is a problem anyway. Directus does weird stuff with this particular page save issue anyway. I've I've learned never to have multiple tabs of a directus instance open because it just it will wreck havoc on your stuff. I love do a duveis or however you pronounce it, please let me know. Work around right now. They basically have a dedicated Slack channel where they message, I'm editing this, hands off. I love it, damn that's most straightforward, just do it solution, I love it. Out of band, out of band, SS7 messaging. Keep your hand up, miss. That's beautiful. I think we have a solution. I had it short here. Thank you for attending. So so you could use the flow in this case to do that. You could actually automate that and send this send the Slack message to say, hey. I've got this item open. Now, again, it comes back to, am I editing it, not editing it, that kind of thing. But Yeah. You could at least have a flow so you don't have to be the one going and typing in the channel that I'm in this record right now. Coming back to, like, how it actually could be implemented, I think there is a viable route to have this implemented as an extension just because, we provide you with all the necessities to do it. We there is real time once you enable WebSockets. So you could potentially even life update the like, life update in a way of, the user who was currently editing the field just left, and you basically subscribe to the changes on that item if you go with the route to have it on this. On one eye like, on a, on the same item or if you introduce, like, Joshua or like I've been talking about, like, a separate table that contains all the locks or not locks, but the current edits or the user presence kind of, I think in collaborative adding new all these presence indication, which basically tells you like this user can get this item, which also allows you to have multiple, which also allows you at some point oh, yeah. Because you would have to so thinking out loud here. Coming back to the problem that, Petros mentioned, we have relation items. So we we can traverse an item to different items. And as soon as all of them have this tracking interface, all the necessary, hey. This item is being edited notifications would be there, and they would automatically, oh, they would automatically be gone. That is might be a problem. Well, anyways, so the the there is, like, a possibility to have that as an extension. That's kind of what I'm trying to say. And, yep. Because I'm kind of having things for relational, so it's just does a relational edit because just because I'm editing this item doesn't mean I'm editing the relationship right around Oh, yeah. No. No. No. They they would, for example, be loaded as soon as you start opening a drawer, for example, that interface would also be loaded. It knows where it's knows and it would do the update and tag that. Yeah. The only problem is the only problem is with that, you would typically use an unmount trigger or something. As soon as that interface is unmounted, you would say, hey. I'm not editing this item anymore. But if you're editing through another item, all those changes would be staged. So if you close the drawer, it actually would tell somebody else, hey, it's not being edited right now or anymore. But in fact, it is because in fact, you just made an edit and staged it, and it's only gonna be committed or saved to the database when you save the paradigm. Yeah. That's a good point. With relational data, that that would be tricky to get right in the yeah. Although, it like, at least the the the the one way, the the setting, the username correctly works on relational items if you go for the route of having a field on the separate item, like, on each collection on based on adding a field for tracking, who's currently editing what. But when do you, like, release that information? When do you release That's a good question, which I not yet know the answer to. Like, you would do it on an unknown trigger for the interface or something. Right. Tim says the way he's done it in his, experiment extension is that he only notifies if it has been saved in in the meantime so people can concurrently edit it. Ah. Not that they just notify, hey. This has been saved while you are still on this page, which certainly is an option as well. Just doesn't feel as nice, but it feels a lot simpler to implement with some resolving options. Okay. So, like, hey. Take my changes, override it, or take their changes kind of deal. Right? Which is commented on the version control. Right? As the you get notified that someone else has made a change, the changes get merged into you can either choose to merge those changes or throw them away and lose out. Which is more along the lines of, like, resolving a conflict and not really and notifying you of a conflict ahead, but not trying to prevent the, conflict before it actually happens, I guess, which is, like, true process or the same kind of thing. I'm honestly divided on which one is better. It won't be, like, trying to prevent the conflict before it's happening. It feels like the nicer user experience to me. Yeah. Like, I I would always go for the user experience, though, in that you want to know in advance that somebody's editing something, not when somebody then actually did their changes and saved them. Because then you can, for example, communicate something with somebody who's working on the same project, on the same item in that sense. Are you editing fields that I'm editing too? Yes. No. And depending on that, they can either just continue working on it together or, like, wait for that other person to then actually do the changes and then the next person. Basically, they have the option of, do we have to do it in series, or can we make it in parallel, basically? Like, via Slack or something, like, like, basically talking that out. At least they know that somebody has had has the intent to do changes on this item in the future. There is a Twitter account well, x account, whatever, that explores hideous, design decisions, UX design decisions. We could also add a button, boot this per pay $5 to boot this person out of that item or something. I like it. Though yeah. That would be another option instead of going like the okay. We do it automatically when the user joins in these, we make it like an basically, like an option where it's like you opt in now to mark this item as you're currently editing, or you can leave it if you maybe, for example, like to even make the opt in optional in a sense, which is, like, even then more work to do. And it's probably nicer to make it automatically set to the current user by when editing. But, again, like, that opt in makes it also that you have to opt out of it kinda thing where where if it's automatic opt in, you expect to have it automatically, like, put your like, basically know when you're done editing. But if you manually opt it in, then you also have the expectation of you have to manually opt out again of editing this item, if that makes sense. It might be automatic. Otherwise, it's just a hassle like an introduce additional hassle and nobody will start actually. I mean, it's it's less of a hassle than going through Slack conversation and seeing if somebody has the same item name somewhere. Yeah. It's still it's still not as nice as it could be if it's automatic. As that said, editing some editing field should be disabled for others, which introduces another possibility or option or That would be possible through the field by, making filters. That that is if the if there's already text in that field where the name would be saved, that all other items are although that would make it different good for the person actually editing it themselves because then these figures would probably also apply for the same person. Although maybe you can fill it out by the user username and the username matching the in the field. I'm not sure how how crazy good our filter or, like, our, things for that are are that might also work, like I'm not sure. I was actually thinking more along the lines of enhancing the notification, possibilities that basically saying this field has been modified by another user. So I have it in line with all the fields and have a notification for all the fields that have been edited in the meantime, which certainly is possible again with real time. It might introduce another permission hell because people might not be able to see some fields. And if we just send them over WebSocket, anybody can read it, which, yeah, introduces problems again. But from UX perspective, again, it's super, super nice to have the possibility to, being able to tell, hey. They edited the event name. They edited the Slack. They edited whatever, as an enhancement to the original request of just shown in banner on my like, for the full item, which then again already puts you more into the collaborative editing experience where you have presence markers on all your fields and, know who's currently doing live edits on the page and seeing the edits and all of that, which is would be amazing to have. But as you already said in the beginning, it's a long ways away with the current architecture of, directors just showing you what's in the database because effectively, that's just what we're doing. Right? As soon as something is in the database, you see the most recent data, present in there. We don't really have any mechanisms on top of that for distributing life changes and all that that aren't already committed to the database. Oh, another interesting approach regarding the like, when is a user done with editing an item? This is, like, a crazy solution and probably not really feasible. I still want to go with it because it sounds quite fun. Instead of subscribing and unsubscribing from an item, we could go the road as long as a user is continuously pinging an endpoint, that he's currently editing. This was which also tackles the who which tab is currently open because only the active tab will then ping that endpoint basically ping a certain endpoint to let, the basically, back end know who where the user is currently editing something. And we just do it like a automatic opt out after a minute of not receiving a ping from that person. That would also be another interesting approach regarding the when is a user ready like, done with editing an item or something like that. But also that that also has edge cases in a lot of senses, like, in a lot of ways. Yeah. Also, you can, like, you can do that through WebSockets as well since you just Yeah. Track. I mean, yeah. I'm sure. I'm just thinking of, like, would it how tricky would it be to get this working without WebSockets? Because that's like, WebSockets makes it also a bit more, like, advanced in a lot of sense. Like, the the I I think we have, like, a ton of good documentation on how to do rest request with like, indirect us with extensions, but on WebSockets, I don't think there's a lot of documentation yet, which makes it difficult for, like, community members to implement features like that. There's always a way, but it's a lot more tricky, and that's I would assume. I'm not sure yet though. We put a couple of guides on how to use the real time SDK, which provides you with a lot of options to use that already in base starting point of Tim's extension as well, for example. Yeah. That's that's we have Tim's example. That's a good starting point. Yeah. But yeah. So I think we agree it's a very good idea. We just aren't sure if it should be in core or if it can be extend an extension because if it can be an extension, let's try to go throughout first and then see it where it breaks and if there are things that have to be implemented for, just because of this many possibilities and flavors to implement this. And if we wanna tackle it, I feel like we should put it in line with presence indications and collaborative editing or at least some way of collaborative editing experience, and that is, like, the next step kind of. And I don't know if you wanna have a future in core which will be replacing the not just in future, for example. Yeah. Sure. Not no. Yeah. Right. In yeah. I I am definitely on the side of, like, let's make this as an extension, and then people like, even people can go with different ways of implementation depending on their preferences. Like, maybe somebody prefers the way of doing it per item where it's like, we add a field to a collection, and that field stores the current user who's editing it. Maybe some people would prefer that solution, and there would be may maybe somebody else implements another solution where it's stored in a separate collection or where it's done on the WebSocket depending what the requirements or, like, where the interests are. And, having this an extension basically allows us also to explore what people prefer as an implementation and see, like, what implementation of this gets favored over time, and also helps us guide, like, in the next iterations of directors to to find out the right way to do this basically in advance. Which is the exact pitch for directors' lab extensions, I wanna say. It allows us to experiment with features to figure out, like, what is correct, what sticks, what are the things we wanna see, once they might be coming to core. Another great example is the command palette, etcetera, which has been released a couple of weeks ago. I wonder by whom? Because that explores a lot of concepts of, global extensions and everything that can be implemented in core at some point. But for now, there's ways around it, and we can use it to prototype features, and we can use it to prototype stuff like the editing notifications, for example, as well. Jonathan, you've been terribly silent while we've been chugging along here. Yes. I'm just trying to keep up with you guys from writing notes over here. I actually like I I like the VIM style option that you guys have discussed here where you would actually say, just add a toggle at the top, and you can do this in your current data model. Right? You can use roles and permissions that restrict its read only unless you've actually toggled it to say, I wanna edit this item. Therefore, I can put the notification and update the notification to say, this user is currently editing. So you could have the flow and the hook and, extensions doing those things. But simply adding a field to the top of your item that says toggle on or off that I'm updating. Right? So VIM, you know, d I, whatever, you know, Linux editing editors who have always been that way where if I'm updating, I have to actually explicitly enter edit mode, and then I have to explicitly exit edit mode. So as long as I'm in edit mode, I have it locked. Now that means that I want the ability, you know, to give a flow manual button or other things where you could say, you know, I and it could be a flow button, right, that just says, I wanna enable edit on this. Therefore, send notification to the team that also is responsible. Right. Yeah. You'd send an email. You could send an in app notification. Or, again, just update another field next to it that says, I'm editing this. Therefore, if the administrators need to go in and override you, they could. But at that point, you can use role and policy permissions to say the policy permission is gonna say based on the toggle being an edit, I now have edit permissions on the appropriate fields that I'm allowed access to. I can make my edits, save my changes, and you could even make it so that if on save, if you wanted to, right, make your edits, if on save, that automatically toggles it back to unedit. Right? So you could do something like that for the users, and you'd have some control over the workflow there. So I like that idea. Problem with that is it sounds terribly manual. Sure. It's Have the design just behind that. Yeah. Having to have all the hands conditions, and also, additionally, I don't I'm not a 100% sure. I don't think so, to be honest, that it is possible with the current policies because policies are additive. So if you add like a policy, you can't edit this item except for this, and you have another policy which allows the user to edit certain fields in that item. They still will be will be able to edit, edit some fields on those items. Although we don't have the option to make, like, fields disabled depending on other fields, like, these like, depending on things and Yeah. You can make it, like, if the the field has a certain value, other fields get disabled some or something like that. And, like, that's the point where I'm not certain that this would work because we have to make it relative to the user's name. But that could be, like, an option to have it like a no code basically, where you don't have to implement any extension and can get this running in a matter of, like, minute or, like, hours, config by just configuring directors in the end, basically. Hours as soon as you start adding another field or another collection with 10 or 20 fields because you will have to go into every single field and apply that condition to it, because those are fields that you will be horribly manual, but it will get the job done, basically. And for some people, that might already be enough. That's what I'm thinking. Like, a proper solution is always better than just doing it manually in a hacky way, but maybe that's better than writing single things in Slack. So Always better than Slack. You know, it's definitely better than a than a Slack manual. I'm working on this item kind of. So that's that's a lot of work. That's a brutal thing. So But, you know, you're terrific. Right? And then it would be a giant mess of configuration that would that you would have to go through, like, an giant effort for a simple feature that could be implemented with an extension. But on the other side, not everybody is an extension developer and hiring one could also be expensive. Like, I'm not sure. So that's maybe, like, you want to just have this and without any, like, effort input like, any large effort put into that and kick that configuration, that might be the way to go using, like, flows and, custom fields or something like that. You still would have to have the user toggle that field and save it. Like, save the item, then only then once somebody else opens the item, you will be able to see it. So there's a lot of, like, user flaws. Yeah. It seems like there's more user error involved than writing a Slack message, because the fields will start appearing, as editable as soon as you toggle it, but you need to remember to save it before. Otherwise, nobody else would see it. So Yeah. Certainly is an option. Certainly isn't the route I would go for. No. I probably neither, but I'm also like an I I I'm also able to develop my own extension. So that also solves the problem for me of, like, would I go the extension route? But, yeah, like, custom extensions, I think that's a great place to for that. Like, that's a powerful way to use, custom extensions, and to just basically extend Reactors without having to con like, to commit to a certain solution that we will decide on. Like, if we would now decide on this solution as the best, like, maybe for us right now at the moment, but maybe, like, we don't know of any of certain use cases where people would prefer another solution and, like, going the extension or, like, the lab route, that's definitely sounds like the best solution at the moment, to like, for everybody that people can try this feature out without having to, like, have it in core. And, then, like, depending on how this develops, people can then, like, we can then start looking into how does this get used and how often and how much, like, interest is behind that after it's gets in after it's get gets implemented as a custom extension, and then we can iterate on the next versions of directors to see what we want to have this rigging call just to make it, like, the setup a lot easier for people. Right? And since we still have the original author of that feature request in the chat, I really wanna ask him to, like, as a closing thought kind of deal, because we're doing quarter like, 45 minutes usually for you, your entry, feature request. Right? Or is it a full hour? It's technically a full hour, but we're well, I think we're just about there. I'm putting in some final notes here. But, yes, if they if they offer some ideas, I'd love to hear. Have we covered whatever we were thinking about? Have we outlined the thoughts behind why it's currently not in core or how it could be implemented as an extension? And maybe, like, future options for collaborative editing, which kind of overtake this or replace it at some point. Jonathan, you will have to tell a story while he's telling chat, I think. Yep. Nope. I'm just quickly I'm quickly scanning back through here to see if there was anything that we missed. I think we've covered the general requirements here. And I agree that longer term, I think, you know, ideally collaborative editing solves this problem outright. Right? Because then you've got field level notification of who's making changes, when they're making changes. It's real time. You see the changes in real time. But that's a story for another day. This this particular use case, I really like the idea of we can potentially put some solutions out into the wild, help us identify what are the edge cases. Because even with collaborative editing, what are the edge cases we're gonna run into? What are things that can happen or will happen? You know, relational always creates the complexity. Right? When you start digging into relationals and, you know, at what point are you locking or not locking, what points are you notifying, not notifying, handling some of those cases. And collaborative may just make that all go away. There may not be edge cases other than speed and performance of getting notifications back and forth, for the users. But, Tim isn't allowed to participate in these Oh, versions. Versions. Should be fun. Yeah. Versions. We haven't really talked about versions in this whole thing. Right? That is yeah. You're not allowed to participate. I don't think so. You also versions. There's a thing like versions. Yeah. That would make it a lot more difficult. Although I'm sorry though. Do for for the for the extensions, you can build your own. Right? That's an option. You can start with that today. You bring it to a very good point. We as the core team, I will get this in as a request into the Directus Labs extensions group. So that there is a core team that is working custom extensions as part of the marketplace. That's where things like yeah. You may have seen it today, but I have this I actually have this one installed. I love this one. The spreadsheet. Right? The spreadsheet layout, this ability to edit these things live right here. Fantastic. Love it. This has been one that was that's been asked for since the day I joined. I've I've heard people asking for spreadsheet style layout. So I think I remember, Ben asking for this feature, like, in 2,000 well, at 2,021 or something, like, or even before that. So, yeah, it has been on a long road of, like, when will this come? When will this come? When will this get implemented? But doom is bringing up a very good point because, yeah, sure. You don't use versions, but the reason why it's taking us so long to bring new stuff like this into core sometimes is you don't use versions, other people might. So everything that is in core has to work for all the features that we already support. Didn't he set the other way around? Because it's like double negation. Is it like who does not use versions in a sense that, like, everybody use versions? Or am I misunderstanding his message? No. Content versioning is I would think Unless we have fixed the permissioning problem, we still it it's it's very, very limited in its use case options and where you can actually today, because of publishing and editing permissions. So if I wanna main should technically be read only and locked, which is published state. But as soon as you create a content version, if you've got the main record locked, all content versions are locked without changing main. So there are permissioning issues, policy issues right now on the permissioning side that make content versioning difficult to use if not impossible. What's that? Do we have an issue for that? I have to ask now because I was the one Yep. We had is it is it if you have a problem? We've got open feature request for it. Yes. What is feature request? So it's a again, this comes back to, you know, the way the policies are implemented currently. It relies on the main permissioning rather than the version permission version having its own permissioning. Yeah. So you can lock things like I can prevent promoting. I can do things around. Can they create or not create, you know, versions? Can they promote or not promote versions? But the ability to edit that version is dependent on the permissions of main, and therefore, I can't do things like lock main, which means now a user, if they've got the permission, they can edit the published record live without doing it inside of a version. So there's some things that are problematic there. That's a very good point. Yeah. Neither here nor there. Just for the folks here, if you see anything in this particular project, this is kind of core team provided. It's not guaranteed that it's maintained long term, but you have if you see these in the marketplace, right, so Directus marketplace here, if you see those in this particular layout and if you see anyone with the let me put an AI space here. If you see anyone with this little check mark here, that tends to be core team. They've been approved, so you can at least trust that it's coming from a reliable source, in that sense, generally. But marketplace extensions is where this will would show up. So if we get the team to agree that they wanna take this on, you'll see that show up at some point in the next 2 to 4 months, generally. We tend to try and get these we're we're tend to roll out, these lab extensions on a monthly basis. So we've got well, again, no guarantees, but, hopefully, the team will decide that this is worthwhile. I'll put the feedback in to say that this seems like a really cool one to actually have out there in the wild to get this haptic feedback so that we know what we need to watch out for as we continue to implement these kinds of features in Directus Core. So so, Petros, give it a give it an upvote or you're not finding the ticket, open a ticket. Yep. The this is a I ran into it. It was what the the first week that we rolled content versioning out, I had a client reach out. I need to be able to do I'm trying to do x y z, and it doesn't seem to be working. And I tried I tried flows. I tried work around. I tried all kinds of hacks. I could not get around the fact that main is driving permissions for the version. So it's, it is the there's a slight problem there. Although I guess you could with a flow, you could watch on main if main's in published, you could just prevent. But it's a it's a it's a bit hacky in the sense of the user can make a whole bunch of changes. Now try to save that and realize that they were in main to be blocked. But you can at least you could put some validation in place that force prevents that save. Feels like a very good discussion topic for another feature request. So Yeah. Absolutely. The point. Straight to the point. Yeah. Of having versions and promoting and demoting versions, versions. Where we get those permissions from since, like, you correctly said all the permissions are determined by the main items since we have one, like, one permissioning engine in core. And it just looks at the main item, and it actually does it actually has a database evaluate all those permissions for you, which makes it easier in a lot of senses, but makes stuff like this where versions are actually separately maintained JSON blobs of that item a lot more difficult. Yeah. Very true. But we're off topic. Any final parting thoughts on editing, notification? Sounds cool. It's like there's an extension. There those are my final words I wanna say. Yeah. Because I definitely see the US improvement. I see the value in it. I'm just not a 100% sure if we can get it into core properly while keeping all the features we currently already have in mind in a reasonable time frame. Yep. It's always the goddamn time. Well, no. Yeah. But let's let's see what we can do. Put it. Yeah. And, I mean, we can also, like, put it out here. If you feel like, hey, that is an extension I'm gonna develop, reach out to us. Maybe we can help you. That would be awesome. Yeah. I would love to hear people getting just their hands dirty in this. Because in the end, anyone can develop an extension for directors. We try to make it as open and easy as possible. So if you feel like that is something you wanna try, reach out to any of us, and we'll see what the options are. Actually, reach out via the ticket. So post your comments, thoughts, work, other things that you're doing. Let's make sure it gets back to this ticket so that we can actually track that progress. And Yeah. We'll try and do the same. We'll, again, when we we do these kinds of extension developments, we'll tag that back into this ticket. So if it gets accepted and committed and delivered, we'll we'll try to remember to populate that back into the ticket. Alright. Cool. Well, well, honest sales. Wonderful having you guys join on short notice. Yeah. Was this last of the year? As usual. It's exciting. Team, thanks everyone for joining. Have a wonderful rest of your week. And as always, reach out through Discord or through the ticketing systems, and we're here to help us find out. October 15th for the next change log that covers all the changes that will be released in the new version. If you're there. And as always, this will be posted in the request review channel of the Directus IO TV. Chat out everyone. Last chat message. All the feedback from this call is has actually been typed up by Jonathan while we were talking until Thursday. I will see. Yeah. Well, I did. You guys feel free to add if I missed anything. Cheers, everyone. Cheers. Cheers. Bye bye.","22421881-df9b-45ac-9008-a65f73b19434",[440,441,442],"64cc5c90-2113-43d9-b02a-476f57841394","1a4269ad-d7a5-42bb-bf94-b921d6972d5e","37101fb3-a511-4ca6-9005-acc6a5b525fe",[],{"id":133,"number":134,"show":122,"year":135,"episodes":445},[137,138,139,140,141,142,143,144,145,146,147,148,149],{"reps":447},[448,504],{"name":449,"sdr":8,"link":450,"countries":451,"states":453},"John Daniels","https://meet.directus.io/meetings/john2144/john-contact-form-meeting",[452],"United States",[454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503],"Michigan","Indiana","Ohio","West Virginia","Kentucky","Virginia","Tennessee","North Carolina","South Carolina","Georgia","Florida","Alabama","Mississippi","New York","MI","IN","OH","WV","KY","VA","TN","NC","SC","GA","FL","AL","MS","NY","Connecticut","CT","Delaware","DE","Maine","ME","Maryland","MD","Massachusetts","MA","New Hampshire","NH","New Jersey","NJ","Pennsylvania","PA","Rhode Island","RI","Vermont","VT","Washington DC","DC",{"name":505,"link":506,"countries":507},"Michelle Riber","https://meetings.hubspot.com/mriber",[508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576,577,578,579,580,581,582,583,584,585,586,587,588,589,590,591,592,593,594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615,616,617,618,619,620,621,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,641,642,643,644,645,646,647,648,649,650,651,652,653,654,655,656,657,658,659,660,661,662,663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,485,696,697],"Albania","ALB","Algeria","DZA","Andorra","AND","Angola","AGO","Austria","AUT","Belgium","BEL","Benin","BEN","Bosnia and Herzegovina","BIH","Botswana","BWA","Bulgaria","BGR","Burkina Faso","BFA","Burundi","BDI","Cameroon","CMR","Cape Verde","CPV","Central African Republic","CAF","Chad","TCD","Comoros","COM","Côte d'Ivoire","CIV","Croatia","HRV","Czech Republic","CZE","Democratic Republic of Congo","COD","Denmark","DNK","Djibouti","DJI","Egypt","EGY","Equatorial Guinea","GNQ","Eritrea","ERI","Estonia","EST","Eswatini","SWZ","Ethiopia","ETH","Finland","FIN","France","FRA","Gabon","GAB","Gambia","GMB","Ghana","GHA","Greece","GRC","Guinea","GIN","Guinea-Bissau","GNB","Hungary","HUN","Iceland","ISL","Ireland","IRL","Italy","ITA","Kenya","KEN","Latvia","LVA","Lesotho","LSO","Liberia","LBR","Libya","LBY","Liechtenstein","LIE","Lithuania","LTU","Luxembourg","LUX","Madagascar","MDG","Malawi","MWI","Mali","MLI","Malta","MLT","Mauritania","MRT","Mauritius","MUS","Moldova","MDA","Monaco","MCO","Montenegro","MNE","Morocco","MAR","Mozambique","MOZ","Namibia","NAM","Niger","NER","Nigeria","NGA","North Macedonia","MKD","Norway","NOR","Poland","POL","Portugal","PRT","Republic of Congo","COG","Romania","ROU","Rwanda","RWA","San Marino","SMR","São Tomé and Príncipe","STP","Senegal","SEN","Serbia","SRB","Seychelles","SYC","Sierra Leone","SLE","Slovakia","SVK","Slovenia","SVN","Somalia","SOM","South Africa","ZAF","South Sudan","SSD","Spain","ESP","Sudan","SDN","Sweden","SWE","Tanzania","TZA","Togo","TGO","Tunisia","TUN","Uganda","UGA","United Kingdom","GBR","Vatican City","VAT","Zambia","ZMB","Zimbabwe","ZWE","UK","Germany","Netherlands","Switzerland","CH","NL",1773850415652]