Skip to content
40 changes: 17 additions & 23 deletions apps/docs/content/docs/search/sim-links.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,62 +3,56 @@ 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.
Sim Links are short names for pages your team opens often, like `sim/handbook` or `sim/okta`. Every member of your organization can use them, with or without a Search seat.

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 **Sim Links** in the organization sidebar to see your organization's links. Search by name, destination, or description, or use **Sort → Opens** to see the most used links.

## 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.
Go to `https://www.sim.ai/sim/<name>`, for example `https://www.sim.ai/sim/handbook`. On a self-hosted deployment, use your Sim address. If you aren't signed in, Sim asks you to sign in first.

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.
Names ignore case and punctuation, so `sim/Team-Handbook` and `sim/teamhandbook` open the same link. If a link doesn't exist yet, Sim offers to create it.

## 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:
Add Sim as a Chrome site search shortcut to type `sim handbook` instead:

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**.
3. Enter `Sim` as the name, `sim` as the shortcut, and `https://www.sim.ai/sim/%s` as the URL.

Chrome administrators can add this shortcut for everyone with the `SiteSearchSettings` policy, using the same shortcut and URL.
Type `sim`, press **Space**, then type a link name and press **Enter**. Chrome administrators can add the shortcut for everyone with the `SiteSearchSettings` policy.

## 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**.
2. Enter the **Destination URL** and a **Name**. Names can use letters, numbers, and `. : @ & ~ - _`.
3. Optionally add a **Description**, then select **Create**.

Select **Copy link** from a link's menu to share it.
To share a link, right-click it and select **Copy link**.

## 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`.
Anything after the name is added to the destination: if `sim/docs` opens `https://docs.example.com`, then `sim/docs/billing` opens `https://docs.example.com/billing`.

To place a value somewhere else, put `{*}` in the destination URL:
To place a value elsewhere, 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 `..`.
Values fill each `{*}` in order, and the last `{*}` takes the rest. A link with `{*}` can set a **Default destination** on the same site for when no value is given. `{*}` can't replace the domain.

## Control access

Under **Access**, the creator of a link can choose:
By default, any member can edit or delete a link. The link's creator and organization admins can change two options under **Access**:

- **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.
- **Unlisted**: only the creator and admins see the link on the Sim Links page. Anyone with the name can still open it.
- **Restricted**: only the creator and admins can edit or delete the link.

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).
Changes to links are recorded in your organization's [audit logs](/platform/enterprise/audit-logs).

## Related docs

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
export { PAGE_COLUMN_CLASS } from '@/app/o/[organizationId]/components/organization-page/constants'
export {
OrganizationPage,
type OrganizationPageTab,
} from '@/app/o/[organizationId]/components/organization-page/organization-page'
export { OrganizationPage } from '@/app/o/[organizationId]/components/organization-page/organization-page'
export { useOrganizationPageFilters } from '@/app/o/[organizationId]/components/organization-page/use-organization-page-filters'
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
SIDEBAR_DIVIDER_PAD_BELOW_CLASS,
} from '@/app/workspace/[workspaceId]/w/components/sidebar/constants'

export interface OrganizationPageTab {
interface OrganizationPageTab {
id: string
label: string
}
Expand Down
43 changes: 29 additions & 14 deletions apps/sim/app/o/[organizationId]/links/loading.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,34 @@
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'
'use client'

import { Link, Plus } from '@sim/emcn/icons'
import {
type ChromeActionSpec,
ResourceChromeFallback,
} from '@/app/workspace/[workspaceId]/components/resource/components/resource-chrome-fallback'
import type { ResourceColumn } from '@/app/workspace/[workspaceId]/components/resource/resource'

const COLUMNS = [
{ id: 'name', header: 'Name' },
{ id: 'destination', header: 'Destination', widthMultiplier: 2 },
{ id: 'description', header: 'Description', widthMultiplier: 1.4 },
{ id: 'owner', header: 'Created by' },
{ id: 'access', header: 'Access' },
{ id: 'updated', header: 'Updated' },
] as const satisfies readonly ResourceColumn[]

const ACTIONS = [
{ text: 'New link', icon: Plus, variant: 'primary' },
] as const satisfies readonly ChromeActionSpec[]

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>
<ResourceChromeFallback
icon={Link}
title='Sim Links'
columns={COLUMNS}
actions={ACTIONS}
searchPlaceholder='Search Sim links...'
hasSort
/>
)
}
18 changes: 17 additions & 1 deletion apps/sim/app/o/[organizationId]/links/search-params.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
import { createSerializer, parseAsString } from 'nuqs/server'
import { SIM_LINK_SORTS } from '@/lib/sim-links/validation'
import { createSortParams } from '@/lib/url-state'

/** `create` opens the new-link editor, prefilled with its value as the name. */
export const simLinkViewParsers = { create: parseAsString } as const
const simLinkViewParsers = { create: parseAsString } as const

export const serializeSimLinkView = createSerializer(simLinkViewParsers)

/** `search` filters by name, destination, or description; only its URL write is debounced. */
export const simLinksParsers = {
...simLinkViewParsers,
search: parseAsString.withDefault(''),
} as const

/** Shared `sort` + `dir` params for the Sim Links list. Default: alphabetical. */
export const simLinksSortParams = createSortParams(SIM_LINK_SORTS, {
column: 'name',
direction: 'asc',
})

export const simLinksUrlKeys = { history: 'replace', clearOnDefault: true } as const
74 changes: 74 additions & 0 deletions apps/sim/app/o/[organizationId]/links/sim-link-context-menu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
'use client'

import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@sim/emcn'
import { ArrowUpRight, Duplicate, Pencil, Trash } from '@sim/emcn/icons'

interface SimLinkContextMenuProps {
isOpen: boolean
position: { x: number; y: number }
onClose: () => void
onOpen: () => void
onCopyLink: () => void
/** Present only when the viewer may edit the link. */
onEdit?: () => void
/** Present only when the viewer may delete the link. */
onDelete?: () => void
}

/** Row actions for one Sim link, anchored where the row was right-clicked. */
export function SimLinkContextMenu({
isOpen,
position,
onClose,
onOpen,
onCopyLink,
onEdit,
onDelete,
}: SimLinkContextMenuProps) {
return (
<DropdownMenu open={isOpen} onOpenChange={(open) => !open && onClose()} modal={false}>
<DropdownMenuTrigger asChild>
<div
className='pointer-events-none fixed size-px'
style={{ left: `${position.x}px`, top: `${position.y}px` }}
tabIndex={-1}
aria-hidden
/>
</DropdownMenuTrigger>
<DropdownMenuContent
align='start'
side='bottom'
sideOffset={4}
onCloseAutoFocus={(e) => e.preventDefault()}
>
<DropdownMenuItem onSelect={onOpen}>
<ArrowUpRight />
Open
</DropdownMenuItem>
<DropdownMenuItem onSelect={onCopyLink}>
<Duplicate />
Copy link
</DropdownMenuItem>
{onEdit && (
<DropdownMenuItem onSelect={onEdit}>
<Pencil />
Edit
</DropdownMenuItem>
)}
{onDelete && <DropdownMenuSeparator />}
{onDelete && (
<DropdownMenuItem onSelect={onDelete}>
<Trash />
Delete
</DropdownMenuItem>
)}
</DropdownMenuContent>
</DropdownMenu>
)
}
Loading
Loading