Bryant takes on the challenge of building a company intranet portal for fictional company "Initech" (complete with Office Space branding). Watch as he implements Google single sign-on, creates team structures with reporting hierarchies, sets up permission-based content access, and designs an announcement system. Follow along as he transforms Directus into a fully-functional corporate portal where employees see only what they're supposed to—TPS reports and all.
Speaker 0: Welcome back to yet another episode of 100 apps, one hundred hours. I'm your host, Brian Gillespie. This is the show where we try to build or rebuild some of your favorite apps in one hour or less or get publicly shamed trying. Alright. So if you're new here, there are only two rules.
Sixty minutes to plan and build, which always results in fun and chaos. And the second rule, use whatever you have at your disposal, AI tools, past projects, random packages off of the Internet, whatever. It's fair game. Alright. Let's dive in.
Today, we are going to be building a company intranet portal thing. Listen. This was honestly a suggestion from, some of the AEs on our team. Love those guys. They're amazing.
The spec for this, very fuzzy. Right? I I don't even know what is in a company Internet portal sort of thing these days. I do know excuse me. I do know that I don't think I ever enjoyed using one.
So we're gonna try to create something in an hour or less that is helpful and actually decent to use. Let's dive in and hit the clock. Alright. Sixty minutes. Usually, let's kick this off with functionality.
Right? What type of functionality do we want out of an intranet portal? And we're gonna do single sign on for sure. Right? If we're using something internal, we want single sign on maybe through Google or Microsoft or something like that.
We're gonna set that up. Yeah. We wanna be able to track team members and show org structure, you know, maybe provide helpful links. I feel like maybe that could be like a Google Doc, but, you know, we're we're doing the fancy version of this. And then what else do we're gonna have?
You know, maybe I wanna be able to send messages to entire team. Great. Okay. So that is what we're looking at as far as functionality. Let's kind of discuss our data model.
Right? We're going to need honestly, there's new shapes there. Figma, come on now. Okay. I don't I don't need a tour on the new shapes.
Thank you, though. Alright. Getting derailed by the tools already. We're, like, two minutes into this. Alright.
So, obviously, we are using Directus on the back end here. That's gonna give me a lot out of the box, like, user permissions, like users. Right? So we're gonna have users of the application. Those are also gonna double as team members.
So one shot, one kill here. You know, users comes with emails, passwords, first name, last name, job title. We're gonna probably want to add, like, reporting structure, direct reports, reports to, something like that so I can establish those relationships. We probably want, like, a team. So we got different teams within the organization, so that'll be a separate one.
Why is that text so small? Oh, too big. Too big. Okay. Alright.
So we got teams. We got users. What else do we have? You know, maybe, like, pages or resources. I guess really fuzzy.
Right? And this is the part of the show where I draw these amazing arrows that that FigJam allows for. So k. Looks great. You know?
And then maybe there's a relationship here where some team members have access to certain pages and some don't, that sort of thing. Let's see what we can get done. Right? Alright. So what have I got set up already?
Basically, absolutely nothing. I've got a example project or a a Docker Directus instance running here. I've got, you know, just kind of like a standard Docker Compose setup. Don't have much config in this. No collections setup whatsoever.
Alright. So let's tackle first thing on the list. Right? I want to set up single sign on. So if I log out of this instance, I see email and password, log in.
I wanna do single sign on for, like, Google, for instance. Alright. So how are we going to configure that? Well, inside our documentation, we've got a list of, like, the configuration that we could set up. So we're gonna have, like, an auth providers.
So that's a comma comma separated list of auth providers. The driver that we're gonna use and then a provider mode, we'll probably use session. And then for Google, I think the recommendation from our team is to use OpenID. So we've got, like, an OpenID setup here. Now do we have, like, a Google SSO single sign on?
This this is the single sign on dock. Do we have a, like, standard config? Somewhere where we could see, like, a standard config for this. Yeah. There we go.
Alright. So we could set up multiple auth providers, but this looks like the the pretty standard config for, Google. So I'm just gonna copy this wholesale. Right? I'm gonna go inside my Docker Compose, you know, or I could stick this in my ENV file if I wanted to.
I'm not gonna open that because I've got some other secrets in there. As far as the IDE I'm using, this is Cursor. I've been using that this entire season. I found it pretty helpful and especially for quick POCs like this. Alright.
So now we got some config in here. We're gonna have to go and create a client inside Google as well. So let's go to Google Google SSO single sign on, console. Cloud. Google, I think, is the let's see what we got here.
Log in as Directus. Alright. Let's get started configuring. I've got my first project, so you're probably gonna have to create a project if you don't have one. Let's get started.
We're gonna call this 100 apps, one hundred hours. The user support email, that's gonna be me, Brian at Directus. This will be an internal audience. So, my knowledge of Google auth is very minimal, But, obviously, internal is gonna be users only within our organization, which for this works well. Right?
When I'm at directus dot I o. Great. I agree. We're going to spin this up. Okay.
Nice. Nice. Okay. We're gonna create an OAuth client. This is a web application.
Let's call this Directus. Alright. So what do we need to do as far as, like, our JavaScript origins and our authorized redirect URLs? So I think we're gonna have to do something like this where we have local host 8055 as far as our origin. Let's see if we can search our doc single sign on.
Here's a entire guide on this. So you could just search that up. Right? Internal authorized domains. Alright.
So we're gonna authorize JavaScript origins. That's gonna be it's not required, but that's gonna be our directus server address. And then the authorized callback is gonna be slash auth slash login slash Google slash callback. And that's because of the auth provider key that we're providing to the auth provider is Google. Alright?
So that's how we reference this in our actual config. Alright. So, let's add that. That'll be HTTP local host 8 0 5 5. Great.
We're gonna hit create. I certainly hope it doesn't take as long as what it's saying. Alright. So if I expand this, over here we're gonna get a client ID. We're gonna copy this client ID.
That's gonna go here. Great. Then we got a secret. Don't steal my secrets. We're gonna paste that here.
And what else do we need? Let's add an auth Google mode. Google mode. We're gonna make that session. The identifier key is email.
I'm also gonna do allow public registration. Google allow public registration. So we want anybody who comes through our organization to be able to register for this. And one of the other things that we could do, I'm just gonna copy and paste. We probably wanna add, like, a default role setup as well.
We'll get to that in a moment. Default role ID. Let's just actually dive into that right now. Alright. So great.
We are going to sign in. If you remember the admin password, that is okay. So now we got this. Let's go in and create we've got two roles by default. These are out of the box for Directus.
We've got public. This role controls, you know, like, what is available without authentication. And there's also a public access policy. So the access policies are, you know, just groups of different permissions, and then you can add many different access to a role. I love the granularity here, and it's super easy to maintain, like, a complex permission system between the both of these.
What we do wanna do here is basically let's create a new role. We're gonna call this a team member role. Great. Okay. Alright.
So we'll just save that. I'm gonna grab the primary key for this. That's what I'm gonna stick here for the role ID. That's the role that we want folks to have. As far as the policies that we're gonna give them, for now, let's just give them full admin access.
They could change anything. We're gonna scope that down eventually, though. Alright. So the next thing I'm gonna do to test this out, right, I want to I I just want to stop my container. I'm gonna spin that container back up, and I'm gonna open this in.
Let's do an incognito window with the admin login. Admin and example. Password. Great. K.
And now if I log out of this one because I'm I'm already signed in to Google for everything here. Alright. If I hit bryant at directus, create a strong password. Why do I have to create a strong password? Come on, dawg.
Why is it asking me to do this? Use 20 characters or more. Come on, guys. What is it? What are we doing?
I'm gonna do this off screen here. I don't I don't know why this is happening here. Google. Let's create a new password. 20 characters or more.
Directus dot I o. Okay. Oh my gosh. Let's see if this is actually gonna work. Sign in to 100 apps, one hundred hours.
The request cannot be processed because it is malformed, which is not good. Let's try it again. What are we doing wrong here? So we go back to our Google where's our Google application? Yeah.
Sign in. Yes. It's me. Love it when all of this nice security tech gets in our way. What are we missing?
Right? HTTP local host 8055 slash login slash google/callback. Okay. See, this is nice because I've tried to log in to a different account, but I should be able to log in to there we go. So now I am in.
Right? And we can see that Bryant Gillespie is created. This is this is really nice. Right? We could see the auth provider here is Google.
There's the external modifier or identifier, not modifier. Now we've got single sign on. Right? And one of the other things that I could potentially do I think there's config for this if we take a look. Go into auth and SSO.
I could disable the default provider as well if I wanted to so that you could only log in with single sign on. So if we do that, let's see what we've got. Auth, disable default, true. And then I'm gonna restart my container. Let's just log back out.
And now there's only Google to log in. There is no email and password auth options. This will disable it at the API level as well. Super nice thing to do. Right?
If if all you want to allow is single sign on. So, with that done, right, let's let's go in and brand this thing because we obviously need a nice brand. Huge fan of office space. If you're younger and you're watching this, you know, this is an older movie. It pains me to say that.
But, let's use Inatec as the company here. So I'm gonna go into our appearance settings, the project logo. So I could just copy the image address, take full advantage of this a lot of times. So I'll just import the file from a URL. If I hit save, we could see that Inatec logo up there.
I'm gonna use the color picker. Let's pick up, like, a Inateq blue, maybe, I guess we could call that. Right? We got, like, this pale blue color. I'm gonna set up the Directus default theme, and in the namesake of the show, I'm gonna steal from our simple CMS template.
I've got, like, a custom theme that I really like, super happy with. So I'm just gonna steal that paste raw value. There we go. We might wanna swap this out. And one of the nice things about the theming in Directus is, you know, I've got all these nice keys for theming, but I also have the ability just to add custom CSS and do whatever I want.
So in this case, we'll do that as well. And what else are we gonna do? I'm gonna fix this just because it's gonna aggravate me. Alright. So this is where that CSS comes in.
I've got the module bar logo. I'm gonna do something like this where we have dot module bar logo, background. Let's just do white. And we're gonna stick important on that. There we go.
Now we're cooking. And maybe we wanna add, like, a subtle subtle border there. Let's see. What is that gonna be? That'll be our navigation.
That'll be the modules. That'll be the border color, which would be I don't know. Let let's use color mix in sRGB. We'll use the var theme. We're gonna use the primary color and maybe 20% white.
F f f f. And let's set, like, a two pixel border just so we can see it. Alright. There we go. So now we got a little little border action to keep things separated.
I mean, this is not like a super nice mouse over active color, but I'm not gonna get too far into it. Right? This is gonna be the Inatec company portal. And one of the things that's gonna aggravate me is just our font choice here. Like, DM Sans is a newer font.
Maybe we just set this to Arial. Do I have that installed? Would it be Arial? Yeah. I think it is one way or the other.
And then we can set, like, our, let's let's pick something, like, super corporate here. Yeah, Roboto feels pretty corporate to me at this point. We'll do Roboto. So if I just put this in quotation marks, this will go ahead and pull those font files from Google for you. So any Google font, good, bad, ugly, whatever you wanna do, you can include those when you're customizing these themes.
Alright. So now we got Inatek. We've got Roboto. This feels very robotic. This is a sad company worked for fictionally.
So now if I refresh our login screen, we've got this kind of action going on. Looks okay. Maybe we wanna spice this up a bit. Right? So we're just gonna put Bill Lemberg on the login page.
So we'll go to appearance. The public background here, we're gonna import Lemberg. Yeah. We need those TPS reports, and, you know, I will just leave the Favicon blank. There it is.
There we go. Right? So this is the it's beginning to shape up as a perfect company portal. Alright. And one thing I'm gonna do, I'm gonna turn this off, or we're not gonna be able to test, like, our permissions.
So disable default. Let me just spin this back up so we can get, like, an email and password. Log in one more time. Sign out. Okay.
So now I've got my email and password back. Let's dive into the next item on our list, single not single sign on. We just completed that one. We're gonna dive into tracking team members and showing, like, an org structure, providing helpful links, and maybe try to send messages to the entire team. Alright.
So, we've already got users through Directus. Right? We've got our user library here. We could see that Brian logged in, etcetera, blah blah blah. Looking great.
Let's add this team functionality. Right? And we probably want the ability to create new teams and adjust teams and etcetera. So let's just create a collection for this. I could also just adjust the users collection, which we'll do in a few.
But for this case, I'm gonna create teams. So each team, we need a primary key field. I could use an auto incremented integer. We can use a manually entered string. You know, I mean, like, in this case, maybe we use a manually entered string because I'm not expecting to have a a ton of teams, and, you know, the way we reference those is probably not gonna change much.
Alright. Do we need any of these default fields? I'm not really sure. I don't think so. So we'll just skip that.
So we got a team. We're gonna give a team name. Pretty simple. We'll make sure that is required. Great.
The ID, we can make sure this is like URL safe, so we'll just enable Slugify through the interface settings. And we've got a team, we've got a name. Now what we're gonna do is set up a relationship between we probably got, like, a a parent and child relationship between teams as well. Right? One team could roll up to another team, could roll up to etcetera.
You know, we could classify things like a team lead, and then we're gonna have, like, an organizational structure where we have direct reports for each user as well. So let's set up that first one. Right? Each team needs a leader. We'll just call this team lead.
So here, I'm using the direct us relationships. I'm gonna set up a many to one because I only want one leader within the team. Could certainly set up multiple leaders if I wanted to, but for the related collection here, I'm gonna use direct us users. And as soon as I hit on the right one, you'll see that kind of turn blue and lock in. I can also just go over here and hit the system collections and do it that way as well.
We're gonna show a link, and I'm gonna open up Advanced Field Creation Mode just so we could see this. What I'm also gonna do here, I can create the corresponding relationship at the same time. And this is where data modeling becomes very important. Right? Because, do we necessarily want this relationship here?
Because I could be leading, you know, I guess I could lead multiple teams. So we will add this relationship here, but, you know, if you need, like, multiple team leads, obviously, you're looking at, like, many to many. We're gonna display the direct as user, show the user in a circle. We'll set that up. So there's the team lead.
And now if I were to go and check our data model for users, right, I should also have a Teams option here. Right? There's our Teams. So we can specify the do I actually want that? The we're gonna have Teams as another thing, like, teams that we're a part of.
Let's delete this, recreate this relationship, one to many, and teams leading. It's not t lead teams leading. Yeah. Leads, teams, teams leading, I guess. Naming stuff is I say this on every episode, I feel like, but naming stuff is the hardest thing in programming without a doubt.
Alright. There we go. We got the display table, and we're gonna show the name. Cool. Team lead already has an associated relationship.
What are we doing here? Have I bricked this whole thing? Let's see what we've got. Can I get access to the relationships here? If I reload what is going on?
Have I totally bricked Directus with this relationship? What have I done? People, what have I done? Permissions, policies, fields, direct us users, team leads. Now if I refresh, did this sort it out?
What have I done? Alright. Teams. Team lead. I don't understand.
Teams users leading does not exist. Let's just try down and up. I goofed up our relationship somehow. I think we can get this back. We can solve this problem.
Now I would be remiss not to take this opportunity to talk about the data mirroring inside Directus. So, you can install Directus onto any existing SQL database, whether that's Postgres, SQLite, MySQL. Directus, like, bootstraps these name space collections as you see here, but everything else is just standard SQL. Right? There's nothing direct as specific about our team teams collection here.
And as I go through and build these out, let's try this one more time. One to many relationship or actually a many to one here. We're gonna have a team lead. We'll pick our direct to users collection, and then in the relationship settings, I'm gonna add that one, teams leading. I hate that, but that's what we're rolling with for now.
We're gonna create this relationship. Right? Now, we could see that that change is being mirrored here. There's my team lead. Amazing.
Right? So I could go in. We could create a new team. We could do team America. Let's just call it bride's team or let's do marketing, I guess.
Marketing. Great. Mister admin user can be our team lead, and then I can go in and add additional teams. Right? Product.
Got the product team. Sales. Great. You know, we could get really fancy and add icons for all these teams. Let's Let's just check how we're doing on time.
We got thirty minutes left. Let's keep cruising. Right? Alright. So we got team leads.
Seems like enough. Let's go in and add our team members. Right? Teams members. Maybe add an icon, though.
Team. Is there a group? This is a collective. There we go. Group.
Looks great. Amazing. Teams. Okay. So now I want to you know, I could potentially sit in multiple teams, I guess.
You know, obviously, you would hope that that you would have a, like, a one to one relationship within the team, but, yeah, I again, hey. Like, data modeling issue, do could a team user belong to multiple teams? I I'm gonna say yes in this case just because I don't know. You know, I maybe, like, you wanna use this as, like, a project team as well. So that's that's how we'll play this.
Alright. Teams, we're gonna call this team members. Okay. I'm just gonna create a junction collection manually here. Like, Directus will create this for you if you want.
I just get in the habit of wanting total total control over everything. I'm just gonna hide this guy. Alright. So now we're gonna link members to our team. And for that, we're gonna reach for our many to many relationships inside Directus.
We're gonna call this members. The related collection is gonna be users, Directus users. Great. And I'm gonna go to the relationship tab. So on almost every episode, you'll see me jump into the advanced setup.
Once you get into the basics with Directus, highly recommend it, because it gives me total control over the fields that are created in the junction collection. Right? Instead of using team ID, I wanna use team, and I'm just gonna use user here because I like to be OCD about certain things. Right? So now we're gonna add this teams field to direct us users so I can, you know, potentially use that in our permissions.
And on all of these relational triggers, I'm gonna set these to cascade, right, because there's no sense in keeping this relationship in there. Alright. We could set up our interfaces, display related values. Great. There we go.
We got our team members. I can go in and set, like, a first name, last name. I could even go in and add, like, an avatar here if I want to. Oh, avatar. There's like a little thumbnail helper.
Oops. Let me just edit the raw value. You could see this is just the mustache syntax to populate these values, but inside the interface it shows very nicely. Alright. So now we got our team.
Let's add some members to the team. I'm gonna add Bryant and Tess Tess to the marketing team. Great. There's our team members. I'm gonna give I gotta upload a photo here just to make sure I got something.
Right? There we go. There's my ugly mug. There we go. So now I'm not seeing myself in there.
We need to fix that as well. Here's where I can just copy these values. So I'll hit copy raw value. I'm just gonna paste that in the interface display template. So the difference between interface and display, the interface shows inside the form.
Right? This is the interface. Here inside, like, the teams, if I were to look at the members, that's our display. So I wanna show the same thing. I could see those members.
There's our team members. There's the team lead. Great. You know, I can prevent editing on all of this. Amazing.
Solid. Right? Alright. So now, you know, we've got team members. Yeah.
Let's add, like, our reporting structure as well with would that be within a team? This is where we get into, like, splitting errors. Right? In this case, I'm gonna add this to the user level. I guess you could add it at the the team member level, but, you know, let's not do that.
So, anyway, I'm gonna go into our system collections here. We're going to create some new fields here. So you can already see I've got two fields. The system fields are locked down. I can't change those, but, I can add new fields to this collection, to this table in the database.
So we're gonna add a, like, a recursive relationship here. So for that, let's just use the one to many, and this is gonna be our direct reports. Right? This is gonna be direct as users, and the foreign key would be reports two. Again, you know, naming structure here is hard.
It would be great to have help on that side. But, alas, this is not live. I am just talking to myself. Alright. So there's our display template.
We're gonna show a link to the item. If I want to, I can just, like, show this relationship. This is gonna be created. Reports to, direct reports. Pretty pretty straightforward.
Right? Direct report. So you could see that it's created, like, two two or two fields here. And if I look at, like, my and, like, here's the teams leading. Here's the teams I'm a part of.
And let's say, mister I this is gonna get confusing as I'll get a test direct report. Test manager. Okay. Alright. So I got two users here.
I have I've got a test direct report. I don't see the other field, right, who I report to, so we can go in and edit that as well. I think by default, we hide that. Maybe I just wanna show that here. So we're gonna show reports to go in, adjust this.
So those are my direct reports. Here is reporting to the test manager. And now if I go into, let's say, the test manager, let's take a look at that, there's the direct reports. I can also make this like a tree view as well. So if I go into users, on these recursive relationships, we can go in and set this up to use our tree view so we have this recursive relationship.
I'm just gonna copy this, we've got tree view, paste that there. Now if I go to mister test manager, I can see my direct reports, but I can also see I'm the test manager in this scenario. I'm not Brian Gillespie. I can see the direct reports of that person and, like, all the way down the chain potentially. Right?
So if I have mister CEO, the test manager rolls up to mister CEO, I can drill all the way down the tree, the tree, as they say. Alright. So now that we've got those relationships set up, you know, it would be nice to show, like, an org chart or something there. Let's focus on on bigger challenges at this point. Like, how can we send messages to all these folks?
Right? We wanna provide some helpful leaks, send messages. You know, maybe we want to have a specific page. You know, as far as, like, a portal, you probably got, hey, like, pages, you know, like, struggle with what to name. Like, here's just, like, helpful content that we want to create.
Right? So we're just gonna add these status, is this published or not? Great. Let's give this a title. And because this is internal, we we don't really need anything like a slug.
You know, I could potentially add it if I wanted to, but, this is the page title. Here's the markdown content. Right. Great. This is our content, page contents.
And then trying to think of the best structure here. Like, will we set up, like, different categories? I mean, this is kinda getting into, like, knowledge base level. You know, I basically, just trying to set up a structure here. Let's say marketing team should have access to that post.
Let's say let's create another one. Marketing should not have access. Right. Alright. And let's kind of get into let's step into this as well.
Right? Tested example, password. They've got our team member role. Cool, test at example, password. Alright, so this is what our other user is gonna see, And right now, the team member role, as we specified, has admin access, which let's go ahead and lock that down.
Right? So let's create a new policy, team member I'm just gonna call this app access. So we're gonna give app access to the team member, and that should hide stuff like settings that we don't want them to configure. How we doing on time? Nineteen minutes remaining.
Cruising. Alright. Team member app. Let's go back to our team member role. We're gonna remove this administrator policy.
Alright. We don't wanna give total access. We want to give team member app access. Great. And I think I just locked myself out of the system.
Fun for everyone. Right? But if I refresh over here where I'm logged in as our test direct report, now I don't see any of our content. I don't see any of the settings. You know, I can access the dashboard, see the file library, etcetera.
I'm gonna dive back into table plus here. We could see there's our team members. I'm just gonna go in and quickly fix this goof up that I just made where I removed myself as an administrator. There we go. Alright.
So now if I reload that, I've got access back again. And again, you can see this is all just underlying SQL. Nothing nothing fancy here. Right? Alright.
Marketing should have access to this. Marketing should not have access. You know, I would probably go one layer deep if I had, like, a a lot of these and say, okay. You know, I'll group these by categories. And, you know, like, that way you could restrict access, but let's just do it this way.
We're going to create another mini to mini teams with access to this content. Yeah. What else could we do? A Couple other ways we could do this. Right?
Yeah. Let's just do the many to many to keep it relational. Teams. Team access. Teams access.
Teams. Great. Show a link to the item. Alright. And we could see page, team access.
That's gonna be the page. That's gonna be the team. This is pages that they have access to, and I'll show you why this is gonna matter in a moment. Alright. So title content, marketing should have access.
We can say marketing. Great. Pages marketing should not have access to. That's gonna be product and sales should have access to those. Okay.
Now by default, no permissions are set for collections. Right? So if I go into team member app policy, I've just got the system collections that they need. This is why I love the access policies because I can also keep those separate. And I could say can access pages or read pages or something like that.
Right? I don't have to do any of these other options. I can just go in and say pages, pages team access. So by default, let's set these up first. Maybe we wanna be able to read the teams.
That's fine enough, we can see all the team members. But when it comes to page access, right, what we want is to restrict that based on teamaccess.ID. No. Teamaccess.team equals or is one of current user. So this is a dynamic variable inside Directus, and, basically, we can go through the tree here.
So this will get us our current user, like, who's logged in. We could go through teams and then Teams.team. I believe Teamsteam. Is that gonna be our junction table collection? Should be.
Right? Here's our team members. There's the team. Alright. Let's just test this out and see.
I don't see any nothing. Right? Well, we created that access policy, but we didn't apply it to our team member role. So here's our policies. Right?
Team member app. They can just log in to the app. And now we're gonna give them access to pages. Hit save and say. And if I did my homework or if I did everything correctly, this should be all set up.
Right? So there's marketing. I could see these. I can't edit any of them. And as far as the pages go, marketing should have access to this, but they should not have access to that.
Bada bing, badda boom. That's all done. Right? Amazing. It just works out of the box.
And the beautiful part about this is not only is this through the UI, right, where I'm logged in, this is respected throughout the API as well. So if I, like, do this API call, oh, I don't need to add API in front of it. Used to working with Nuxt. Items dot pages, there's that specific page. But if I just fetch items pages, again, I'm only seeing the one page.
Whereas if I do it over here in this browser, you could see I've got two pages, because I am logged in as an admin, and admins have full permissions. Great. Alright. I'm gonna check this off as the helpful links. You know, couple ways we could send messages to our users.
We've obviously got, like, an email. I don't think we have a phone field in here. We could add a field to track phone numbers for our team members. We could, you know, message them via Twilio without, say, exposing, phone numbers or private information to other members of the team. Right?
Do we have enough time for something like Twilio? Let's just let's cover the email use case. Right? I want to craft a message to, let's say, team announcements. Right?
And I want to draft this message. I wanna send it out to all of our team members. Too many n's in there. Thank you. Spell check.
Date created. Cool. We'll generate a UID. Got it. And we got the message body, and we want to do what?
Message body is just gonna be WYSIWYG. That's our content. We could just call it content, or, yeah, you might even do text. Fine. Keep it simple.
Alright. Alright. And then we're gonna do, like, a mini to mini for our teams that we wanna message. Right? Maybe I wanna message individual teams.
So we'll do the related collection. And, again, like, behind the scenes right now, Directus Us is crew will create those junction tables for me. Again, I just won't have the control unless I go into this team announcement teams, team announcement teams, team announcement. Let's just call it announcement. We're gonna call that team.
Alright. And this is like a, an insane way to do this, but I I could really just create, like, a a flow. But maybe I wanted to, like, schedule this as well. Right? Okay.
So here's our team announcements. I want to add a announcement for the marketing team. And, hey. This is an announcement from me. Alright.
So, you know, maybe I'm, like, drafting this. You know, maybe I don't wanna send this right away. Maybe we track, like, a another time stamp for date sent, date scheduled, that sort of thing. But we've got this announcement. Right?
I there's a couple of ways that we could do this as well, but let's create a flow for this. Right? So I'm gonna go in, let's say, send announcement, and we're just gonna manually trigger this. So once we have the announcement, we wanna send it out. We're gonna require a confirmation.
Send announcement. K. And I could actually use, like, this flow to, you could build forms into this, right, which is another nice thing. I could say, hey, form field. This is a field.
So when you're doing these manual flows inside Directus, it's always nice to have this ability to just stick a form field in there. And from here, hit send announcement. I can add something to this field, run this flow, and that will give me some data. Right? So here I can see the body.
Here's the keys that we're receiving. So this is the actual announcement. And we could do something like this, where we're going to, what are we going to do? We're going to read the data. So we're going to get the announcement.
Announcements. That's going to be your Team Announcements. The IDs here are gonna be trigger dot body dot keys. I'm just gonna hit enter to save that. That.
I don't need to run a filter on that. And then, also, I'm gonna get the team members. Right? So if I look at my payload one more time oh, no. We'll get the we'll get the team members from the actual announcements.
Right? So here, I'm gonna do something like this where I have fields. Fields allows you to fetch what you need in a GraphQL like manner even though we're using REST. So I don't necessarily have to reach for the complexity of GraphQL if I don't need it. So I'm gonna get all the root level fields with an asterisk, then I am going to get teams, and I want teams dot member dot star.
I'm just gonna test that out and see. I think it's depending on how we set up that. We've got teams, team members. Oh, it's gonna be user, not member. Alright.
Let's test this out. Teams dot user teams dot user dot star. We'll save that. Alright. Now, what do we got?
Six minutes left. Let's crush this here. We're going to send the announcement. Send that out. Hit flows.
We get send announcements. There's our payload error, UUID. Some kind of issue here. Oh, we're passing an array. Let's not pass an array.
Let's just pass the array of arrays. Let's just pass the single array. We're gonna hit send announcement here. Test that out. Get our flow.
Send announcement. This is an announcement. Okay. So we got teams. I'm not getting the actual team members that we need here because we need, like, teams.
Teams. I should be getting the team data. Right? And I should be getting that. Teams.
Why am I not getting that data that I want? Let's try it again. Send flows. Send announcement. We're gonna take a look at this.
Okay. Okay. Team.team.marketing. And then can I get through users from there? Teams.starTeam.star.
Team Members Star. Love waiting through a good data model here. Let's see what we get now. Test, flows, send announcement. Okay.
So now we're getting closer. Right? Here's our team. There's our members. We got the users.
Those are what we're trying to get to. Teams.user.star. This is gonna give me the emails of the team members. Once I get that, send announcement. Flows.
Is this gonna give us the data of what we want? Yes. There we go. Alright. And, really, all I need here is the email.
This is where I'm going to turn to AI for, like, three minutes worth here. Let's just open cursor. Write a function, a JS function that returns the array of emails for this sample data. There we go. First, we need to okay.
Spit something out, friend. Data dot teams, that flat map. Okay. So there's a simple this is writing TypeScript, which we're not gonna be able to use in flows, but you do have the ability to run just JavaScript. We'll call this transform.
Let's just pop in that function. We'll remove the types. Data data dot teams. Alright. So we're gonna do this.
We're going to get the, what did we call that last one? This is just announcement. We're gonna get the announcement data. So here's what we're gonna do. We'll do, this doesn't need to be async.
We're gonna say const, actually, we're just gonna return get emails, and the data is gonna be dot data dot announcement. So as you go through a flow, like, each step will append the result under the key. So this data object that we pass, I can access the announcement data for that step through this. And then the final step here is gonna be sending an email, which I don't think I've actually I can't remember if I got emails hooked up or not. We're gonna get this transform.
We're going to reference that. So I'm gonna send the email. We're going to say transform, transform. And I'm gonna make sure that that is that should be passing an array. So we're just gonna use the raw value.
I don't have a this is an important announcement. And then for the WYSIWYG content, we are going to do announcements dot text. Alright. We got forty five seconds. We're only gonna get one go at this probably.
Let's see if this is actually gonna work. Run this flow. Send announcement. Is it actually going to run the flow to brian@directus.io? Did I configure this?
Yes or no? Come on, baby. Come on. It shows my email is disconnected. Gmail.
Come on. Come on, Gmail. Fifteen seconds. Are we gonna get an announcement? Are we gonna get an announcement?
Are we gonna get an announcement? No. I don't think I've got email connected inside this actual Docker Compose file, to be honest with you. Too bad. Too bad.
We didn't get to the last one. That sucks. Sending messages to the entire team, it should go through. And if I were on a Directus cloud instance, it probably would go through, but I don't have the actual email drivers conf like, the config set up for that. So, like, no emails are going through there.
You know, obviously, I would wanna take the time as a next step to just go ahead and do that. So, if I go to, like, the direct us documentation and I look for email, you know, I would want to set up, like, my either my SMTP settings or Mailgun or SES, to actually send those emails out. But I will I I don't know if we're gonna call this a win or not because it did run this flow. It did give us the emails. We're not getting any errors there.
We're just, yeah. I don't know. Let's let's just do the explosion anyway. That's my favorite animation of this whole series. So that is building a company Internet internal portal.
Hope this was a helpful look at just how powerful Directus is. I will catch you on the next episode of 100 apps, one hundred hours.