Skip to content
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

Release v3.4.0 #275

Merged
merged 9 commits into from
Jul 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Change Log

## [3.4.0] - 2024-07-18

- Improved welcome experience
- Fixed lags in sample gallery search
- Improved sample gallery filter functionalities
- Improved create project step in walkthrough

## [3.3.0] - 2024-06-16

- Refactored scaffolding form to smaller components
Expand Down
16 changes: 2 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@

<p align="center">
<a href="#-capabilities">Capabilities</a> |
<a href="#-preview-features">Preview features</a> |
<a href="#%EF%B8%8F-architecture">Architecture</a> |
<a href="#-wiki">Wiki</a> |
<a href="#-contributing">Contributing</a> |
Expand Down Expand Up @@ -264,12 +263,7 @@ By default, the SharePoint Framework Toolkit will use the Node.js version that i

You can use the settings to change which Node.js version manager you want to use. You may choose between `nvm` and `nvs`. If you wish to avoid using a Node.js version manager, you can set the value to `none`

## 🧪 Preview features

> [!WARNING]
> Features described in this section are considered as an early beta feature. They may change or be removed in a future major or minor release.

### 1️⃣ SPFx Toolkit GitHub Chat Participant
### 1️⃣3️⃣ SPFx Toolkit GitHub Chat Participant

![SPFx Toolkit chat](./assets/images/chat-intro.png)

Expand All @@ -286,13 +280,7 @@ Currently, we support the following commands:
- `/new` - that may be used to get guidance on how to create a new solution or find and reuse an existing sample from the PnP SPFx sample gallery
- `/code` - that is fine-tuned to provide help in coding your SharePoint Framework project and provides additional boosters like validating the correctness of your SPFx project, scaffolding a CI/CD workflow, or renaming your project, and many more.

> [!IMPORTANT]
> In order for this feature to work you need to meet the following requirements:
> - Use the [Visual Studio Code Insiders](https://code.visualstudio.com/insiders/) release
> - Use the pre-release version of the [GitHub Copilot Chat](https://marketplace.visualstudio.com/items?itemName=GitHub.copilot-chat) extension
> - Use latest version of [SPFx Toolkit](https://marketplace.visualstudio.com/items?itemName=m365pnp.viva-connections-toolkit)

[Check out our docs for more details](https://github.com/pnp/vscode-viva/wiki/8.-Preview-features)
[Check out our docs for more details](https://github.com/pnp/vscode-viva/wiki/8.-SPFx-Toolkit-GitHub-Chat-Participant)

## ⚙️ Architecture

Expand Down
7 changes: 6 additions & 1 deletion assets/walkthrough/create-new-project.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@ Check it out in action 👇.

![Create new project](../images/scaffolding-form.gif)

It's possible to scaffold any kind of SPFx project.
It's possible to scaffold any kind of SPFx project including web parts, extensions, library components, and adaptive card extensions.

![All SPFx project support](../images/scaffolding-support.png)

- **Web parts** are reusable elements that serve as the building blocks for SharePoint pages. They allow you to create customizable controls that can be used across multiple pages.
- **Extensions** enable you to extend the SharePoint user experience by adding scripts to pages, modifying views, adding new actions, and altering list form experiences.
- **Library components** are reusable code elements that can be shared across all the components in the tenant.
- **Adaptive Card Extensions (ACEs)** allow you to build rich, native extensions for Viva Connections Dashboards and SharePoint Pages.

Install additional dependencies with a single click straight from the scaffolding form. Currently we support installing [PnP reusable property pane controls](https://pnp.github.io/sp-dev-fx-property-controls/), [PnP reusable React controls](https://pnp.github.io/sp-dev-fx-controls-react/), and [PnPjs](https://pnp.github.io/pnpjs/).

![Additional dependency step](../images/scaffolding-additional-step.png)
Expand Down
18 changes: 15 additions & 3 deletions npm-shrinkwrap.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "viva-connections-toolkit",
"displayName": "SharePoint Framework Toolkit",
"description": "SharePoint Framework Toolkit aims to boost your productivity in developing and managing SharePoint Framework solutions helping at every stage of your development flow, from setting up your development workspace to deploying a solution straight to your tenant without the need to leave VS Code and now even create a CI/CD pipeline to introduce automate deployment of your app. This toolkit is provided by the community.",
"version": "3.3.0",
"version": "3.4.0",
"publisher": "m365pnp",
"preview": false,
"homepage": "https://github.com/pnp/vscode-viva",
Expand Down Expand Up @@ -260,7 +260,7 @@
"viewsWelcome": [
{
"view": "pnp-view-empty",
"contents": "Welcome to SharePoint Framework Toolkit\n\n\nTo start create a new SharePoint Framework project. \n[Create a new project](command:spfx-toolkit.createProject)\n\n\n\n\n\nUse a sample to kick off a new project and boost your development.\n[View samples](command:spfx-toolkit.samplesGallery)\n\n\n\n\n\nYou can also open an existing app.\n[Open folder](command:vscode.openFolder)\n\n\n\n\n\nValidate your local workspace and check if you have the required dependencies.\n[Check dependencies](command:spfx-toolkit.checkDependencies)\n\n\n\n\n\nInstall the required dependencies.\n[Install dependencies](command:spfx-toolkit.installDependencies)\n\n\n\nIf you need additional help or resources visit the [extension wiki](https://github.com/pnp/vscode-viva/wiki) for more information or go over the [walkthrough](command:spfx-toolkit.welcome)."
"contents": "Welcome to SharePoint Framework Toolkit\n\n\nTo start create a new SharePoint Framework project. \n[Create a new project](command:spfx-toolkit.createProject)\n\n\n\n\n\nUse a sample to kick off a new project and boost your development.\n[View samples](command:spfx-toolkit.samplesGallery)\n\n\n\n\n\nYou can also open an existing app.\n[Open folder](command:vscode.openFolder)\n\n\n\n\n\nValidate your local workspace and check if you have the required dependencies.\n[Check dependencies](command:spfx-toolkit.checkDependencies)\n\n\n\n\n\nInstall the required dependencies.\n[Install dependencies](command:spfx-toolkit.installDependencies)\n\n\n\nLearn more about SharePoint Framework and this toolkit.\n[Walkthrough](command:spfx-toolkit.welcome)\n\n\n\nFor additional help or resources visit the [extension wiki](https://github.com/pnp/vscode-viva/wiki)."
}
],
"commands": [
Expand Down Expand Up @@ -473,6 +473,7 @@
"@pnp/cli-microsoft365": "6.11.0",
"node-forge": "^1.3.1",
"react-markdown": "^9.0.1",
"remark-gfm": "^4.0.0"
"remark-gfm": "^4.0.0",
"use-debounce": "^10.0.1"
}
}
1 change: 1 addition & 0 deletions src/webview/view/components/controls/MultiSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ export const MultiSelect: React.FunctionComponent<IMultiSelectProps> = ({ onChan
<Dropdown
placeholder={label ?? 'Select'}
multiSelect
selectedKeys={[...options.filter((option) => option.selected).map((option) => option.key as any)]}
options={options}
styles={getDropdownStyles()}
onChange={onChange}
Expand Down
2 changes: 1 addition & 1 deletion src/webview/view/components/gallery/DetailsView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const DetailsView: React.FunctionComponent<IDetailsViewProps> = ({ }: Rea
useEffect(() => {
const { item } = state;
setSample(item);

window.scrollTo(0, 0);
const url = item.url.replace('github.com', 'raw.githubusercontent.com').replace('/blob', '').replace('/tree', '');

const fetchData = async () => {
Expand Down
68 changes: 59 additions & 9 deletions src/webview/view/components/gallery/GalleryView.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,36 @@
import * as React from 'react';
import { useState } from 'react';
import { useEffect } from 'react';
import useSamples from '../../hooks/useSamples';
import { List } from './List';
import { SearchBar } from './SearchBar';
import { ISelectedFilter, SearchBar } from './SearchBar';
import { NoResults } from './NoResults';
import { GalleryHeader } from './GalleryHeader';
import { GalleryLoader } from './GalleryLoader';
import { IDropdownOption } from '@fluentui/react';
import useLocalStorage from '../../hooks/useLocalStorage ';


export interface IGalleryViewProps { }

export const GalleryView: React.FunctionComponent<IGalleryViewProps> = ({ }: React.PropsWithChildren<IGalleryViewProps>) => {
const [samples, versions, search] = useSamples();
const [query, setQuery] = useState<string>('');
const [spfxVersions, setSPFxVersions] = useState<string[]>();
const [showOnlyScenarios, setShowOnlyScenarios] = useState<boolean>(false);
const [componentTypes, setComponentTypes] = useState<string[]>();
const [selectedFilters, setSelectedFilters] = useLocalStorage<ISelectedFilter[]>('selectedFilters', []);
const [query, setQuery] = useLocalStorage<string>('query', '');
const [spfxVersions, setSPFxVersions] = useLocalStorage<string[]>('spfxVersions', []);
const [showOnlyScenarios, setShowOnlyScenarios] = useLocalStorage('showOnlyScenarios', false);
const [componentTypes, setComponentTypes] = useLocalStorage<string[]>('componentTypes', []);

const onSearchTextboxChange = (event: any) => {
const input: string = event.target.value;
setQuery(input);
search(input, componentTypes ?? [], spfxVersions ?? [], showOnlyScenarios);
};

const onClearTextboxChange = () => {
setQuery('');
search('', componentTypes ?? [], spfxVersions ?? [], showOnlyScenarios);
};

const onFilterOnlyScenariosChange = () => {
setShowOnlyScenarios(!showOnlyScenarios);
search(query, componentTypes ?? [], spfxVersions ?? [], !showOnlyScenarios);
Expand All @@ -33,22 +40,42 @@ export const GalleryView: React.FunctionComponent<IGalleryViewProps> = ({ }: Rea
let spfxVersionsInput: string[] = [];
if (option?.selected) {
spfxVersionsInput = [...spfxVersions ?? [], option.key as string];
setSelectedFilters([...selectedFilters, {
key: option.key as string,
text: option.key as string,
kind: 'spfxVersion'
}]);
} else {
spfxVersionsInput = spfxVersions?.filter(componentType => componentType !== option?.key) ?? [];
const removedFilter = selectedFilters.filter(filter => filter.key !== option?.key);
setSelectedFilters(removedFilter);
}

setSPFxVersions(spfxVersionsInput);
search(query, componentTypes ?? [], spfxVersionsInput, showOnlyScenarios);
};

const onRemoveFilterBySPFxVersion = (key: string) => {
onFilterBySPFxVersionChange(null, { key: key, text: key, selected: false });
};

const onRemoveFilterByComponentType = (key: string) => {
onFilterByComponentTypeChange(null, { key: key, text: key, selected: false });
};

const onFilterByComponentTypeChange = (event: any, option?: IDropdownOption) => {
let componentTypesInput: string[] = [];
if (option?.selected) {
componentTypesInput = [...componentTypes ?? [], option.key as string];
setSelectedFilters([...selectedFilters, {
key: option.key as string,
text: option.text as string,
kind: 'componentType'
}]);
} else {
componentTypesInput = componentTypes?.filter(componentType => componentType !== option?.key) ?? [];
const removedFilter = selectedFilters.filter(filter => filter.key !== option?.key);
setSelectedFilters(removedFilter);
}

setComponentTypes(componentTypesInput);
search(query, componentTypesInput, spfxVersions ?? [], showOnlyScenarios);
};
Expand All @@ -57,21 +84,38 @@ export const GalleryView: React.FunctionComponent<IGalleryViewProps> = ({ }: Rea
const dropdownOptions: IDropdownOption[] = versions.map(version => ({
key: version,
text: version,
selected: selectedFilters.filter(filter => filter.key === version).length > 0
})).filter((value, index, self) =>
value.key !== null &&
index === self.findIndex((v) => v.key === value.key)
);
return dropdownOptions;
};

useEffect(() => {
if (samples !== undefined) {
setShowOnlyScenarios(showOnlyScenarios);
search(query, componentTypes ?? [], spfxVersions ?? [], showOnlyScenarios);
}
}, [samples]);

const clearFilters = () => {
localStorage.clear();
setSelectedFilters([]);
setSPFxVersions([]);
setComponentTypes([]);
setShowOnlyScenarios(false);
setQuery('');
search('', [], [], false);
};

return (
<div className={'w-full h-full max-w-7xl mx-auto sm:px-6 lg:px-8 py-16'}>
{
samples === undefined && (
<GalleryLoader />
)
}

{
samples !== undefined && (
<div className={'pb-16'}>
Expand All @@ -82,6 +126,12 @@ export const GalleryView: React.FunctionComponent<IGalleryViewProps> = ({ }: Rea
onFilterByComponentTypeChange={(event, option) => onFilterByComponentTypeChange(event, option)}
onFilterOnlyScenariosChange={() => onFilterOnlyScenariosChange()}
initialQuery={query}
selectedFilters={selectedFilters}
onRemoveFilterBySPFxVersion={onRemoveFilterBySPFxVersion}
onRemoveFilterByComponentType={onRemoveFilterByComponentType}
clearAllFilters={clearFilters}
onClearTextboxChange={onClearTextboxChange}
showOnlyScenarios={showOnlyScenarios}
spfxVersions={getSPFxVersions()} />

{
Expand Down
Loading