Giter Site home page Giter Site logo

contentful / ui-extensions-sdk Goto Github PK

View Code? Open in Web Editor NEW
123.0 74.0 31.0 9.19 MB

A JavaScript library to develop custom apps for Contentful

Home Page: https://www.contentful.com/developers/docs/extensibility/app-framework/

License: MIT License

TypeScript 97.24% JavaScript 2.72% Shell 0.04%

ui-extensions-sdk's Introduction

App SDK

The App SDK (formerly known as UI Extensions SDK) is a JavaScript library that allows developers to create custom Contentful Apps for the Contentful Web App. Every Contentful App has to include the library in its source.

Resources

Getting help

Technical questions, feedback or feature request can be provided directly through the Github issues for this repository. However, if you are a paying customer or at any point business sensitive information needs to be discussed, then the conversation should be handled via our support system.

Development

Publishing

A new package version is automatically published to npm using semantic-release.

To manually publish the package, run npm run publish-all.

This repository is published as two packages with identical data. We recommend using @contentful/app-sdk.

  • @contentful/app-sdk
  • contentful-ui-extensions-sdk

Canary releases

This package has two main development streams: latest and canary.

The default and stable releases are always published under the latest tag (as per npm convention). The release under the canary tag is to be considered unstable and potentially breaking. You should not rely on it in production.

To start a new alpha version of the package follow these steps:

  1. Checkout the canary branch.
  2. Reset canary to the latest main: git reset --hard origin/main
  3. Create a new branch with your changes from canary
  4. Create a PR that merges into canary.

File Structure

docs

Former home of the documentation and reference for this library. This is now deprecated and you should use links above.

lib

Includes the files constituting the SDK and the associated types.

Top level files are split by feature. Most of them map 1-to-1 to an API (keep reading for the outliers). When APIs are considered too small to be in a separate file, they are part of the api file.

  • channel and signal abstract the communication between an App and the host;
  • locations exports available location where you can run App;
  • initialize creates an initializer to start an App within Contentful's App Framework.

All the typings are in the types folder and they map 1-to-1 APIs, when they make sense. The entities file maps Contentful entities in TypeScript. utils includes utility types, meant to save on characters to type.

scripts

Includes utility tools for maintainers.

test

Includes unit tests (run by mocha)

ui-extensions-sdk's People

Contributors

andipaetzold avatar colomolo avatar contentful-automation[bot] avatar damienxy avatar danwede avatar david-shibley-contentful avatar davidfateh avatar dependabot-preview[bot] avatar dependabot[bot] avatar floelhoeffel avatar floppix avatar ghepting avatar giotiskl avatar jelz avatar jwhiles avatar kdamball avatar loweisz avatar lynnagara avatar madtrick avatar marynag avatar mdmjg avatar mgoudy91 avatar neonichu avatar ronaldronson avatar semantic-release-bot avatar shikaan avatar strazzulla avatar suevalov avatar vikaskumr avatar zeusdeux avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ui-extensions-sdk's Issues

`extension.space.createEntry` documentation seems to differ from actual behavior.

Hey Contentful Team, 👋

The documentation states, that extension.space.createEntry(data) should be of the following form (as I understand it):

const data = {
  sys: {
    contentType: <contentTypeId>,
  },
  fields: {
    name: { [locale]: <nameContent> },
    more: [ [locale]: <moreContent> },
  },
}

extension.space.createEntry(data).then(...).catch(...);

when I run the command I get the error message "Missing object", similar to issue #97 on contentful-mangement.js.

But passing the content type as the first argument seems to work like it should (and as it is on the management library):

const data = {
  fields: {
    name: { [locale]: <nameContent> },
    more: [ [locale]: <moreContent> },
  },
}

extension.space.createEntry(<contentTypeId>, data).then(...).catch(...);

I am using version 3 of the library from unpkg link.

Now I just wanted to clarify:

  • Was it a misunderstanding on my side?
  • Are the docs outdated/referencing a different version than I am using?
  • Anything I otherwise have to consider?

User id in extension.user object

We have a use case where we need to know if the current user is the original creator of the entry. Would it be possible to have the id of the user included in the user object?

Feature Req: Ability to make use of native Asset picker / Link selector in UI Extensions

Hi Contentful,

Thank you for the awesome SDK. This is exactly what I've been looking for.

I was wondering if there's an exposed API to invoke the Image/Asset Picker and Link/Reference picker in the form editor? I know that you can use space.getPublishedAssets and space.getPublishedEntries but it would be much nicer to be able to use Contentful's native pickers.

Long text isn't searchable through dialogs when the content is an url

I'm using dialogs.selectSingleEntry() to search for an entry. One of the content types used is basically a link, with a title and a long text field (which should be searchable) used as an url, with url validation, However, when typing parts of the url in the search field, no results pop up. Long text fields from other entries containing plain text are searched correctly.
Even when typing the full URL, the search isn't working correctly, it behaves as if the search field is empty, showing all the entries with the specified content types.

(update docs) Finding related (linked) entries

Hi,

I noticed your docs don't explicitly mention it, but I spent quite some time trying to reverse look up entries which were pointed to the entry that contained the UI extension.

Eg if my UI extension is on an asset with assets pointed TO it (not from)- then I wanted to list them.

I discovered this functionality already exists, but isn't mentioned anywhere. And it's so easy.

Just thought it worth a mention for other users.

Code below will find any items that "Link to" your asset.

window.contentfulExtension.init(function(extension) {
            const currentItemId = extension.entry.getSys().id
            extension.space.getEntries({
                'links_to_entry': currentItemId
            })
            .then((entries) => {
              console.log('linked to:', entries)
            });
        })

Set entry fields to hide/show

Is it possible to hide/show other fields that belong to the content type using ui extensions ? Also, is conditional field rendering on the road map to ever become a built in feature?

How to fill Array fields using JS SDK?

Context

I need to update some Symbol's Array fields, such fields have been declared from a migration in this way:

  asin
    .createField("naratorsAsins")
    .name("Narrators ASIN's")
    .type("Symbol")
    .type("Array")
    .items({
      type: "Symbol"
    });

What I'm doing

While my UI extension is running, I have some values like ['John Legend', 'Roberto Carlos', 'Kanye West'] and I'm trying to update these kind of fields this way fields[fieldName].setValue(value); where fields is a parameter of sdk's entry instance.

What's happening

Execution fails somehow. I see no error catched (code is inside a try-catch block).

Feature req: Method to redirect to another entry

We have a use case where we'd like to either open a new window or redirect the parent window to another entry in the space. New window works in Chrome with either window.open or a "_blank" target but does not work in ie11 due to the sandboxed iFrame.

The dash symbol in the widget id

There seems to be a bug with widgets that have a dash in their id.

I created a custom widget with the id design-preview and used it in a newly created content type. When I tried to save the content type, it gave me an error. Looking at the network panel of Chrome's dev tools revealed, that the server responded with an error: Incorrect widget. Id doesn't match the regex [A-Za-z0-9]. When I changed the id of the widget to design, I was finally able to save the content type.

Since some of the examples in this repo have a dash in their id, I suggest this symbol should be allowed in the widget id.

Trouble opening pop-up from within editor iframe

Hi!

I am trying to open a Filepicker in a pop-up from within a custom widget. It works locally, but does not work when editing the Entry on contentful.com.

I have a sample repo here wardpenney/contentful-issue-widget-with-pop-up with instructions on how to view it working locally, and not work in prod.

Thanks for all your help!

This is carried over from support ticket at https://support.contentful.com/hc/en-us/requests/7185?flash_digest=f9adcbaeba6855987cc70c14e325063d55300b9f

Improvement: Environment information should be more clear in the SDK

I needed to know what environment my ui extension was executing in. Couldn't find anything in the official docs. Eventually I found that environment information was located in sdk.contentType.sys.environment.sys.id.

A more natural location for this info would be sdk.space or maybe sdk.environment.

Refresh other fields after setValue()

I am working on a widget that takes an Instagram URL and calls the Instagram API on it to get things like author, image url and caption.
I am using that loaded data to populate other fields in the entry with that data. This is working correctly. However, the new text isn't visible until the entry is reloaded. Is there a way to force the other input fields to update with this data without a reload?

Custom WYSIWYG editor not rendering

I've created a custom WYSIWYG editor with Froala-React and everything is working fine when I run it through localhost. However, when I set it up as an extension in Contentful, the extension appears to be rendering (as seen in the dev tools), but nothing is actually showing up on the screen. Two errors I'm getting are:

Uncaught DOMException: Failed to set the 'cookie' property on 'Document': The document is sandboxed and lacks the 'allow-same-origin' flag. at http://localhost:8080/bundle.js:11237:138801 at new Ee.FE.MODULES.data (http://localhost:8080/bundle.js:11237:138898) at s.load (http://localhost:8080/bundle.js:11237:4692) at s.<anonymous> (http://localhost:8080/bundle.js:11237:2021) at HTMLDivElement.proxy (http://localhost:8080/bundle.js:10635:14) at HTMLDivElement.dispatch (http://localhost:8080/bundle.js:5755:92) at HTMLDivElement.elemData.handle (http://localhost:8080/bundle.js:5560:104) at Object.trigger (http://localhost:8080/bundle.js:8714:13) at HTMLDivElement.<anonymous> (http://localhost:8080/bundle.js:8786:18) at Function.each (http://localhost:8080/bundle.js:1155:19)

bundle.js:15292 TypeError: Cannot read property 'off' of undefined at t.value (bundle.js:11476) at t.value (bundle.js:11451) at Wg (bundle.js:15306) at Xg (bundle.js:15364) at Xh (bundle.js:15648) at Rh (bundle.js:15588) at Uh (bundle.js:15572) at Sh (bundle.js:15567) at wh (bundle.js:15548) at kg (bundle.js:15504)

...but I'm not sure if that's my main problem.

This is all that's rendering now:
screen shot 2018-06-14 at 3 51 17 pm

Any ideas?

Add publishing schedule to entry

Hi!

It would be tremendously useful to be able to access the publishing schedule of an entry. Read-only is fine. I guess this could be included in the result from entry.getSys() perhaps?

Or is this already available somewhere?

Add "Open Bulk Editor" to the Navigator

Hi! Are there any plans to extend the Navigator to allow us to open the new Bulk Editor that's currently available for multi-reference fields?

I think this would be very useful because my team likes this editor and our models depend on lots of multi-reference fields. Adding this to the UI extension SDK would make our extensions even better.

Thank you!

https://www.contentful.com/developers/docs/extensibility/ui-extensions/sdk-reference/#navigator

https://www.contentful.com/blog/2017/02/13/product-improvements-shipped-in-nov-dec-jan/

Inconsistent validation between API and UI

When uploading a widget through the API, IDs with a "-" are accepted. However once the widget gets assigned to a ContentType, saving in UI fails with a validation error not allowing a "-" in the filename.

API response when saving CT:

{
"sys": {
"type": "Error",
"id": "ValidationFailed"
},
"message": "Validation error",
"details": {
"errors": [
{
"name": "regexp",
"details": "Does not match /^[a-zA-Z][a-zA-Z0-9_]$/",
"path": [
"controls",
2,
"widgetId"
],
"value": "foo-widget",
"pattern": "^[a-zA-Z][a-zA-Z0-9
]_$"
}
]
},
"requestId": "content-api:6GCmiNIqDCuUqkC2w8oy4K"
}

Forbidden `setValue` update to sibling entry field

Hi!

We are working on a custom widget that will be used to update the value of a sibling field on the entry. When we call the SDK's entry.fields[OUR_FIELD] we receive the following error:

{
  code: "ENTRY UPDATE FAILED",
  message: "Could not update entry field",
  data: {shareJSCodeL "forbidden"}
}

The widget-sdk API docs for .field mention field.setValue(value, locale?): Promise<void> as an endpoint.

Is there something we are missing?

I see in the docs for the "using multiple fields" suggested method suggests using the CMA. It would be nice to not have to use the CMA API when we are so close with the widget-sdk API.

Thanks for your help.

Feature req: allow confirm modals

This would entail updating the iframe sandbox attribute to include allow-modals. We have a button in the sidebar that triggers a webhook. We'd like our editors to confirm before triggering. We can add confirm buttons underneath of course, but for various reasons, an actual confirm box would be preferrable.

Unable to create/update my extension

I'm having the same issue as mentioned here: #130

When executing contentful-extension create --space-id <space-id>

I get the following error:

Failed to create the extension: TypeError: Cannot read property 'id' of undefined

I get the same error when trying to update an extension. Is there another release happening that's causing this error?

Extension parameters are undefined

Expected behavior

extension.parameters should be defined and hold the instance and installation parameters.

Actual behavior

extension.parameters is undefined.

Steps to reproduce

Install and use the Image Data URI UI extension. The config values are currently hardcoded, so you'll need to uncomment these lines. Let me know if I should provide more instructions are a boiled down test case.

setInvalid not a function

Hi all,

It looks like setInvalid on widget.field is not available. I receive api.field.setInvalid is not a function (api is the valid sdk Object).

Is it not yet implemented? If that is the case, mabybe let's remove it out of the docs until we have it. There seem to be other fields within the field scope that may also be candidates.

Thanks!

Visual: cf-is-loading on disabled button

Certain actions require to show a loading indicator while not letting the button be clicked again.

<button class="cf-btn-secondary cf-is-loading" disabled="">Loading</button>

Having such a button, loses the disabled styles (opacity 0.4) when that should win in priority over the loading wheel addition.

This is explicitly put in https://github.com/contentful/ui-extensions-sdk/blob/master/lib/style/buttons.styl#L99 but the user case should be valid to have it half opacity.

Need to make lots of API calls when looking at Reference

Hi team.

I am having to make additional API calls to get information linked by Reference, resulting in a large amount of API calls through the SDK.

Pain Point

The SDK does not have the ability to request joined entity data for a Reference. For example, I have an Asset field (multiple).We have an additional AssetWrapper entity type that links to a single Asset (and contains more info than Asset, such as License). We also have a Reference from AssetWrapper to Owner (a list of possible owners if the asset).

In order to display a thumbnail and this extra information in our Custom UI extension, I need to make an additional API call each time a reference is made:

  1. space.getEntry for Asset to get information about it (thumbnail, title, etc.)
  2. Query space.getEntries for the AssetWrapper
  3. Query space.getEntry again, but this time a Reference to Owner (entity Owner of the image)

Possible Solutions

  • It would be great if I could somehow request that joined Reference information is also brought down in an original call.
  • A queueing function within the SDK that would allow me to push API requests that queue up, and have callbacks. That way the SDK could manage it so the Extension does not violate the rate limit.

Thanks!

Navigator callback event

What's the best way for a custom extension app to get notified when a navigator slide-in dialog closes? The docs state that navigator.openEntry (for example) returns a promise that resolves when the dialog opens, but I'm looking for something that tells me when the dialog closes so that my code knows the entry in question may have changed and an update may be needed.

Help with `sdk.window.startAutoResizer() `

I created a UI extension where you can click a dropdown and add entries.

I noticed that sdk.window.startAutoResizer() doesn’t always work properly:

A lot of times, when adding a new entry, the iframe’s height doesn’t change, which hides some of the content.
When opening the dropdown, I have change the body’s minHeight manually to adapt to the height of the dropdown.
Do you have any tips to handle these issues? Would really appreciate some help here.

Unable to use make commands

Hello guys!

I was trying today to install ui-extension alloyeditor and had problems: editor could not be rendered when I was going to localhost:3000, however it's not the main problem, perhaps you could lead me to the what is wrong here.

And main problem: I saw you added changes related to renaming widgets to extension and now I am not able to run make commands.

Steps I did:

I cloned the repo https://github.com/contentful/extensions, navigated to folder samples/alloy-editor (https://github.com/contentful/extensions/tree/master/samples/alloy-editor) and did steps from README. The problem appears when I invoke make commands:

make create
contentful-extension create --space-id xxx
Failed to create the extension: TypeError: Cannot read property 'id' of undefined
make: *** [create] Error 1

p.s: links to ui-extensions are messed up on this page - https://www.contentful.com/developers/docs/concepts/uiextensions/

Add openEntryList to Navigator

Would be nice to add several new methods to navigator like:

  • opening entries list in the current space
  • opening assets list in the current space
  • opening content type list
  • opening content type configuration

Unable to set Object field to Object or JSON string

Hi!

I am trying to set an Object field type via the field.setValue() method in the SDK. I can not seem to give it a value that passes, always returning in a generic error: code: "ENTRY UPDATE FAILED", message: "Could not update entry field".

These both fail:

api.field.setValue({});
const obj = {};
const objString = JSON.stringify(obj);
api.field.setValue(objString);

Am I missing something? I see the two examples, but both of those take the value coming out of CodeMirror plugin. Is there something that CodeMirror is doing that is required?

Thanks

edits:

  • Added call to field on API calls
  • This is a dumbed-down example, my real life situation has more data in the object. But I wanted to make the example clear with empty JS objects.

space.updateEntry 500 (Internal Server Error)

I'm using the Contentful Extensions SDK / CLI to build a sidebar save button similar to the idea which is listing in this community issue, in fact you can see my comments here:

https://www.contentfulcommunity.com/t/lack-of-save-buttton-on-entry-edit-page/576/3

The idea is that the custom "save button" exists on a ProductPage content type that contains many linked content modules. The user would:

  1. change linked content but not publish
  2. when finished changing content hit the save button associated with the ProductPage
  3. save button triggers a update event for the ProductPage (this is where I'm stuck)
  4. webhook filtering for "save" events triggers AWS Lambda
  5. Lambda finds all pages associated with the change linked modules and renders them using the Preview API

Currently I have code something like this:

const SaveButton = (props) => {
  const {extension} = props;

  const onClick = async () => {
    const sys = extension.entry.getSys();
    const entry = await extension.space.getEntry(sys.id);

    try {
      const data = await extension.space.updateEntry({sys});
    } catch (err) {
      console.log(`***ERR`, err); // {code: "ServerError", message: "Request failed", data: undefined} 500 (internal server error)
    }
  };

  return (
    <Button onClick={onClick}>
      Custom Save Button
    </Button>
  );
};

I'm not sure if I'm using the correct methods but from getSys I get the id of the parent content entry that contains the linked modules, i.e. the id in the URL of the browser matches that returned by getSys.

I then get the entry for that id getEntry(sys.id).

Next I try to update the entry assuming this will trigger the save event for the webhook and also change the "status" to "Published (pending changes)" with the little blue ball showing in the UI. But when I call space.updateEntry({sys}) I get the 500 error with little information about what went wrong. From the docs on updateEntry I thought I was passing everything correctly but maybe I'm missing something 🤷‍♂️

https://github.com/contentful/contentful-management.js/tree/legacy#spaceupdateentrydata---contenttypepromise

Widget to affect the visibility of other fields

I am experimenting with a widget to change the visibility of certain fields based on the value of another field.
I was originally planning on using the onValueChanged mechanism to observe the controlling field and then inject css to hide or show the correct form fields. However, this is not possible as a result of the widget iframe being sandboxed without the allow-same-origin flag.
Do you have any recommendations on how to approach this problem. One thought would be to add a widget to every field that should show or hide and have that widget listen to the correct field. However, that would mean reimplementing the logic and display of many types of form objects.

UI-Extension not working in standalone javascript file!!!

I been following the UI Extension tutorial in Contentful and ran into an issue using npm start. When I start the server nothing displays to the browser. Even trying to log to the console in the javascript file nothing shows, but it tends to work when I place the code in the Index.html script tags.

Can someone explain what I am doing wrong?

Extensions have no access to their own extension ID

If a field extension, I am trying to open this very extension via dialogs.openExtension. The extension itself detects by its parameters whether it is executed in a dialog.
dialogs.openExtension requires the id of the extension to open being specified. However, when installed via Github, extensions are given a random id and the id from extension.json is ignored, rendering the extension incapable of knowing it's own ID.

As one potential approach to a solution, BaseExtensionSDK could be augmented with an id: string property, conveying the current extension's ID. This way it would be available to all extensions in the init methods.

Import when bundling with Webpack/Babel

Since api/index.js is exporting var init, I had to use import * as contentfulExtension from 'contentful-ui-extensions-sdk' rather than import contentfulExtension from 'contentful-ui-extensions-sdk'. The latter returned undefined.

Max Extension size

Hi team!

We are on a spike to port our existing Extension to use React. I'll list reasons for that below, but we are hitting a validation when updating the widget with the CLI: a max file-size of 204,800B. Our current compressed bundle is 207KB and we are working to keep it low, but we will likely add more.

I imagine there are performance considerations if multiple widgets exist on the page, but that might be solved with caching:

If we could upload more than one file (such as the html app and a bundle.js) for the UI Extension, we could link to it in the HEAD of the page and fingerprint the bundle.js locally so it caches in browsers. Or Contentful could apply a hashed fingerprint?

That would help with debugging, because in Chrome Dev Tools, it's currently illegible to debug a large script injected into the srcdoc of the iframe.

Thanks for your help.

Reasons for using a frameworks (in this case, React):

  • Team knows React and can easily work with it
  • Conventions for code organization, event dispatching / handling, templating, and component organization
  • Easier to test

Edit: Added reasons for using a framework

Feature: scroll parent page

In certain cases, it is useful to be able to scroll the parent page to a specific place.
Example usability case: having <a href="#point">modify them below</a> and <div id="point"></div> somewhere down below in a rather large custom field.

Technically, it would be scrolling <div ui-on-scroll="scroll-editor" ui-set-scroll="initialEditorScroll" class="workbench-main__content">

Do you think this is worth PRing ?

SDK hook for when page is done being constructed

Occasionally I am getting a 429 Rate Limit Exceeded Error using the SDK's API.

Primary Cause

Web hooks watching the onValueChanged event of other fields are firing many times.

For array-based fields (like Asset field with Multiple, or Reference field with Multiple) it triggers each time an item is added to it during the page's construction.

For single-value fields (like Reference with Single) it ends up firing one extra time at least, when the item's value is populated into it.

Solution Suggestions

  • Some sort of a hook from the SDK where I could bind those events, after the page is done being constructed.
  • Prevent SDK from dispatching the onValueChanged events until the page is done being constructed.
  • In the UI Extension, bind the events after a delay (current solution).

Does anyone have any other solution ideas?

Thanks all.

Question about support for Reference field types

Hi team!

We are looking to make a Reference custom widget, but I see it is not supported. Is it on a roadmap for support? If it isn't, we would love it!

Here is what I am trying to do:

  • Editor wants to select Destinations that are filtered from a City dropdown

My plan was to make Destinations have a reference to City, that way a custom widget could have a City dropdown, that would filter the options in a Destination dropdown (or list) to select from.

Thanks again for all your help!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.