Repository navigation
feat(sim-links): organization Sim links (go links) with sim/<name> redirects #9484
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+34,067
−39
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
65d2354
feat(sim-links): organization Sim links (go links) with sim/<name> re…
waleedlatif1 7e903d4
refactor(sim-links): share pagination, clipboard, path, and audit hel…
waleedlatif1 c964348
test(sim-links): pin destination origin, encoding, and http-only inva…
waleedlatif1 3626d7a
feat(sim-links): real-HTTP E2E suite, docs, and field-level name conf…
waleedlatif1 3441290
chore(sim-links): regenerate docs manifest
waleedlatif1 7e4278c
fix(sim-links): require a closed authority before {*} so values canno…
waleedlatif1 d71e3c5
fix(sim-links): read writes in their transaction, lock the editor whi…
waleedlatif1 c0d9cf3
fix(sim-links): infer use-case input from execute and use the footer'…
waleedlatif1 a51b236
feat(sim-links): show link details, count visits with a most-used vie…
waleedlatif1 653acf7
fix(sim-links): keep slashes in typed values, show most-used as one p…
waleedlatif1 549988a
improvement(sim-links): count visits best-effort, drop the unused vis…
waleedlatif1 3dfac32
improvement(sim-links): illustrated empty state, server-safe page col…
waleedlatif1 7a7e759
fix(sim-links): harden destinations against dot segments, control cha…
waleedlatif1 d427eb3
improvement(sim-links): hold the leading link in the empty-state graphic
waleedlatif1 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| --- | ||
| title: Sim Links | ||
| description: Short sim/ links that take everyone in your organization to the right page | ||
| --- | ||
|
|
||
| Sim Links are short, memorable names for the pages your team opens often, like `sim/handbook` for the employee handbook or `sim/okta` for your sign-in portal. Anyone in the organization can open them, with or without a Search seat. They work like go links in other tools. | ||
|
|
||
| Open **Sim Links** in the organization sidebar to see every link in your organization, with who created it, how often it's opened, and when it last changed. Search by name, destination, or description, and select **Most used** to see the 50 links your team opens most. | ||
|
|
||
| ## Open a link | ||
|
|
||
| Go to `https://sim.ai/sim/<name>`, for example `https://sim.ai/sim/handbook`. On a self-hosted deployment, use your Sim address instead of `sim.ai`. Sim sends you to the link's destination. If you aren't signed in, Sim asks you to sign in first, then continues to the link. | ||
|
|
||
| Names ignore case and punctuation, so `sim/Team-Handbook`, `sim/team_handbook`, and `sim/teamhandbook` all open the same link. The destination still applies its own permissions. | ||
|
|
||
| If nobody has created the link yet, Sim offers to create it with that name. | ||
|
|
||
| ## Open links from the address bar | ||
|
|
||
| Add Sim as a site search shortcut in Chrome so you can type `sim handbook` instead of the full address: | ||
|
|
||
| 1. Open Chrome **Settings → Search engine → Manage search engines and site search**. | ||
| 2. Next to **Site search**, select **Add**. | ||
| 3. Enter `Sim` as the name, `sim` as the shortcut, and `https://sim.ai/sim/%s` as the URL. | ||
|
|
||
| Type `sim`, press **Space** or **Tab**, then type a link name such as `handbook` or `jira/123` and press **Enter**. | ||
|
|
||
| Chrome administrators can add this shortcut for everyone with the `SiteSearchSettings` policy, using the same shortcut and URL. | ||
|
|
||
| ## Create a link | ||
|
|
||
| 1. Open **Sim Links** and select **New link**. | ||
| 2. Enter the **Destination URL**, a full `https://` address. | ||
| 3. Enter a **Name**. Use letters, numbers, and `. : @ & ~ - _`. | ||
| 4. Optionally add a **Description** so teammates know what the link is for. | ||
| 5. Select **Create**. | ||
|
|
||
| Select **Copy link** from a link's menu to share it. | ||
|
|
||
| ## Add values to a link | ||
|
|
||
| Anything after the name is added to the destination. If `sim/docs` opens `https://docs.example.com`, then `sim/docs/billing/invoices` opens `https://docs.example.com/billing/invoices`. | ||
|
|
||
| To place a value somewhere else, put `{*}` in the destination URL: | ||
|
|
||
| | Destination URL | You open | Sim opens | | ||
| | --- | --- | --- | | ||
| | `https://jira.example.com/browse/PROD-{*}` | `sim/jira/123` | `https://jira.example.com/browse/PROD-123` | | ||
| | `https://wiki.example.com/search?q={*}` | `sim/wiki/expense policy` | `https://wiki.example.com/search?q=expense%20policy` | | ||
| | `https://github.com/acme/{*}/issues/{*}` | `sim/issues/api/42` | `https://github.com/acme/api/issues/42` | | ||
|
|
||
| Each value fills the next `{*}` in order, and the last `{*}` takes everything that remains. A link with `{*}` can also have a **Default destination** on the same site, which opens when you use the link without a value. `{*}` can't replace the domain, and values can't be `.` or `..`. | ||
|
|
||
| ## Control access | ||
|
|
||
| Under **Access**, the creator of a link can choose: | ||
|
|
||
| - **Unlist**: hides the link from the Sim Links page for everyone except the creator and organization admins. Anyone who knows the name can still open it. | ||
| - **Restrict editing**: only the creator and organization admins can edit or delete the link. Everyone can still open it. | ||
|
|
||
| Without restrictions, any member can edit or delete a link. Only the creator and organization admins can change its access settings. Creating, editing, and deleting links is recorded in your organization's [audit logs](/platform/enterprise/audit-logs). | ||
|
|
||
| ## Related docs | ||
|
|
||
| - [Find content](/search/find-content) |
34 changes: 34 additions & 0 deletions
34
apps/sim/app/api/organizations/[id]/sim-links/[linkId]/route.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| import { deleteSimLinkContract, updateSimLinkContract } from '@/lib/api/contracts/sim-links' | ||
| import { | ||
| defineInternalJsonRoute, | ||
| internalOrchestrationErrorPolicy, | ||
| internalRateLimits, | ||
| internalSessionAuth, | ||
| } from '@/lib/api/server/routes' | ||
| import { presentSimLink } from '@/lib/api/server/sim-link-presenters' | ||
| import { deleteSimLink, updateSimLink } from '@/lib/sim-links/application/use-cases' | ||
|
|
||
| const policy = { | ||
| auth: internalSessionAuth, | ||
| rateLimit: internalRateLimits.user({ bucketName: 'sim-links' }), | ||
| errorPolicy: internalOrchestrationErrorPolicy, | ||
| staticResponseHeaders: { 'Cache-Control': 'private, no-store' }, | ||
| } | ||
|
|
||
| export const PUT = defineInternalJsonRoute({ | ||
| ...policy, | ||
| contract: updateSimLinkContract, | ||
| operation: updateSimLink.operation, | ||
| useCase: updateSimLink, | ||
| mapInput: ({ params, body }) => ({ organizationId: params.id, linkId: params.linkId, ...body }), | ||
| present: (link) => ({ link: presentSimLink(link) }), | ||
| }) | ||
|
|
||
| export const DELETE = defineInternalJsonRoute({ | ||
| ...policy, | ||
| contract: deleteSimLinkContract, | ||
| operation: deleteSimLink.operation, | ||
| useCase: deleteSimLink, | ||
| mapInput: ({ params }) => ({ organizationId: params.id, linkId: params.linkId }), | ||
| present: () => ({ success: true as const }), | ||
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| import { createSimLinkContract, listSimLinksContract } from '@/lib/api/contracts/sim-links' | ||
| import { | ||
| defineInternalJsonRoute, | ||
| internalOrchestrationErrorPolicy, | ||
| internalRateLimits, | ||
| internalSessionAuth, | ||
| } from '@/lib/api/server/routes' | ||
| import { presentSimLink } from '@/lib/api/server/sim-link-presenters' | ||
| import { createSimLink, listSimLinks } from '@/lib/sim-links/application/use-cases' | ||
|
|
||
| const policy = { | ||
| auth: internalSessionAuth, | ||
| rateLimit: internalRateLimits.user({ bucketName: 'sim-links' }), | ||
| errorPolicy: internalOrchestrationErrorPolicy, | ||
| staticResponseHeaders: { 'Cache-Control': 'private, no-store' }, | ||
| } | ||
|
|
||
| export const GET = defineInternalJsonRoute({ | ||
| ...policy, | ||
| contract: listSimLinksContract, | ||
| operation: listSimLinks.operation, | ||
| useCase: listSimLinks, | ||
| mapInput: ({ params, query }) => ({ organizationId: params.id, ...query }), | ||
| present: ({ links, nextCursor }) => ({ links: links.map(presentSimLink), nextCursor }), | ||
| }) | ||
|
|
||
| export const POST = defineInternalJsonRoute({ | ||
| ...policy, | ||
| contract: createSimLinkContract, | ||
| operation: createSimLink.operation, | ||
| useCase: createSimLink, | ||
| mapInput: ({ params, body }) => ({ organizationId: params.id, ...body }), | ||
| present: (link) => ({ link: presentSimLink(link) }), | ||
| }) |
5 changes: 5 additions & 0 deletions
5
apps/sim/app/o/[organizationId]/components/organization-page/constants.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| /** | ||
| * The home surface's reading column, so every organization page shares its width. Kept out of | ||
| * the client component module so server-rendered loading views receive the class string itself. | ||
| */ | ||
| export const PAGE_COLUMN_CLASS = 'mx-auto w-full max-w-chat px-6' |
2 changes: 1 addition & 1 deletion
2
apps/sim/app/o/[organizationId]/components/organization-page/index.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| export { PAGE_COLUMN_CLASS } from '@/app/o/[organizationId]/components/organization-page/constants' | ||
| export { | ||
| OrganizationPage, | ||
| type OrganizationPageTab, | ||
| PAGE_COLUMN_CLASS, | ||
| } from '@/app/o/[organizationId]/components/organization-page/organization-page' | ||
| export { useOrganizationPageFilters } from '@/app/o/[organizationId]/components/organization-page/use-organization-page-filters' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| import { cn } from '@sim/emcn' | ||
| import { HEADER_ACTION_CLUSTER, PAGE_HEADER_BAR } from '@/components/page-header-bar' | ||
| import { PAGE_COLUMN_CLASS } from '@/app/o/[organizationId]/components/organization-page' | ||
|
|
||
| export default function SimLinksLoading() { | ||
| return ( | ||
| <div className='flex h-full flex-col bg-[var(--bg)]'> | ||
| <div className={PAGE_HEADER_BAR}> | ||
| <div className={HEADER_ACTION_CLUSTER} /> | ||
| </div> | ||
| <div className={cn(PAGE_COLUMN_CLASS, 'pt-8')}> | ||
| <h1 className='text-[var(--text-primary)] text-lg'>Sim Links</h1> | ||
| <p role='status' className='mt-4 text-[var(--text-muted)] text-small'> | ||
| Loading Sim links | ||
| </p> | ||
| </div> | ||
| </div> | ||
| ) | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| import type { Metadata } from 'next' | ||
| import { notFound, redirect } from 'next/navigation' | ||
| import { getSession } from '@/lib/auth' | ||
| import { organizationRoutes } from '@/lib/navigation/paths' | ||
| import { isSimLinksEnabled } from '@/lib/sim-links/feature-flag' | ||
| import { buildAuthCrossLink } from '@/app/(auth)/auth-redirect' | ||
| import { SimLinks } from '@/app/o/[organizationId]/links/sim-links' | ||
|
|
||
| export const metadata: Metadata = { title: 'Sim Links' } | ||
|
|
||
| interface SimLinksPageProps { | ||
| params: Promise<{ organizationId: string }> | ||
| } | ||
|
|
||
| export default async function SimLinksPage({ params }: SimLinksPageProps) { | ||
| const { organizationId } = await params | ||
| const session = await getSession() | ||
| if (!session?.user) | ||
| redirect( | ||
| buildAuthCrossLink('/login', { | ||
| callbackUrl: organizationRoutes(organizationId).simLinks, | ||
| isInviteFlow: false, | ||
| }) | ||
| ) | ||
| if (!(await isSimLinksEnabled(organizationId))) notFound() | ||
| return <SimLinks organizationId={organizationId} /> | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| import { createSerializer, parseAsString } from 'nuqs/server' | ||
|
|
||
| /** `create` opens the new-link editor, prefilled with its value as the name. */ | ||
| export const simLinkViewParsers = { create: parseAsString } as const | ||
|
|
||
| export const serializeSimLinkView = createSerializer(simLinkViewParsers) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.