Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat: create multi-org template creation page#13879

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Closed
jaaydenh wants to merge34 commits intomainfrommulti-org-create-template
Closed
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
34 commits
Select commitHold shift + click to select a range
d640312
feat: initial changes for multi org template creation
jaaydenhJul 12, 2024
1c973ae
feat: styling and add template creation options
jaaydenhJul 18, 2024
6b5e7ec
chore: remove unused imports
jaaydenhJul 18, 2024
fbd6ca3
fix: use theme on cardTitle
jaaydenhJul 18, 2024
013522b
fix: remove unused import
jaaydenhJul 18, 2024
f547bfc
fix: pass key directly to JSX without using spread
jaaydenhJul 19, 2024
6b6c635
fix: use correct path
jaaydenhJul 19, 2024
b4e3c67
fix: fix test
jaaydenhJul 19, 2024
2636753
chore: handle merge changes
jaaydenhJul 19, 2024
c113979
fix: remove CreateTemplateButton
jaaydenhJul 19, 2024
cb53396
fix: update template examples for multi-org
jaaydenhJul 23, 2024
789699a
feat: pass along organizationId when creating templates
jaaydenhJul 23, 2024
8b03b11
fix: improve organization autocomplete
jaaydenhJul 24, 2024
b3aa04f
Feat: move org dropdown and add orgId search param
jaaydenhJul 24, 2024
03768c4
chore: show org autocomplete if experiment is enabled
jaaydenhJul 24, 2024
7baba1e
fix: remove unnecessary query param
jaaydenhJul 24, 2024
f513633
fix: cleanup
jaaydenhJul 24, 2024
b350b95
fix: fix tests
jaaydenhJul 24, 2024
2810cd3
fix: fix create template form stories
jaaydenhJul 24, 2024
6499543
fix
jaaydenhJul 24, 2024
c52c3dc
fix: merge issues
jaaydenhJul 25, 2024
6205129
chore: use default org for example templates
jaaydenhJul 26, 2024
b721a43
feat: add organizationId to the templates route
jaaydenhJul 26, 2024
41a414e
fix: add missing useMemo dependency
jaaydenhJul 26, 2024
e23475b
fix: add organizationId dependency
jaaydenhJul 26, 2024
53d4a3e
feat: update tests for organization in templates route
jaaydenhJul 26, 2024
7d92893
feat: gate org dropdown to multiple_organizations feature
jaaydenhJul 26, 2024
73ae86b
chore: set default for organization route param
jaaydenhJul 26, 2024
9bb1139
feat: update template routes for organizations
jaaydenhJul 26, 2024
1375b30
feat: add templates route
jaaydenhJul 26, 2024
aa452fe
feat: use templates_route
jaaydenhJul 26, 2024
0830dcc
Merge branch 'main' into multi-org-create-template
aslilacJul 26, 2024
b637620
the whirly durly
aslilacJul 26, 2024
0fc9acc
Merge branch 'main' into multi-org-create-template
aslilacJul 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletionsite/src/api/queries/templates.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,11 +13,19 @@ import type {
import { delay } from "utils/delay";
import { getTemplateVersionFiles } from "utils/templateVersion";

export const templateKey = (templateId: string) => ["template", templateId];

export const template = (templateId: string): QueryOptions<Template> => {
return {
queryKey: templateKey(templateId),
queryFn: async () => API.getTemplate(templateId),
};
};

export const templateByNameKey = (organizationId: string, name: string) => [
organizationId,
"template",
name,
"settings",
];

export const templateByName = (
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
import { css } from "@emotion/css";
import Autocomplete from "@mui/material/Autocomplete";
import CircularProgress from "@mui/material/CircularProgress";
import TextField from "@mui/material/TextField";
import {
type ChangeEvent,
type ComponentProps,
type FC,
useState,
} from "react";
import { useQuery } from "react-query";
import { organizations } from "api/queries/organizations";
import type { Organization } from "api/typesGenerated";
import { Avatar } from "components/Avatar/Avatar";
import { AvatarData } from "components/AvatarData/AvatarData";
import { useDebouncedFunction } from "hooks/debounce";

export type OrganizationAutocompleteProps = {
value: Organization | null;
onChange: (organization: Organization | null) => void;
label?: string;
className?: string;
size?: ComponentProps<typeof TextField>["size"];
required?: boolean;
};

export const OrganizationAutocomplete: FC<OrganizationAutocompleteProps> = ({
value,
onChange,
label,
className,
size = "small",
required,
}) => {
const [autoComplete, setAutoComplete] = useState<{
value: string;
open: boolean;
}>({
value: value?.name ?? "",
open: false,
});
const organizationsQuery = useQuery(organizations());

const { debounced: debouncedInputOnChange } = useDebouncedFunction(
(event: ChangeEvent<HTMLInputElement>) => {
setAutoComplete((state) => ({
...state,
value: event.target.value,
}));
},
750,
);

return (
<Autocomplete
noOptionsText="No organizations found"
className={className}
options={organizationsQuery.data ?? []}
loading={organizationsQuery.isLoading}
value={value}
data-testid="organization-autocomplete"
open={autoComplete.open}
isOptionEqualToValue={(a, b) => a.name === b.name}
getOptionLabel={(option) => option.display_name}
onOpen={() => {
setAutoComplete((state) => ({
...state,
open: true,
}));
}}
onClose={() => {
setAutoComplete({
value: value?.name ?? "",
open: false,
});
}}
onChange={(_, newValue) => {
onChange(newValue);
}}
renderOption={({ key, ...props }, option) => (
<li key={key} {...props}>
<AvatarData
title={option.display_name}
subtitle={option.name}
src={option.icon}
/>
</li>
)}
renderInput={(params) => (
<TextField
{...params}
required={required}
fullWidth
size={size}
label={label}
autoFocus
placeholder="Organization name"
css={{
"&:not(:has(label))": {
margin: 0,
},
}}
InputProps={{
...params.InputProps,
onChange: debouncedInputOnChange,
startAdornment: value && (
<Avatar size="sm" src={value.icon}>
{value.name}
</Avatar>
),
endAdornment: (
<>
{organizationsQuery.isFetching && autoComplete.open && (
<CircularProgress size={16} />
)}
{params.InputProps.endAdornment}
</>
),
classes: { root },
}}
InputLabelProps={{
shrink: true,
}}
/>
)}
/>
);
};

const root = css`
padding-left: 14px !important; // Same padding left as input
gap: 4px;
`;
22 changes: 10 additions & 12 deletionssite/src/components/UserAutocomplete/UserAutocomplete.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,6 +22,7 @@ export type UserAutocompleteProps = {
label?: string;
className?: string;
size?: ComponentProps<typeof TextField>["size"];
required?: boolean;
};

export const UserAutocomplete: FC<UserAutocompleteProps> = ({
Expand All@@ -30,6 +31,7 @@ export const UserAutocomplete: FC<UserAutocompleteProps> = ({
label,
className,
size = "small",
required,
}) => {
const [autoComplete, setAutoComplete] = useState<{
value: string;
Expand DownExpand Up@@ -59,16 +61,15 @@ export const UserAutocomplete: FC<UserAutocompleteProps> = ({

return (
<Autocomplete
// Since the values are filtered by the API we don't need to filter them
// in the FE because it can causes some mismatches.
filterOptions={(user) => user}
noOptionsText="No users found"
className={className}
options={usersQuery.data?.users ?? []}
loading={usersQuery.isLoading}
value={value}
id="user-autocomplete"
data-testid="user-autocomplete"
open={autoComplete.open}
isOptionEqualToValue={(a, b) => a.username === b.username}
getOptionLabel={(option) => option.email}
onOpen={() => {
setAutoComplete((state) => ({
...state,
Expand All@@ -84,12 +85,8 @@ export const UserAutocomplete: FC<UserAutocompleteProps> = ({
onChange={(_, newValue) => {
onChange(newValue);
}}
isOptionEqualToValue={(option: User, value: User) =>
option.username === value.username
}
getOptionLabel={(option) => option.email}
renderOption={(props, option) => (
<li {...props}>
renderOption={({ key, ...props }, option) => (
<li key={key} {...props}>
<AvatarData
title={option.username}
subtitle={option.email}
Expand All@@ -100,6 +97,7 @@ export const UserAutocomplete: FC<UserAutocompleteProps> = ({
renderInput={(params) => (
<TextField
{...params}
required={required}
fullWidth
size={size}
label={label}
Expand All@@ -119,9 +117,9 @@ export const UserAutocomplete: FC<UserAutocompleteProps> = ({
),
endAdornment: (
<>
{usersQuery.isFetching && autoComplete.open? (
{usersQuery.isFetching && autoComplete.open&& (
<CircularProgress size={16} />
) : null}
)}
{params.InputProps.endAdornment}
</>
),
Expand Down
17 changes: 17 additions & 0 deletionssite/src/modules/navigation.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
/**
* @fileoverview TODO: centralize navigation code here! URL constants, URL formatting, all of it
*/
import type { Experiments } from "api/typesGenerated";

export function withFilter(path: string, filter: string) {
return path + (filter ? `?filter=${encodeURIComponent(filter)}` : "");
Expand All@@ -9,3 +10,19 @@ export function withFilter(path: string, filter: string) {
export const AUDIT_LINK = "/audit";

export const USERS_LINK = withFilter("/users", "status:active");

export const TEMPLATES_ROUTE = (
organizationId: string,
templateName: string,
routeSuffix: string = "",
orgsEnabled: boolean = false,
experiments: Experiments = [],
) => {
const multiOrgExperimentEnabled = experiments.includes("multi-organization");

if (multiOrgExperimentEnabled && orgsEnabled) {
return `/templates/${organizationId}/${templateName}${routeSuffix}`;
}

return `/templates/${templateName}${routeSuffix}`;
};
13 changes: 8 additions & 5 deletionssite/src/modules/templates/TemplateFiles/TemplateFiles.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,20 +10,22 @@ import type { TemplateVersionFiles } from "utils/templateVersion";
import { TemplateFileTree } from "./TemplateFileTree";

interface TemplateFilesProps {
organizationName: string;
templateName: string;
versionName: string;
currentFiles: TemplateVersionFiles;
/**
* Files used to compare with current files
*/
baseFiles?: TemplateVersionFiles;
versionName: string;
templateName: string;
}

export const TemplateFiles: FC<TemplateFilesProps> = ({
organizationName,
templateName,
versionName,
currentFiles,
baseFiles,
versionName,
templateName,
}) => {
const filenames = Object.keys(currentFiles);
const theme = useTheme();
Expand DownExpand Up@@ -104,7 +106,8 @@ export const TemplateFiles: FC<TemplateFilesProps> = ({

<div css={{ marginLeft: "auto" }}>
<Link
to={`/templates/${templateName}/versions/${versionName}/edit?path=${filename}`}
// TODO: skip org name if we're not licensed
to={`/templates/${organizationName}/${templateName}/versions/${versionName}/edit?path=${filename}`}
css={{
display: "flex",
gap: 4,
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,9 +25,10 @@ export const Language = {
};

interface TooltipProps {
onUpdateVersion: () => void;
organizationName: string;
templateName: string;
latestVersionId: string;
onUpdateVersion: () => void;
ariaLabel?: string;
}

Expand All@@ -48,10 +49,11 @@ export const WorkspaceOutdatedTooltip: FC<TooltipProps> = (props) => {
};

export const WorkspaceOutdatedTooltipContent: FC<TooltipProps> = ({
organizationName,
templateName,
latestVersionId,
onUpdateVersion,
ariaLabel,
latestVersionId,
templateName,
}) => {
const popover = usePopover();
const { data: activeVersion } = useQuery({
Expand All@@ -71,7 +73,8 @@ export const WorkspaceOutdatedTooltipContent: FC<TooltipProps> = ({
<div>
{activeVersion ? (
<Link
href={`/templates/${templateName}/versions/${activeVersion.name}`}
// TODO: skip org name if we're not licensed
href={`/templates/${organizationName}/${templateName}/versions/${activeVersion.name}`}
target="_blank"
css={{ color: theme.palette.primary.light }}
>
Expand Down
Loading
Loading

[8]ページ先頭

©2009-2025 Movatter.jp