-
Notifications
You must be signed in to change notification settings - Fork 0
Feature/panoramax #74
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
base: develop
Are you sure you want to change the base?
Changes from all commits
7ba77a9
0bd8e1a
72c4b3e
821bd19
030984b
2f2f1f2
26e2fd9
163725e
825ef8c
70d5487
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| import '@panoramax/web-viewer/build/index.css'; | ||
| import '@panoramax/web-viewer'; | ||
|
|
||
| import { useMemo } from 'react'; | ||
| import { | ||
| _cs, | ||
| isDefined, | ||
| } from '@togglecorp/fujs'; | ||
|
|
||
| import styles from './styles.module.css'; | ||
|
|
||
| interface Props { | ||
| className?: string; | ||
| imageId: string | undefined; | ||
| url?: string | undefined | null; | ||
| } | ||
|
|
||
| const DEFAULT_ENDPOINT = 'https://api.panoramax.xyz/api'; | ||
|
|
||
| function PanoramaxImagePreview({ className, imageId, url }: Props) { | ||
| const endpoint = useMemo(() => { | ||
| // NOTE: Workaround to use Metacatalog API for MapComplete Panoramax due to CORS issues. | ||
| if (!url) return DEFAULT_ENDPOINT; | ||
| return url.includes('mapcomplete') ? DEFAULT_ENDPOINT : `${url.replace(/\/+$/, '')}/api`; | ||
| }, [url]); | ||
|
|
||
| const PanoramaxPhotoViewer = 'pnx-photo-viewer' as React.ElementType; | ||
| return ( | ||
| <div className={_cs(styles.panoramaxImagePreview, className)}> | ||
| {isDefined(imageId) && ( | ||
| <PanoramaxPhotoViewer | ||
| class={styles.viewer} | ||
| endpoint={endpoint} | ||
| picture={imageId} | ||
| widgets={false} | ||
| url-parameters={false} | ||
| keyboard-shortcuts={false} | ||
| psv-options={JSON.stringify({ | ||
| picturesNavigation: 'pic', | ||
| displayAnnotations: false, | ||
| })} | ||
| /> | ||
| )} | ||
| </div> | ||
| ); | ||
| } | ||
|
|
||
| export default PanoramaxImagePreview; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| .panoramax-image-preview { | ||
| isolation: isolate; | ||
| height: 20rem; | ||
|
|
||
| .viewer { | ||
| width: 100%; | ||
| height: 100%; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,7 +6,10 @@ import CustomOptionPreview from '#components/domain/CustomOptionsPreview'; | |
| import ProjectAssetPreview from '#components/domain/ProjectAssetPreview'; | ||
| import ListLayout from '#components/ListLayout'; | ||
| import TextOutput from '#components/TextOutput'; | ||
| import { StreetProjectPropertyType } from '#generated/types/graphql'; | ||
| import { | ||
| StreetImageProviderNameEnum, | ||
| StreetProjectPropertyType, | ||
| } from '#generated/types/graphql'; | ||
|
|
||
| interface Props { | ||
| data: StreetProjectPropertyType | undefined; | ||
|
|
@@ -36,7 +39,7 @@ function StreetDetails(props: Props) { | |
| </Container> | ||
| </ListLayout> | ||
| <Container | ||
| heading="Mapillary Image Filters" | ||
| heading="Street-level Image Filters" | ||
| headingLevel={5} | ||
| > | ||
| <ListLayout | ||
|
|
@@ -56,7 +59,7 @@ function StreetDetails(props: Props) { | |
| value={data.mapillaryImageFilters.creatorId} | ||
| /> | ||
| <TextOutput | ||
| label="Mapillary Organization ID" | ||
| label="Organization ID" | ||
| value={data.mapillaryImageFilters.organizationId} | ||
| /> | ||
| <TextOutput | ||
|
|
@@ -71,7 +74,7 @@ function StreetDetails(props: Props) { | |
| > | ||
| <TextOutput | ||
| label="Only use 360 degree panaroma images" | ||
| value={data.mapillaryImageFilters.isPano} | ||
| value={data.mapillaryImageFilters.panoOnly} | ||
| valueType="boolean" | ||
| /> | ||
| <TextOutput | ||
|
|
@@ -80,6 +83,26 @@ function StreetDetails(props: Props) { | |
| valueType="boolean" | ||
| /> | ||
| </ListLayout> | ||
| <ListLayout | ||
| layout="block" | ||
| spacing="sm" | ||
| > | ||
| <TextOutput | ||
| label="Image provider name" | ||
| value={data.imageProvider?.name} | ||
| valueType="text" | ||
| /> | ||
| {( | ||
| data.imageProvider?.name === StreetImageProviderNameEnum.PanoramaxCustom | ||
| && data.imageProvider?.url | ||
| ) && ( | ||
| <TextOutput | ||
| label="Panoramax API URL" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this label correct? How do we know the url is for Panoramax?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The url field is only allowed for custom Panoramax API (see https://github.com/mapswipe/mapswipe-backend/blob/3089d827103cc40157930d0ff527ca93d0caa33f/utils/geo/street_image_provider/models.py#L28)
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's better to check the imageProvider type so that it does not break in the future. |
||
| value={data.imageProvider.url} | ||
| valueType="text" | ||
| /> | ||
| )} | ||
| </ListLayout> | ||
| </Container> | ||
| </> | ||
| ); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| import { | ||
| useCallback, | ||
| useContext, | ||
| useMemo, | ||
| } from 'react'; | ||
| import { | ||
| EntriesAsList, | ||
| getErrorObject, | ||
| LeafError, | ||
| ObjectError, | ||
| } from '@togglecorp/toggle-form'; | ||
|
|
||
| import Container from '#components/Container'; | ||
| import ListLayout from '#components/ListLayout'; | ||
| import RadioInput from '#components/RadioInput'; | ||
| import TextInput from '#components/TextInput'; | ||
| import EnumsContext from '#contexts/EnumsContext'; | ||
| import { StreetImageProviderNameEnum } from '#generated/types/graphql'; | ||
|
|
||
| import { PartialStreetImageProviderInputFields } from './schema'; | ||
|
|
||
| interface Props { | ||
| value: PartialStreetImageProviderInputFields | undefined; | ||
| error: LeafError | ObjectError<PartialStreetImageProviderInputFields>; | ||
| setFieldValue: ( | ||
| ...entries: EntriesAsList<PartialStreetImageProviderInputFields> | ||
| ) => void; | ||
| disabled?: boolean; | ||
| } | ||
|
|
||
| interface StreetProviderOption { | ||
| key: StreetImageProviderNameEnum; | ||
| label: string; | ||
| } | ||
|
|
||
| function providerKeySelector(option: StreetProviderOption) { | ||
| return option.key; | ||
| } | ||
|
|
||
| function providerLabelSelector(option: StreetProviderOption) { | ||
| return option.label; | ||
| } | ||
|
|
||
| function StreetImageProviderInput(props: Props) { | ||
| const { | ||
| value, error: formError, setFieldValue, disabled, | ||
| } = props; | ||
|
|
||
| const { streetImageProviderNameOptions } = useContext(EnumsContext); | ||
| const error = getErrorObject(formError); | ||
|
|
||
| const providerOptions = useMemo(() => { | ||
| if (!streetImageProviderNameOptions || streetImageProviderNameOptions.length === 0) { | ||
| return []; | ||
| } | ||
|
|
||
| return streetImageProviderNameOptions.map((option) => ({ | ||
| key: option.key as StreetImageProviderNameEnum, | ||
| label: option.label, | ||
| })); | ||
| }, [streetImageProviderNameOptions]); | ||
|
|
||
| const handleChange = useCallback((newValue: StreetImageProviderNameEnum) => { | ||
| setFieldValue(newValue, 'name'); | ||
| if (newValue !== StreetImageProviderNameEnum.PanoramaxCustom) { | ||
| setFieldValue(undefined, 'url'); | ||
| } | ||
| }, [setFieldValue]); | ||
|
|
||
| return ( | ||
| <Container heading="Street-level imagery provider"> | ||
| <ListLayout layout="block"> | ||
| <RadioInput | ||
| name="provider" | ||
| label="Image provider" | ||
| options={providerOptions} | ||
| keySelector={providerKeySelector} | ||
| labelSelector={providerLabelSelector} | ||
| value={value?.name} | ||
| onChange={handleChange} | ||
| error={error?.name} | ||
| disabled={disabled} | ||
| radioListLayout="block" | ||
| /> | ||
|
|
||
| {value?.name === StreetImageProviderNameEnum.PanoramaxCustom && ( | ||
| <TextInput | ||
| name="url" | ||
| label="Panoramax API URL" | ||
| value={value?.url} | ||
| error={error?.url} | ||
| onChange={setFieldValue} | ||
| disabled={disabled} | ||
| /> | ||
| )} | ||
| </ListLayout> | ||
| </Container> | ||
| ); | ||
| } | ||
|
|
||
| export default StreetImageProviderInput; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| import { | ||
| addCondition, | ||
| ObjectSchema, | ||
| PartialForm, | ||
| requiredStringCondition, | ||
| } from '@togglecorp/toggle-form'; | ||
|
|
||
| import { | ||
| StreetImageProviderInput, | ||
| StreetImageProviderNameEnum, | ||
| } from '#generated/types/graphql'; | ||
| import { DeepNonNullable } from '#utils/types'; | ||
|
|
||
| export type PartialStreetImageProviderInputFields = PartialForm< | ||
| DeepNonNullable<StreetImageProviderInput> | ||
| >; | ||
|
|
||
| type StreetImageProviderSchema = | ||
| ObjectSchema<PartialStreetImageProviderInputFields>; | ||
|
|
||
| type StreetImageProviderFields = | ||
| ReturnType<StreetImageProviderSchema['fields']>; | ||
|
|
||
| export const defaultStreetImageProviderValue: | ||
| PartialStreetImageProviderInputFields = { | ||
| name: StreetImageProviderNameEnum.Mapillary, | ||
| }; | ||
|
|
||
| const streetImageProviderSchema: StreetImageProviderSchema = { | ||
| fields: (value): StreetImageProviderFields => { | ||
| const baseSchema: StreetImageProviderFields = { | ||
| name: { | ||
| required: true, | ||
| }, | ||
| url: {}, | ||
| }; | ||
|
|
||
| return addCondition( | ||
| baseSchema, | ||
| value, | ||
| ['name'], | ||
| ['url'], | ||
| (): StreetImageProviderFields => { | ||
| if (value?.name === StreetImageProviderNameEnum.PanoramaxCustom) { | ||
| return { | ||
| url: { | ||
| required: true, | ||
| requiredValidation: requiredStringCondition, | ||
| }, | ||
| }; | ||
| } | ||
|
|
||
| return { | ||
| url: { required: false }, | ||
| }; | ||
| }, | ||
| ); | ||
| }, | ||
| }; | ||
|
|
||
| export default streetImageProviderSchema; |
Uh oh!
There was an error while loading. Please reload this page.