-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #245 from manifoldco/gui/8688-deprovision-button
Adds a new deprovision button and it's resource-container wrapper
- Loading branch information
Showing
6 changed files
with
437 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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,57 @@ | ||
--- | ||
title: 🔒 Deprovision Button | ||
path: /data/deprovision-button | ||
example: | | ||
<manifold-data-deprovision-button resource-label="my-resource"> | ||
Deprovison resource | ||
</manifold-data-provision-button> | ||
--- | ||
|
||
# 🔒 Deprovision Button | ||
|
||
An unstyled button for deprovisioning resources. 🔒 Requires authentication. | ||
|
||
## CTA text | ||
|
||
Set the CTA text by adding anything between the opening and closing tags: | ||
|
||
```html | ||
<manifold-data-deprovision-button> | ||
Deprovision My Resource | ||
</manifold-data-provision-button> | ||
``` | ||
|
||
`slot` can be attached to any HTML or JSX element. To read more about slots, see [Stencil’s Documentation][stencil-slot] | ||
|
||
## Events | ||
|
||
For validation, error, and success messages, it will emit custom events. | ||
|
||
```js | ||
document.addEventListener('manifold-deprovisionButton-click', ({ detail: { resourceName } }) => | ||
console.info(`⌛ Derovisioning ${resourceName} …`) | ||
); | ||
document.addEventListener( | ||
'manifold-deprovisionButton-success', | ||
({ details: { resourceName } }) =>alert(`${resourceName} deprovisioned successfully!`) | ||
); | ||
document.addEventListener('manifold-deprovisionButton-error', ({ detail }) => console.log(detail)); | ||
// {message: "bad_request: bad_request: No plan_id provided", resourceid: "1234", resourceName: "my-resource"} | ||
``` | ||
|
||
| Name | Returns | Description | | ||
| :--------------------------------- | :--------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------- | | ||
| `manifold-deprovisionButton-click` | `resourceName` | Fires immediately when button is clicked. May be used to trigger a loading state, until `-success` or `-error` is received. | | ||
| `manifold-deprovisionButton-success` | `message`, `resourceId`, `resourceName` | Successful deprovision. Returns a resource ID and resource Label. | | ||
| `manifold-deprovisionButton-error` | `message`, `resourceId`, `resourceName` | Erred provision, along with information on what went wrong. | | ||
|
||
## Styling | ||
|
||
Whereas other components in this system take advantage of [Shadow | ||
DOM][shadow-dom] encapsulation for ease of use, we figured this component | ||
should be customizable. As such, style it however you’d like! We recommend | ||
attaching styles to a parent element using any CSS-in-JS framework of your | ||
choice, or plain ol’ CSS. | ||
|
||
[shadow-dom]: https://developers.google.com/web/fundamentals/web-components/shadowdom | ||
[stencil-slot]: https://stenciljs.com/docs/templating-jsx/ |
This file contains 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
170 changes: 170 additions & 0 deletions
170
src/components/manifold-data-deprovision-button/manifold-data-deprovision-button.spec.ts
This file contains 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,170 @@ | ||
import { newSpecPage } from '@stencil/core/testing'; | ||
import fetchMock from 'fetch-mock'; | ||
|
||
import { Resource } from '../../spec/mock/marketplace'; | ||
import { connections } from '../../utils/connections'; | ||
|
||
import { ManifoldDataDeprovisionButton } from './manifold-data-deprovision-button'; | ||
|
||
describe('<manifold-data-provision-button>', () => { | ||
it('fetches the resource id on load if not set', () => { | ||
const resourceName = 'test-resource'; | ||
|
||
const provisionButton = new ManifoldDataDeprovisionButton(); | ||
provisionButton.fetchResourceId = jest.fn(); | ||
provisionButton.resourceName = resourceName; | ||
provisionButton.componentWillLoad(); | ||
expect(provisionButton.fetchResourceId).toHaveBeenCalledWith(resourceName); | ||
}); | ||
|
||
it('does not fetch the resource id on load if set', () => { | ||
const resourceName = 'test-resource'; | ||
|
||
const provisionButton = new ManifoldDataDeprovisionButton(); | ||
provisionButton.fetchResourceId = jest.fn(); | ||
provisionButton.resourceName = resourceName; | ||
provisionButton.resourceId = resourceName; | ||
provisionButton.componentWillLoad(); | ||
expect(provisionButton.fetchResourceId).not.toHaveBeenCalled(); | ||
}); | ||
|
||
it('fetches resource id on change if not set', () => { | ||
const resourceName = 'new-resource'; | ||
|
||
const provisionButton = new ManifoldDataDeprovisionButton(); | ||
provisionButton.fetchResourceId = jest.fn(); | ||
provisionButton.resourceName = 'old-resource'; | ||
|
||
provisionButton.nameChange(resourceName); | ||
expect(provisionButton.fetchResourceId).toHaveBeenCalledWith(resourceName); | ||
}); | ||
|
||
it('does not resource id on change if set', () => { | ||
const resourceName = 'new-resource'; | ||
|
||
const provisionButton = new ManifoldDataDeprovisionButton(); | ||
provisionButton.fetchResourceId = jest.fn(); | ||
provisionButton.resourceName = 'old-resource'; | ||
provisionButton.resourceId = '1234'; | ||
|
||
provisionButton.nameChange(resourceName); | ||
expect(provisionButton.fetchResourceId).not.toHaveBeenCalled(); | ||
}); | ||
|
||
describe('when created without a resource ID', () => { | ||
afterEach(() => { | ||
fetchMock.restore(); | ||
}); | ||
|
||
it('will fetch the resource id', async () => { | ||
const resourceName = 'new-resource'; | ||
|
||
fetchMock.mock(`${connections.prod.marketplace}/resources/?me&label=${resourceName}`, [ | ||
Resource, | ||
]); | ||
|
||
const page = await newSpecPage({ | ||
components: [ManifoldDataDeprovisionButton], | ||
html: ` | ||
<manifold-data-deprovision-button | ||
resource-name="${resourceName}" | ||
>Deprovision</manifold-data-deprovision-button> | ||
`, | ||
}); | ||
|
||
expect( | ||
fetchMock.called(`${connections.prod.marketplace}/resources/?me&label=${resourceName}`) | ||
).toBe(true); | ||
|
||
const root = page.rootInstance as ManifoldDataDeprovisionButton; | ||
expect(root.resourceId).toEqual(Resource.id); | ||
}); | ||
|
||
it('will do nothing on a fetch error', async () => { | ||
const resourceName = 'new-resource'; | ||
|
||
fetchMock.mock(`${connections.prod.marketplace}/resources/?me&name=${resourceName}`, []); | ||
|
||
const page = await newSpecPage({ | ||
components: [ManifoldDataDeprovisionButton], | ||
html: ` | ||
<manifold-data-deprovision-button | ||
resource-name="${resourceName}" | ||
>Deprovision</manifold-data-deprovision-button> | ||
`, | ||
}); | ||
|
||
expect( | ||
fetchMock.called(`${connections.prod.marketplace}/resources/?me&label=${resourceName}`) | ||
).toBe(true); | ||
|
||
const root = page.rootInstance as ManifoldDataDeprovisionButton; | ||
expect(root.resourceId).not.toEqual(Resource.id); | ||
}); | ||
}); | ||
|
||
describe('When sending a request to deprovision', () => { | ||
afterEach(() => { | ||
fetchMock.restore(); | ||
}); | ||
|
||
beforeEach(() => { | ||
fetchMock.mock(/.*\/resources\/.*/, [Resource]); | ||
}); | ||
|
||
it('will trigger a dom event on successful deprovision', async () => { | ||
fetchMock.mock(`${connections.prod.gateway}/id/resource/${Resource.id}`, 200); | ||
|
||
const page = await newSpecPage({ | ||
components: [ManifoldDataDeprovisionButton], | ||
html: ` | ||
<manifold-data-deprovision-button | ||
resource-name="test" | ||
>Deprovision</manifold-data-deprovision-button> | ||
`, | ||
}); | ||
|
||
const instance = page.rootInstance as ManifoldDataDeprovisionButton; | ||
instance.successEvent.emit = jest.fn(); | ||
|
||
await instance.deprovision(); | ||
|
||
expect(fetchMock.called(`${connections.prod.gateway}/id/resource/${Resource.id}`)).toBe(true); | ||
expect(instance.successEvent.emit).toHaveBeenCalledWith({ | ||
message: 'test successfully deprovisioned', | ||
resourceName: 'test', | ||
resourceId: Resource.id, | ||
}); | ||
}); | ||
|
||
it('will trigger a dom event on failed deprovision', async () => { | ||
fetchMock.mock(`${connections.prod.gateway}/id/resource/${Resource.id}`, { | ||
status: 500, | ||
body: { | ||
message: 'ohnoes', | ||
}, | ||
}); | ||
|
||
const page = await newSpecPage({ | ||
components: [ManifoldDataDeprovisionButton], | ||
html: ` | ||
<manifold-data-deprovision-button | ||
resource-name="test" | ||
>Provision</manifold-data-deprovision-button> | ||
`, | ||
}); | ||
|
||
const instance = page.rootInstance as ManifoldDataDeprovisionButton; | ||
instance.errorEvent.emit = jest.fn(); | ||
|
||
await instance.deprovision(); | ||
|
||
expect(fetchMock.called(`${connections.prod.gateway}/id/resource/${Resource.id}`)).toBe(true); | ||
expect(instance.errorEvent.emit).toHaveBeenCalledWith({ | ||
message: 'ohnoes', | ||
resourceName: 'test', | ||
resourceId: Resource.id, | ||
}); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.