This repository was archived by the owner on Jul 9, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 375
feat: add extensions page in settings #4264
Merged
Merged
Changes from 22 commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
4a6f8ba
re-enable extensions page
a-b-r-o-w-n 7aa168e
support multiple extension pages
a-b-r-o-w-n dbfd671
revert to using bundleId for page config
a-b-r-o-w-n 921d9ab
omit sensitve properties from extension apis
a-b-r-o-w-n 504eb59
fix adding new extension to state
a-b-r-o-w-n 9815cd5
add shimmer list when doing remote calls
a-b-r-o-w-n 5b08eb5
show extension display name
a-b-r-o-w-n e5a1082
update search mechanics
a-b-r-o-w-n 67e40ee
ensure remote extensions dir exists
a-b-r-o-w-n 9af004d
fix api call to get plugin bundle
a-b-r-o-w-n 9097571
spawn npm with shell on windows platforms
a-b-r-o-w-n 999ae0a
Merge branch 'main' into abrown/extensions/list-ui
a-b-r-o-w-n 191b405
improve searching UX
a-b-r-o-w-n 03f489b
show message when no extensions or search results
a-b-r-o-w-n 681e666
add description to extension db
a-b-r-o-w-n 43a02a9
move uninstall action to toolbar
a-b-r-o-w-n f30b5ca
use ensureDir api from fs-extra
a-b-r-o-w-n 33de4b3
memoize callback functions
a-b-r-o-w-n a6da5bc
Merge branch 'main' into abrown/extensions/list-ui
a-b-r-o-w-n 70f455f
fix type error in test
a-b-r-o-w-n 4fe78c3
fix failing tests
a-b-r-o-w-n b2957ba
Merge branch 'main' into abrown/extensions/list-ui
a-b-r-o-w-n fc593ea
localize some strings
a-b-r-o-w-n 0032175
Merge branch 'main' into abrown/extensions/list-ui
cwhitten 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
136 changes: 136 additions & 0 deletions
136
Composer/packages/client/src/pages/setting/extensions/ExtensionSearchResults.tsx
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,136 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| /** @jsx jsx */ | ||
| import { jsx, css } from '@emotion/core'; | ||
| import React from 'react'; | ||
| import formatMessage from 'format-message'; | ||
| import { | ||
| DetailsListLayoutMode, | ||
| SelectionMode, | ||
| IColumn, | ||
| CheckboxVisibility, | ||
| ConstrainMode, | ||
| } from 'office-ui-fabric-react/lib/DetailsList'; | ||
| import { ScrollablePane } from 'office-ui-fabric-react/lib/ScrollablePane'; | ||
| import { Sticky } from 'office-ui-fabric-react/lib/Sticky'; | ||
| import { ShimmeredDetailsList } from 'office-ui-fabric-react/lib/ShimmeredDetailsList'; | ||
|
|
||
| // TODO: extract to shared? | ||
| export type ExtensionSearchResult = { | ||
| id: string; | ||
| keywords: string[]; | ||
| version: string; | ||
| description: string; | ||
| url: string; | ||
| }; | ||
|
|
||
| type ExtensionSearchResultsProps = { | ||
| results: ExtensionSearchResult[]; | ||
| isSearching: boolean; | ||
| onSelect: (extension: ExtensionSearchResult) => void; | ||
| }; | ||
|
|
||
| const containerStyles = css` | ||
| position: relative; | ||
| height: 400px; | ||
| `; | ||
|
|
||
| const noResultsStyles = css` | ||
| display: flex; | ||
| align-items: center; | ||
| justify-content: center; | ||
| `; | ||
|
|
||
| const ExtensionSearchResults: React.FC<ExtensionSearchResultsProps> = (props) => { | ||
| const { results, isSearching, onSelect } = props; | ||
|
|
||
| const searchColumns: IColumn[] = [ | ||
| { | ||
| key: 'name', | ||
| name: formatMessage('Name'), | ||
| minWidth: 100, | ||
| maxWidth: 150, | ||
| onRender: (item: ExtensionSearchResult) => { | ||
| return <span>{item.id}</span>; | ||
| }, | ||
| }, | ||
| { | ||
| key: 'description', | ||
| name: formatMessage('Description'), | ||
| minWidth: 100, | ||
| maxWidth: 300, | ||
| isMultiline: true, | ||
| onRender: (item: ExtensionSearchResult) => { | ||
| return <div css={{ overflowWrap: 'break-word' }}>{item.description}</div>; | ||
| }, | ||
| }, | ||
| { | ||
| key: 'version', | ||
| name: formatMessage('Version'), | ||
| minWidth: 30, | ||
| maxWidth: 100, | ||
| onRender: (item: ExtensionSearchResult) => { | ||
| return <span>{item.version}</span>; | ||
| }, | ||
| }, | ||
| { | ||
| key: 'url', | ||
| name: formatMessage('Url'), | ||
| minWidth: 100, | ||
| maxWidth: 100, | ||
| onRender: (item: ExtensionSearchResult) => { | ||
| return item.url ? ( | ||
| <a href={item.url} rel="noopener noreferrer" target="_blank"> | ||
| {formatMessage('View on npm')} | ||
| </a> | ||
| ) : null; | ||
| }, | ||
| }, | ||
| ]; | ||
|
|
||
| const noResultsFound = !isSearching && results.length === 0; | ||
|
|
||
| return ( | ||
| <div css={containerStyles}> | ||
| <ScrollablePane> | ||
| <ShimmeredDetailsList | ||
| checkboxVisibility={CheckboxVisibility.always} | ||
| columns={searchColumns} | ||
| constrainMode={ConstrainMode.horizontalConstrained} | ||
| enableShimmer={isSearching} | ||
| items={noResultsFound ? [{}] : results} | ||
| layoutMode={DetailsListLayoutMode.justified} | ||
| selectionMode={SelectionMode.single} | ||
| shimmerLines={8} | ||
| onActiveItemChanged={(item) => onSelect(item)} | ||
| onRenderDetailsHeader={(headerProps, defaultRender) => { | ||
| if (defaultRender) { | ||
| return <Sticky>{defaultRender(headerProps)}</Sticky>; | ||
| } | ||
|
|
||
| return <div />; | ||
| }} | ||
| onRenderRow={(rowProps, defaultRender) => { | ||
| // there are no search results | ||
| if (!isSearching && results.length === 0) { | ||
| return ( | ||
| <div css={noResultsStyles}> | ||
| <p>No search results</p> | ||
| </div> | ||
| ); | ||
| } | ||
|
|
||
| if (defaultRender) { | ||
| return defaultRender(rowProps); | ||
| } | ||
|
|
||
| return null; | ||
| }} | ||
| /> | ||
| </ScrollablePane> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export { ExtensionSearchResults }; | ||
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.