Skip to content

Commit 8964b49

Browse files
authored
Merge pull request #130 from lumapps/chore/search-template-settings
chore(search): update types + playground preview
2 parents 23f8f30 + f6b7032 commit 8964b49

21 files changed

+500
-196
lines changed

template-search-extension/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,5 @@ yarn-error.log*
2525

2626
*.lum
2727
build/
28+
bundle.zip
29+
config.trans.js

template-search-extension/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
"start": "run-p start:playground start:shipping-server",
99
"start:playground": "react-scripts start",
1010
"start:shipping-server": "lumapps-shipping-server",
11-
"test": "react-scripts test --coverage"
11+
"test": "react-scripts test --coverage",
12+
"build": "yarn start:shipping-server bundle"
1213
},
1314
"eslintConfig": {
1415
"extends": "react-app"
@@ -39,7 +40,7 @@
3940
"@lumx/react": "^3.0.2",
4041
"axios": "0.21.4",
4142
"lodash": "4.17.21",
42-
"lumapps-sdk-js": "^1.21.0",
43+
"lumapps-sdk-js": "1.24.1",
4344
"moment": "^2.29.1",
4445
"moment-range": "^4.0.2",
4546
"react": "^16.13.1",
Lines changed: 2 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,94 +1,11 @@
11
/**
2-
* Create-LumApps-Widget config file
2+
* Create-LumApps-Search config file
33
* update the following to fit your needs
44
*/
55

6-
/**
7-
* The ids of your partner and extension
8-
*/
9-
const partnerId = {
10-
beta: '',
11-
production: '',
12-
};
13-
14-
const extensionId = {
15-
beta: '',
16-
production: '',
17-
};
18-
19-
const description = {
20-
en: 'SearchExtension',
21-
};
22-
23-
const name = {
24-
en: 'SearchExtension',
25-
};
26-
27-
const icon = {
28-
en:
29-
'https://lh3.googleusercontent.com/-6F_iwel8KGY/WD8MdGS0PkI/AAAAAAAAGDI/KaqvKtZCK_AsdK6BcKp6Cy1MpwoEWCUvgCKgB/s400/logo.png', // a working link to your widget icon
30-
};
31-
32-
const oauth = false;
33-
34-
/**
35-
* Define the availability of your extension :
36-
* - open : available for everyone
37-
* - marketplace : the customer need to have access to the marketplace
38-
*/
39-
40-
const availability = 'marketplace';
41-
42-
/**
43-
* Define if your extension needs to connect to external service through an application declare on provider side.
44-
*
45-
* Uncomment the following block to declare application usage for your extension.
46-
* Do not forget to add the application attribute in the config object.
47-
*/
48-
/*const application = {
49-
providerType: '',
50-
};*/
51-
52-
/**
53-
* The documentation's url of the extension.
54-
*/
55-
const links = {
56-
documentation: null,
57-
};
58-
59-
/**
60-
* The components available for your extensions
61-
* 'content' : For the Widget content itself (required)
62-
* 'settings' : For your search settings that will be used in a Tab context
63-
* 'globalSettings' : For global settings used by platform admin.
64-
*/
65-
const components = ['content', 'settings', 'global_settings'];
66-
67-
// Whether the extension is public or not in the marketplace.
68-
const isPublic = true;
69-
70-
/**
71-
* The list of authorized customer ids.
72-
*
73-
* If your extension is not public only these customers will see and
74-
* will be able to install this extensions.
75-
*/
76-
const whitelist = [];
77-
786
// do not change the following unless you know what you are doing
797
const config = {
80-
availability,
81-
category: 'widget',
82-
components,
83-
description,
84-
extensionId,
85-
icon,
86-
links,
87-
name,
88-
oauth,
89-
partnerId,
90-
public: isPublic,
91-
whitelist,
8+
category: 'search',
929
};
9310

9411
export default config;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { ExtensionSearchSettings } from './types';
2+
3+
export const DEFAULT_SETTINGS: ExtensionSearchSettings = {
4+
searchId: '427af9d7-632f-5cf2-b909-141d229248b1',
5+
};
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
/**
22
* Do not modify unless you know what you are doing
33
*/
4-
import { Search } from './search/Search';
5-
6-
export { Search };
4+
export { Search } from './search';

template-search-extension/src/index.global_settings.ts

Lines changed: 0 additions & 4 deletions
This file was deleted.

template-search-extension/src/index.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
import React from 'react';
22
import ReactDOM from 'react-dom';
33
import { Provider } from 'react-redux';
4+
import { ExtensionConfig } from 'lumapps-sdk-js';
5+
// eslint-disable-next-line import/no-extraneous-dependencies
46
import { Playground, store } from '@lumapps-extensions-playground/devenv';
57

68
import '@lumx/core/lumx.css';
79

8-
import config from './config.js';
10+
import config from './config';
911
import { SearchSettings } from './index.settings';
10-
import { SearchGlobalSettings } from './index.global_settings';
12+
import { SearchPagePreview } from './playground/SearchPagePreview';
1113

1214
ReactDOM.render(
1315
<React.StrictMode>
1416
<Provider store={store}>
1517
<Playground
16-
config={config as any}
18+
config={config as ExtensionConfig}
19+
ContentComponent={SearchPagePreview}
1720
SettingsComponent={SearchSettings}
18-
GlobalSettingsComponent={SearchGlobalSettings}
1921
/>
2022
</Provider>
2123
</React.StrictMode>,
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import React from 'react';
2+
import { mdiFileDocument } from '@lumx/icons';
3+
import { Divider, FlexBox, GenericBlock, Heading, Icon, Text, Link, Thumbnail } from '@lumx/react';
4+
5+
import { ExtensionSearchResult } from 'lumapps-sdk-js';
6+
7+
export interface ResultsProps {
8+
items: ExtensionSearchResult[];
9+
}
10+
11+
export const Results = ({ items }: ResultsProps) => {
12+
return (
13+
<FlexBox>
14+
{items.map((item, index) => (
15+
<React.Fragment key={item.id}>
16+
<GenericBlock
17+
key={item.id}
18+
as="article"
19+
orientation="horizontal"
20+
className="lumx-spacing-padding-big"
21+
>
22+
<GenericBlock.Figure>
23+
{item.thumbnail ? (
24+
<Thumbnail
25+
image={item.thumbnail}
26+
alt=""
27+
badge={item.icon ? <Icon icon={item.icon} size="s" hasShape /> : undefined}
28+
aspectRatio="square"
29+
size="l"
30+
/>
31+
) : (
32+
<Icon icon={item.icon || mdiFileDocument} size="l" hasShape />
33+
)}
34+
</GenericBlock.Figure>
35+
<GenericBlock.Content>
36+
<Heading as="h2" typography="subtitle2">
37+
<Link href={item.url} target="_blank">
38+
{item.title}
39+
</Link>
40+
</Heading>
41+
{item.source ? (
42+
<Text as="span" typography="body1" color="dark" colorVariant="L2">
43+
{item.source}
44+
</Text>
45+
) : null}
46+
<Text
47+
as="p"
48+
typography="body1"
49+
color="dark"
50+
colorVariant="L2"
51+
dangerouslySetInnerHTML={{ __html: item.snippet }}
52+
/>
53+
</GenericBlock.Content>
54+
</GenericBlock>
55+
{index !== items.length - 1 && (
56+
<Divider className="lumx-spacing-margin-vertical-big lumx-spacing-margin-horizontal-huge" />
57+
)}
58+
</React.Fragment>
59+
))}
60+
</FlexBox>
61+
);
62+
};
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import React from 'react';
2+
import { ContentComponentProps, RESULT_STATUS, useDebounce, SearchSort } from 'lumapps-sdk-js';
3+
import { mdiMagnify, mdiTrophyBroken } from '@lumx/icons';
4+
import { FlexBox, Icon, Text, TextField, Button, Orientation, Divider } from '@lumx/react';
5+
6+
import { UseSearchParams, useSearch } from '../search/useSearch';
7+
import { ExtensionSearchSettings } from '../types';
8+
import { Results } from './Results';
9+
import { Sorters } from './Sorters';
10+
11+
/**
12+
*
13+
* @param props
14+
* @returns
15+
*/
16+
export const SearchPagePreview = (props: ContentComponentProps<unknown, ExtensionSearchSettings>) => {
17+
const [query, setQuery] = React.useState('formage');
18+
const [page, setPage] = React.useState(0);
19+
const debouncedQuery = useDebounce(query, 500);
20+
const [sort, setSort] = React.useState<SearchSort | undefined>();
21+
22+
const { properties, extensionId } = props;
23+
24+
const input: UseSearchParams = React.useMemo(
25+
() => ({
26+
query: debouncedQuery,
27+
pageSize: 10,
28+
language: 'en',
29+
extensionId,
30+
connectorId: 'connector',
31+
page,
32+
sort: sort?.value,
33+
settings: properties,
34+
}),
35+
[page, debouncedQuery, sort, properties, extensionId],
36+
);
37+
38+
const { results, hasMore, status, totalCount, sortOrders = [] } = useSearch(input);
39+
40+
const onSortChange = (newSort: SearchSort) => {
41+
setSort(newSort);
42+
setPage(0);
43+
};
44+
45+
const loadMoreResults = () => {
46+
setPage(page + 1);
47+
};
48+
49+
const currentSort = React.useMemo(() => {
50+
if (sort) {
51+
return sort;
52+
}
53+
if (sortOrders.length > 0) {
54+
return sortOrders[0];
55+
}
56+
57+
return undefined;
58+
}, [sortOrders, sort]);
59+
60+
return (
61+
<div className="lumx-spacing-padding-horizontal-huge">
62+
<TextField value={query} onChange={setQuery} icon={mdiMagnify} />
63+
64+
{status === RESULT_STATUS.ERROR ? (
65+
<FlexBox
66+
orientation="vertical"
67+
hAlign="center"
68+
vAlign="center"
69+
className="lumx-spacing-padding-horizontal-huge"
70+
>
71+
<Icon icon={mdiTrophyBroken} size="xl" hasShape />
72+
<Text as="p" typography="title">
73+
Oups, an error occured{' '}
74+
<span role="img" aria-label="shrug">
75+
🤷‍♂️
76+
</span>
77+
</Text>
78+
<Text as="p" typography="body1">
79+
Check the browser console
80+
</Text>
81+
</FlexBox>
82+
) : (
83+
<FlexBox orientation={Orientation.horizontal} className="lumx-spacing-margin-top-big" gap="big">
84+
<FlexBox orientation={Orientation.vertical}>
85+
<FlexBox orientation={Orientation.horizontal} hAlign="center" vAlign="space-between">
86+
<Text as="p" typography="caption">
87+
Found {totalCount} results for &quot;{debouncedQuery}&quot;
88+
</Text>
89+
90+
{currentSort ? (
91+
<Sorters choices={sortOrders} value={currentSort} onChange={onSortChange} />
92+
) : null}
93+
</FlexBox>
94+
<Results items={results} />
95+
{hasMore && (
96+
<Button
97+
fullWidth
98+
onClick={loadMoreResults}
99+
className="lumx-spacing-margin-vertical-big"
100+
emphasis="medium"
101+
type="button"
102+
>
103+
Display more results
104+
</Button>
105+
)}
106+
</FlexBox>
107+
</FlexBox>
108+
)}
109+
110+
<Divider />
111+
<FlexBox className="lumx-spacing-margin-vertical-huge lumx-spacing-margin-horizontal-huge">
112+
<Text as="p" color="grey" typography="body2">
113+
Debug info
114+
</Text>
115+
<p>Status: {status}</p>
116+
<p>Total count: {totalCount}</p>
117+
<p>hasMore: {`${hasMore}`}</p>
118+
</FlexBox>
119+
</div>
120+
);
121+
};

0 commit comments

Comments
 (0)